Flixel Adventure Game tutorial – Part 3: Characters

Index
Previous part: Flixel basics

In the previous part we have discussed how the gameloop of Flixel works and how we can manipulate objects either automatically by frame or by keyboard input. In this part we will start by taking a look at Object Oriented Programming (OOP), this means that specific functions of the program are packed individually in different classes so you will be able to re-use them in other projects. By programming in this style, you will save time if you use a lot of the same code. On top of that, it is also very clear what part does what and it will aid in collaborating with other programmers, since you can work on different files simultaneously.

In the ‘com’ folder, create a new class called ‘Character’ and open the file. Import the org.flixel.FlxSprite class and make the Character class extend FlxSprite.

public class Character extends FlxSprite

We will give the constructor a number of arguments, an image to load, the x-value and the y-value.

public function Character(x:uint, y:uint, image:Class)

We will use a 16 by 16 pixels grid to display all the characters and the background tiles, so we will multiply the given location values by 16.

// Setting up the position of the character.
this.x = x * 16;
this.y = y * 16;

Using ‘this’ will refer to the object itself, so it is clear for the compiler not to use the argument variable named ‘x’ but the value of the object itself named ‘x’.

To load the image that will be passed down by the image argument, use the following function in the constructor.

// Loading the image.
loadGraphic(image, true, false, 16, 16);

Now we will add the movement functions to the class, we will make a public function with one argument, the direction, and use it to manipulate the x and y values of the object. Note that we don’t use ‘this’ here, since there is only one variable that can be addressed by the name ‘x’, the same goes for the ‘y’ variable.

public function move(dir:String):void
{
	// A switch statement works like a combination of else-if-statements.
	switch(dir)
	{
		// If the direction is up, move the object 16 pixels up.
		case "UP":
			y -= 16;
			break;
		// If the direction is down, move the object 16 pixels down.
		case "DOWN":
			y += 16;
			break;
		// If the direction is left, move the object 16 pixels left.
		case "LEFT":
			x -= 16;
			break;
		// If the direction is right, move the object 16 pixels right.
		case "RIGHT":
			x += 16;
			break;
		}
	}
}

Let’s go back to our PlayState file, here we want to create a variable that holds an instance of our Character class.

// Test character variable.
private var char:Character;

Next, we want to import an image that will be our character. You can make your own characters if you want, but for now I suggest you will use the example I will give to you here. He will probably look a bit familiar to you if you have played a game from the Kees’ Adventure series. There are a number of sprites on this spritesheet, an idle one and two for walking, for each of the four directions.

Charactersheet for Flixel Adventure Tutorial

Create a ‘data’ folder inside the ‘com’ folder, and save the Char.png file in it. We will have to embed the image into our code, place the following code next to your other variables. We use the *.png format because it supports transparency.

// Embedding the Char.png image and assigning it to a variable.
[Embed(source = "data/Char.png")] private var imgChar:Class;

Now we have our image and our Character class, we can instantiate our ‘char’ variable, and add it to the gameloop.

// Creating the character.
char = new Character(5, 5, imgChar);
add(char);

Our update loop still contains code to move around the text, we should change it to move our character. We have created a function for this in the Character class, so we will only have to call that by name.

override public function update():void
{
	// If down arrow key is pressed.
	if (FlxG.keys.DOWN)
	{
		char.move("DOWN");
	}
	// Else if up arrow key is pressed.
	else if (FlxG.keys.UP)
	{
		char.move("UP");
	}
	// Else if left arrow key is pressed.
	else if (FlxG.keys.LEFT)
	{
		char.move("LEFT");
	}
	// Else if right arrow key is pressed.
	else if (FlxG.keys.RIGHT)
	{
		char.move("RIGHT");
	}
	super.update();
}

If you test the game you will see that the character will move quite fast and that the sprite will keep facing the front. Open the Character class again and add the following code to the constructor.

// Setting up the animations.
addAnimation("DOWN_IDLE", [0]);
addAnimation("UP_IDLE", [3]);
addAnimation("LEFT_IDLE", [6]);
addAnimation("RIGHT_IDLE", [9]);

addAnimation("DOWN_WALK", [1,2], 6);
addAnimation("UP_WALK", [4,5], 6);
addAnimation("LEFT_WALK", [7,8], 6);
addAnimation("RIGHT_WALK", [10,11], 6);

Note that the first element is 0, this is caused by the way arrays are declared in Actionscript 3. Using the ‘Play’ function, you can call a certain animation. Take a look at the ‘move’ function, can you make the character face the right direction for each movement? Below you can see how I did it for the ‘UP’ condition, do the same for the other three directions.

// If the direction is up, move the object 16 pixels up.
case "UP":
	y -= 16;
	play("UP_IDLE");
	break;

We want to use the moving animations, not just the idle ones. In order to do this we will have to change the update function of the Character class, override it and add checks to see if our character is moving and facing which direction.

First we will add three new variables that we will use for this purpose. We will make the ‘moving’ variable public so we can access it from outside the class.

// Flag used to check if char is moving.
public var moving:Boolean = false;
// Var used to hold moving direction.
private var move_dir:String = "DOWN";
// Distance already moved.
private var move_dis:uint = 0;

If we are not moving, we want to look in the direction we were last moving, add the following function to your Character class.

public function look(dir:String):void
{
	move_dir = dir;

	switch(dir)
	{
		case "UP":
			play("UP_IDLE");
			break;
		case "DOWN":
			play("DOWN_IDLE");
			break;
		case "LEFT":
			play("LEFT_IDLE");
			break;
		case "RIGHT":
			play("RIGHT_IDLE");
			break;
	}
}

We want to move the actual moving to our update functions, so we can implant an walk-by-grid system. We will have to change our move function (again).

public function move(dir:String):void
{
	// Check if not already moving.
	if (!moving && move_dis <= 0)
	{
		// Setting variables.
		move_dir = dir;
		moving = true;
		move_dis = 16;
				
		// A switch statement works like a combination of else-if-statements.
		switch(dir)
		{
			case "UP":
				play("UP_WALK");
				break;
			case "DOWN":
				play("DOWN_WALK");
				break;
			case "LEFT":
				play("LEFT_WALK");
				break;	
			case "RIGHT":
				play("RIGHT_WALK");
				break;
		}
	}
}

Of course, we will also have to adjust our update loop of the Character class. If you are having trouble understanding the code, I suggest you read through it a couple of times and play around with it a bit, change some variables and see what happens.

override public function update():void
{
	// If not moving, look at the direction of last movement.
	if (!moving)
	{
		look(move_dir);
	}
	else
	{
		// If the object is still allowed to move.
		if (move_dis > 0)
		{
			move_dis --;
			switch(move_dir)
			{
				case "UP":
					y--;
					break;
				case "DOWN":
					y++;
					break;
				case "LEFT":
					x--;
					break;
				case "RIGHT":
					x++;
					break;
			}
		}
		else // If the object has moved.
		{
			moving = false;
		}
	}
	super.update();
}

If you have done everything correctly, you should now be able to control your character by using the arrow keys. As you can see, it is bound to a grid, this may seem a bit useless now, but once we get into collision detection and interaction with the environment, it will come in handy.



In the next part we will start by creating the world for our little character to live in.

You can download the code for this part here: Flixel Adventure Game Tutorial part 3 code.

Next part: The World

Join the Conversation

3 Comments

  1. Please could you provide me with the finished source code for each file, for this stage?

    I keep getting 11 errors, about moving the moving (e.g. x++) to the update loop, about undefined properties.

    It would really help to compare what I have with what you have.

    Thanks!

    1. Maybe a bit late:

      In the Character class file you have to add the following:

      org.flixel.FlxSprite

      and make the class extend FlxSprite:

      public class Character extends FlxSprite

Leave a comment

Your email address will not be published. Required fields are marked *