In this tutorial you will learn how to make a simple fly through camera
Step 1: W S A D
First we will modify the init.lua script file main loop.
Here is how the init.lua script should look now:
scene1 = Engine.LoadScene( "level1.pak" )
while ( Engine.Run() == true ) do
end
|
Hey! Whats that 'scene1' variable there before Engine.LoadScene?
I didn't see it in the first tutorial!
Yeah, we didn't need it in the first tutorial. In addition to loading the
scene, Engine.LoadScene also returns a handle to the loaded scene so
that we can access the objects in the scene with it.
So the first thing we have to do is to gain access to the currently active
camera. Lets write a line that does that for us.
scene1 = Engine.LoadScene( "level1.pak" )
camera1 = Scene.GetActiveCamera( scene1 )
while ( Engine.Run() == true ) do
end
|
We pass the 'scene1' variable we just got from
Engine.LoadScene to Scene.GetActiveCamera to get the active
camera in that particular scene.
So now we have our camera stored in the 'camera1' variable, what
then? Well, now we will check on each frame (inside our while loop) if the
user is pressing a certain button, and if he/she is, we will move the
camera accordingly. Lets check for the W (we go forward with
W) button first.
scene1 = Engine.LoadScene( "level1.pak" )
camera1 = Scene.GetActiveCamera( scene1 )
while ( Engine.Run() == true ) do
if ( Context.GetKeyState(KEY_W) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, -12.0 )
end
end
|
The Context.GetKeyState function returns the current state of the
key passed to it. In this case we pass KEY_W, meaning the W
key, to it. Here is a overview of the possible button states that
Context.GetKeyState returns:
* UP - the button is up
* PRESSED - the button has been pressed on the current frame
* DOWN - the buttons is being pressed but wasn't just pressed on the current frame
* RELEASED - the buttons has been released on the current frame
So why do we have two states for a pressed button, PRESSED and
DOWN? Basically when you press a button, its state changes to
PRESSED for the current frame. After that, if the button is still
pressed, the state changes to DOWN. The PRESSED is useful if
you want to, for example shoot a gun a single time. If you used DOWN
for that, you would be firing a bullet on every frame assuming that the
button is still pressed. The DOWN is useful for continuous movement.
If you would use PRESSED for that, your actor would move just for
the instant the button is pressed and not when its down.
We use Actor.MoveLocal to move our camera. The actor functions can
be performed on any actor. That is cameras, entities,
lights and particles. And what does Local stand for in
Actor.MoveLocal? That means that you are moving the actor according
to its local orientation. For example, if you would use just
Actor.Move, it would move according to the global x/y/z axises
instead of moving according to the models local x/y/z axises. Yes, the
three floating point values we pass to Actor.MoveLocal represent the
amount of movement in 3D space during one second. Since we are moving a
camera, we want to move it locally every time we are moving it front, back,
left or right. That being said, there are many situations where you will
want to move an actor according to the global axises, and you will most
likely know when to do that.
Hey! Why are we moving the camera -12.0 to the Z direction, is that
really moving to the front?
Yes it is. Why is that? Well the camera coordinate system is different from
the coordinate systems of other actors. For a camera, negative Z is front,
positive Y is up and positive X is right. Just remember that and you are
good to go ;). Also remember that this only applies when moving the camera
locally. When you are moving the camera with Actor.Move or any other
globally moving function, it works just like with other actors.
Try out the code so far, if it works right, it should make the camera go
forward when you press W. If it doesn't work, please check the
console or CorEngine.log for errors.
Now, lets add the code for S, A and D.
scene1 = Engine.LoadScene( "level1.pak" )
camera1 = Scene.GetActiveCamera( scene1 )
while ( Engine.Run() == true ) do
if ( Context.GetKeyState(KEY_W) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, -12.0 )
end
if ( Context.GetKeyState(KEY_S) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, 12.0 )
end
if ( Context.GetKeyState(KEY_A) == DOWN ) then
Actor.MoveLocal( camera1, -12.0, 0.0, 0.0 )
end
if ( Context.GetKeyState(KEY_D) == DOWN ) then
Actor.MoveLocal( camera1, 12.0, 0.0, 0.0 )
end
end
|
Again, go ahead and test your code. Be sure to test your code a lot and
often. If it works, you should be able to move the camera forward, back,
left and right. If the code doesn't work, check the console or
CorEngine.log for errors.
Step 2: Rotating the camera with the mouse
Now we are ready to code the rotation for the camera. We are going for a
classic flythrough camera, so you will be able to rotate the camera with
the mouse.
But wait, what is needed for that? First we need to make sure that the
mouse is inside the window all the time so that we don't get weird jumps in
rotation while the mouse enters the window and goes out. We can do this by
passing true to function Context.HideMouse. Also since now we
can't close the window by clicking the X symbol in the top right
corner of the window like you usually do to windows, we need an alternate
way to close the window. Lets do that with the ESC key. You can also
shut down CorEngine with the F10 button on your keyboard, but it is
nice to have some backup for it. Great! Lets add the code for this:
Context.HideMouse( true )
scene1 = Engine.LoadScene( "level1.pak" )
camera1 = Scene.GetActiveCamera( scene1 )
while ( Engine.Run() == true ) do
if ( Context.GetKeyState(KEY_W) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, -12.0 )
end
if ( Context.GetKeyState(KEY_S) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, 12.0 )
end
if ( Context.GetKeyState(KEY_A) == DOWN ) then
Actor.MoveLocal( camera1, -12.0, 0.0, 0.0 )
end
if ( Context.GetKeyState(KEY_D) == DOWN ) then
Actor.MoveLocal( camera1, 12.0, 0.0, 0.0 )
end
if ( Context.GetKeyState(KEY_ESC) == PRESSED ) then
Engine.Quit()
end
end
|
For clarification, the new lines of code are marked in
RED. Now try to run the code
and see if the mouse disappears and if the ESC button works. If not, don't
worry, you can still close the window with F10 or ALT + F4 so
that you can come back to fix your code.
So now we can move to camera rotation. For this, we need to know how much
the mouse has moved during the current and the last frame. You could store
the previous frames mouse position and calculate the differece between it
and the current frames mouse position, but CorEngine already does this. You
can access the difference with Context.GetMouseForce. The rest is
just using the values we get from that:
Context.HideMouse( true )
scene1 = Engine.LoadScene( "level1.pak" )
camera1 = Scene.GetActiveCamera( scene1 )
while ( Engine.Run() == true ) do
if ( Context.GetKeyState(KEY_W) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, -12.0 )
end
if ( Context.GetKeyState(KEY_S) == DOWN ) then
Actor.MoveLocal( camera1, 0.0, 0.0, 12.0 )
end
if ( Context.GetKeyState(KEY_A) == DOWN ) then
Actor.MoveLocal( camera1, -12.0, 0.0, 0.0 )
end
if ( Context.GetKeyState(KEY_D) == DOWN ) then
Actor.MoveLocal( camera1, 12.0, 0.0, 0.0 )
end
mf = Context.GetMouseForce()
Actor.Rotate( camera1, 0.0, 0.0, -mf.x * 10.0 )
Actor.RotateLocal( camera1, -mf.y * 10.0, 0.0, 0.0 )
if ( Context.GetKeyState(KEY_ESC) == PRESSED ) then
Engine.Quit()
end
end
|
Because the mouse and 3d space coordinate systems are different, we use
the negatives of the force as you can see. Also you can notice that we used
just Actor.Rotate for the Z rotation instead of
Actor.RotateLocal. That is because unless you are writing a
flight simulator, you don't want the camera to turn around Z according to
its own orientation. That would make the user "stand tilted". You can try
Actor.RotateLocal on the Z rotation if you want to see the
effect. Also keep in mind that the rotations we input are in degrees, not
radians. Pretty much all rotation related functions in CorEngine use degrees.
Thats it! I hope you enjoyed the tutorial, and if you have any comments
about it, please post to the
forums.
|