Moving the avatar

There are two ways to tell the avatar to walk. Either input by pressing the arrows keys or clicking on the destination point by mouse.

Which method is better? We need to consider both the game play and the network synchronization.

The game play of the virtual world is our first consideration. A virtual world with fighting theme requires players to stick on the keyboard to walk and create key combination attack. On the other hand, our virtual world focuses on social interaction so that mouse input will be the main use.

Movement synchronization

When moving the avatars by keyboard, we may keep sending the "move right" command until the right arrow key is released. In this case, the client broadcasts many same messages to synchronize the movement and will slow down the network.

Note

When we are designing the network game, we need to optimize the amount of commands to send over the network. An average TCP connection can have a lag that ranges between 50 ms to 200 ms. The synchronization will fail if we send commands too often.

Movement synchronization

In the second case, we only broadcast the press and release action; the other clients will automatically do the movement until the external release action is received. The final position is not synchronized perfectly because of the network lag of the release message passing. Other clients will receive the release action slightly slower then the original sender.

Movement synchronization

When the avatar movement is by mouse, we can broadcast the destination points and clients will render the movement. As only one message is needed, the movement in other clients lags for only the message passing time and the final position is synchronized.

Movement synchronization

In the virtual world where the avatars are walking around casually, the slightly asynchronous position is acceptable. However, some fixing has to apply in real-time fighting or other games that require precise positioning.

Making avatar able to walk

We need to extend the avatar class to provide walking features. We made another class called WalkingAvatar that extends the original Avatar class.

public class WalkingAvatar extends Avatar{
...
}

There are some instance variables in the WalkingAvatar class.

Every avatar has a walking speed. The speed is the pixel displacement every time we draw the walking animation.

private var _walkingSpeed:Number = 4;

The isWalking flag indicates whether the avatar is now walking.

private var _isWalking:Boolean = false;

A destination point will be set along with the walking command. A loop will keep track if the avatar reaches the destination point.

private var _destX:Number;
private var _destY:Number;

In isometric coordinate, we may not be able to move the avatar from start point to the destination point in a straight line. We have the limitation of the 4 (or 8) directions movement for which we need to split the path into segments. We need an array to store the segments of the walking path. We will name this array walkPath.

public var walkPath:Array;

The segments are the straight lines of the path. Take the following graph as an example; we need to move three tiles up and two tiles left to the destination. The walkPath array will contain the (0,-3) and (-2,0) coordinates.

Making avatar able to walk

We need to save the current position in the isometric coordinate. It is very useful because we will often calculate isometric coordinate of the avatar, including movement and path finding.

public var isoPosition:Point;

The avatar class will interact with the world once it can move around. Therefore we have a reference of the world.

public var world:World;

The walkByPath function will get one segment from the stored path array and call the avatar to walk to the position according to the path segment.

public function walkByPath():void {
if (walkPath != null && walkPath.length>0){
var nextPathSegment:Object = walkPath.pop();
var nextDeltaX:int = nextPathSegment.x - isoPosition.x;
var nextDeltaY:int = nextPathSegment.y - isoPosition.y;
walkTo(nextDeltaX,nextDeltaY);
}
}

We will also add an entry point to the walkByPath function by creating a startWalkByPath function. This function now only calls the walkByPath function. In later sections, we will add more logic that needs to be executed before starting the walking animation.

public function startWalkByPath():void {
walkByPath();
}

This function calculates the destination position to move. The input is the incremental steps from current position. It will then calculate the destination position in isometric coordinate from the input and convert it to screen position inside the world coordinate. This function also faces the avatar to the destination and sets the walking animation.

public function walkTo(deltaX:int, deltaY:int):void {
/* get the destinetion point from the delta*/
var destIsoX:int = isoPosition.x + deltaX;
var destIsoY:int = isoPosition.y + deltaY;
/* calculate the screen point of the destination from isometric */
var screenPoint:Point = world.map.i2sLocal(destIsoX,destIsoY);
var newDirection:String = getDirectionFromDestination(deltaX, deltaY);
_destX = screenPoint.x;
_destY = screenPoint.y;
this.showDirection(newDirection);
/* we only need to set the animation to walk again when not walking or change direciton */
if (!_isWalking || _currentDirection != newDirection){
this.playAnimation('walk'),
_isWalking = true;
_currentDirection = newDirection;
}
}

The world class checks every avatars' walking state in every frame. When the isWalking flag of the avatar is set to true, the world class will call this walking function to make it walk. This function moves the avatar closer to the destination and stops walking when it reaches there. We play the animation in the walkTo function instead of this function to avoid frequently animation reset and play. The walking animation will be played smoothly without interruption until the avatar stops walking.

public function walking():void {
var remainX:int = _destX - this.x;
var remainY:int = _destY - this.y;
var remainLenth:Number = Math.sqrt(remainX*remainX + remainY*remainY);
if (remainLenth > _walkingSpeed){
this.x += remainX/remainLenth * _walkingSpeed;
this.y += remainY/remainLenth * _walkingSpeed;
}else{
this.x = _destX;
this.y = _destY;
/* Test if this is the end of the path segment or the end of the whole path */
if (walkPath != null && walkPath.length>0){
walkByPath();
}else{
stopWalk();
}
}
/* update the isometric coordinate when walking */
isoPosition = world.map.s2iLocal(this.x,this.y);
}

The stopWalk function simply resets the animation to idle and switches off the isWalking flag.

public function stopWalk():void {
this.playAnimation("idle");
_isWalking = false;
}

We need to face the direction towards the destination position to make the walking realistic. The directions are based on our isometric coordinate that is used in our virtual world.

Making avatar able to walk

We are using a 4-direction isometric map. We can know which direction the avatar is facing by comparing the next tile's coordinates. If the next tile is in positive x-axis and zero y-axis, the avatar is facing southeast; if the x-axis is negative, it is facing northwest; if the next tile is in positive y-axis and zero x-axis, the avatar is facing southwest; and if the y-axis is negative, it is facing northeast.

private function getDirectionFromDestination(deltaX:int,deltaY:int): String
{
if (deltaX > 0 && deltaY == 0){
return "se";
}else if (deltaX < 0 && deltaY == 0){
return "nw";
}else if (deltaX == 0 && deltaY > 0){
return "sw";
}else if (deltaX == 0 && deltaY < 0){
return "ne";
}
return _currentDirection;
}

Walking by keyboard

We have made the avatar class able to walk. Let's try to move the avatars by keyboard input and see them walking around.

We set up two event listeners in World class. The onKeyboardDown and onKeyboardUp listeners capture the event when any keyboard key is pressed or released. For each arrow key, we call the walkTo methods with one tile movement. For example, when the left arrow key is kept pressed, the avatar will keep moving to the left.

private function onKeyboardDown(e:Event):void {
var c:uint = e.target.lastKey;
if (c){
if (c==Keyboard.LEFT){
_myAvatar.walkTo(-1,0);
}else if (c==Keyboard.RIGHT){
_myAvatar.walkTo(1,0);
}else if (c==Keyboard.UP){
/* Please note that Y is positive down */
_myAvatar.walkTo(0,-1);
}else if (c==Keyboard.DOWN){
_myAvatar.walkTo(0,1);
}
}
}

When the key is released, we stop the avatar.

private function onKeyboardUp(e:Event):void {
myAvatar.stopWalk();
}

When we test the virtual world, the walking animation is lagged. It is because the walking animation stopped after one walked tile and reset the animation. Then the other one-tile movement started and resulted in non-smooth walking animation. We can improve the animation by moving the avatar two tiles instead of one.

...
_myAvatar.walkTo(-2,0);
...

The main purpose of this keyboard movement is to test the newly implemented WalkingAvatar class. For our virtual world, it is better to use mouse input for the movement which will be discussed later in this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.90.172