The Script and Camera

For the code shy of you out there, please feel free to move to the next section “Attach the Camera”. But before you go you may want to change the speed of the characters walking or running!

1) Walk and Run Speed

To match your characters walk and run animations to the speed it moves in the game world you only need to adjust a couple of text values and then press save. At the top of the script look for the “walkSpeed”,” runSpeed” and ” turnSpeed” values. These large values are required as these speed variables get used in code that maintains a stable speed regardless of frame rate. Notice the big difference between the walk value and the run value.

walkSpeed  = 1000;
runSpeed   = 2000;
turnSpeed  = 150;

2) Optional Move to Camera

For the rest of this page we are going to take an overview of the code to see how it is working. It is not a script tutorial more a quick look at the main functions and what they are doing. The top of the script has some variables we need to control the speed of walking and turning. In a full game object we would make these values into a dynamic property so they can be easily adjusted by any user without the need to change any code. Please have a look at the scripting section for more information on setting up dynamic properties.


3) PostInit()

This function is your friend for when you want to initialise some values. After the play button has been pressed and all of the entities have their engine parameters initialized, all of the entities script onInit() functions get called, following this the postInit() functions are then called, so by now we are generally safe to start grabbing data.

function postInit()
	idleanim 	= anim.getFromMap(obj, "Idle1");
	walkanim 	= anim.getFromMap(obj, "Walk");
	runanim 	= anim.getFromMap(obj, "Run");
	jumpanim 	= anim.getFromMap(obj, "Jump");
 
	anim.playAnimation(obj, idleanim, 0, 0);
end

In our postInit() function we grab the names of the models animations which were set up in the animation mapping step of this tutorial idleanim = anim.getFromMap(obj, “Idle1”); These names are stored in a variable, so we don’t need to worry if the model is replaced with another one and the animation names have changed. These variables pulled from the animation map will save us having to worry about them, leaving us to just use them.

We also start playing the character “Idle” animation so our character looks active when pressing play, there is no blend enabled as we want it to start in Idle not blend from a T pose to animate.

anim.playAnimation(obj, idleanim, 0, 0);

4) Key Events

The Key Events are called anytime a key is pressed (KeyDown) or released (KeyUp). All Skylines Lua scripts respond to these events if the functions are added to the script. In this example we need both key down and key up events to detect the player’s keystrokes. When a required key is pressed we set a flag to tell our script what should be done, eg by setting “forwardKeyDown = true” to move our character forwards. To switch between walking and running we use an extra flag “shiftKeyDown” to show that we have pressed the “Shift” key, then in the checkForKeys() function we can choose whether to walk or run based on the value of this flag.

function onKeyDown(key)
	if(key == "w")then forwardKeyDown = true; end
	if(key == "s")then backKeyDown = true; end
	if(key == "a")then leftKeyDown = true; end
	if(key == "d")then rightKeyDown = true; end
 
	if(key == "space")then spaceKeyDown = true; end
	if(key == "shift")then shiftKeyDown = true; end
end
 
function onKeyUp( key )
	if(key == "w")then forwardKeyDown = false; end
	if(key == "s")then backKeyDown = false; end
	if(key == "a")then leftKeyDown = false; end
	if(key == "d")then rightKeyDown = false; end
 
	if(key == "space")then spaceKeyDown = false; end
	if(key == "shift")then shiftKeyDown = false; end
end


5) checkForKeys()

This function is called from the onUpdate() loop and checks flags related to each key direction, if it finds a match then it calls the appropriate movement function, either walk() or run() which performs the actual directional movement commands and the turn() function which surprisingly does the turning of our character.

function checkForKeys(timeDelta)
	if(forwardKeyDown == true and shiftKeyDown == false)then
		walk(1);
	elseif(forwardKeyDown == true and shiftKeyDown == true)then
		run(1);
	elseif(backKeyDown == true and shiftKeyDown == false)then
		walk(-1);
	elseif(backKeyDown == true and shiftKeyDown == true)then
		run(-1);
	else
		idle();
	end
 
	if(spaceKeyDown == true)then
		startJump();
	end
 
	if(leftKeyDown == true)then	turn(-1, timeDelta); end
	if(rightKeyDown == true)then turn(1, timeDelta); end
end

6) Idle, Walk or Run!

These small functions are responsible for the directional movement. A character as with all objects has a direction, the direction it faces. By using the character.move() command, we move the character forwards or backwards and this is done by a multiplier called “direction”.

If “direction = 1” then move one direction as we are using positive speed values, if “direction =-1” then move the other direction due to the negative speed. If the characters entity is rotated the character controller will move in that direction.

function idle()
	character.move(obj, 0 );
	anim.playAnimation(obj, idleanim,30, 1);
end

In the idle function, we set the character controllers movement to zero. We need to stop movement and play the “Idle” animation.

function walk(direction)
	character.move(obj, walkSpeed*direction*timeDelta );
	anim.setSpeed(obj, walkanim, direction);
	anim.playAnimation(obj, walkanim, 30, 1);
end

To get our character to move in a specified direction, we send a little math into the speed argument of the character.move(objID, Speed ) command. The “walkSpeed” variable that is defined at the top of the script is our move speed.

This multiplied by the “direction” creates either a positive or negative value (forward or backwards), then we multiply this against the update loops “timeDelta”.

Note: TimeDelta is a value to represent the difference in time from the last frame.
Multiplying by this “timeDelta”, we can keep movement the same regarding if the games frame rate is 100fps or 20fps. The distance our character will travel will be the same.

function run(direction)
	character.move(obj, runSpeed*direction*timeDelta ); 
	anim.setSpeed(obj, runanim, direction);
	anim.playAnimation(obj, runanim, 100, 1);
end

A cool trick we can do with the animation is to reverse the playback if our character is moving backwards, this saves us having to use extra animations. This is done by passing the direction variable, which is 1 or -1 into the “speedMultiplier” argument of the anim.setSpeed(objID, animationName, speedMultiplier) function.

7) A Turning Effect

Our character would be no good for a 3D world if it cannot turn. To change the direction of our character we need to rotate the characters entity. This is done by the command entity.turn(objID, Pitch, Yaw, Roll) where pitch , yaw, and roll are the angle of rotation in degrees to apply to the object.

function turn( direction )
	if(direction == -1)then
		entity.turn(obj, 0, turnSpeed*timeDelta, 0)
	elseif(direction == 1)then
		entity.turn(obj, 0, -turnSpeed*timeDelta, 0)	
	end
end

Turning our entity also uses the “timeDelta” to ensure the same rate of rotation persists regardless of frame rates.