51. HaxeFlixel RPG tutorial: Part 14

2014-10-22

HaxeFlixel RPG tutorial leveling

Today we'll improve our existing combat system, by adding experience rewards, leveling up, leveled player damage, random enemy damage, and the ability to level up.

Currently, all of our player stat data, such as health and experience, is stored and displayed using the HUD.hx class.

We will add new methods to the class, which will let us manipulate the player's experience and automatically level the player up.

It's also required to add a conditional statement, which responds to the player's health becoming 0 or negative.

Go to the HUD.hx class now and add an addExp() function, which increments a value to the experience bar and handles leveling up:

public function addExp(num:Int):Void {

	exp += num;

	while (exp > maxExp) {

		level++;

		exp -= maxExp;

		maxExp = Math.ceil(maxExp * 1.3);

		hp++;

		maxHp++;

	}

}

You can see that by gaining a level the player's max experience value is multiplied by 1.3, and their health and maximum health is increased by 1.

Add an additional if statement to addHealth(), which switches the state to MenuState whenever the health drops to 0 or below.

public function addHealth(num:Int):Void {

	hp += num;

	if (hp > maxHp) {

		hp = maxHp;

	}

	if (hp <= 0) {

		FlxG.switchState(new MenuState());

	}

}

Add a method to read the level value:

public function getLevel():Int {

	return level;

}

Overall, the HUD.hx class now looks like this:

package ;

import flixel.FlxG;

import flixel.group.FlxSpriteGroup;

import flixel.text.FlxText;

import flixel.ui.FlxBar;



/**

 * RPG HUD.

 * @author Kirill Poletaev

 */

class HUD extends FlxSpriteGroup

{

	private var healthDisplay:FlxText;

	private var levelDisplay:FlxText;

	private var expBar:FlxBar;

	

	private var hp:Int;

	private var maxHp:Int;

	private var exp:Int;

	private var maxExp:Int;

	private var level:Int;

	

	public function new() 

	{

		super();

		scrollFactor.x = 0;

		scrollFactor.y = 0;

		

		healthDisplay = new FlxText(2, 2);

		hp = 5;

		maxHp = 10;

		add(healthDisplay);

		

		levelDisplay = new FlxText(2, 12);

		level = 1;

		add(levelDisplay);

		

		maxExp = 10;

		exp = 0;

		expBar = new FlxBar(4, 25, FlxBar.FILL_LEFT_TO_RIGHT, 100, 4);

		expBar.createFilledBar(0xFF63460C, 0xFFE6AA2F);

		add(expBar);

	}

	

	override public function update() {

		healthDisplay.text = "Health: " + hp + "/" + maxHp;

		levelDisplay.text = "Level: " + level;

		expBar.currentValue = exp;

		expBar.setRange(0, maxExp);

	}

	

	public function addHealth(num:Int):Void {

		hp += num;

		if (hp > maxHp) {

			hp = maxHp;

		}

		if (hp <= 0) {

			FlxG.switchState(new MenuState());

		}

	}

	

	public function addExp(num:Int):Void {

		exp += num;

		while (exp > maxExp) {

			level++;

			exp -= maxExp;

			maxExp = Math.ceil(maxExp * 1.3);

			hp++;

			maxHp++;

		}

	}

	

	public function getLevel():Int {

		return level;

	}

	

}

Now go to CombatWindow.hx and update the onAttack() method to use the available HUD methods for proper damage and health calculations:

private function onAttack() {

	var dmg:Int = playState.hud.getLevel();

	enemy.health -= dmg;

	txt.text = "You hit the enemy, dealing " + dmg + " damage.";

	if (enemy.health > 0) {

		var enemyDmg:Int = Math.floor(Math.random()*2);

		txt.text += "\nThe enemy strikes, dealing " + enemyDmg + " damage.";

		playState.hud.addHealth( -enemyDmg);

	} else {

		playState.winCombat(enemy);

		playState.hud.addExp(6);

	}

}

You can see that I made the player's damage fully depend on the player's current level. The damage dealt by enemy is randomized, in this case between the values 0 and 1. Six experience points are added to the player whenever they win a battle.

Back in PlayState.hx, it is necessary to make the HUD instance public and accessible inside of the CombatWindow object:

public var hud:HUD;

Done, now you should be able to gain experience by killing enemies and eventually level up. If you lose a battle, you're sent back to the menu state.

We'll add tween animations to our combat window next time!