Other than the story itself, battle is the most important part of The Botanist. Now that I’ve got basic maps and movement working, I decided to spend some time on developing the core of the battle system. A game can be fun to play test with just maps and battling, so building this system has a nice side effect of making the rest of the development process even more fun!

I want The Botanist’s battle system to be rich and challenging (unlike many mobile games that don’t actually give you control over the battle), but I’m still constrained by my requirement to make this game work smoothly on both PC and mobile.

A good paradigm for the type of battle control that should work for us is Diablo II’s system. In Diablo II the keyboard enhances the control experience but isn’t required. Click to move, click to interact, click to attack. Right click to cast a spell. This works for me! The keyboard is used mostly for shortcuts to things you can click on-screen, like bringing up the map overlay, getting into your inventory, using potions, and switching spells.

The next step, of course, is figuring out the player attributes that determine its performance in battle. I nearly made a mistake here and went too deep too early. I started down the path of trying to define, at the beginning, the entirety of the player stats and attributes system and modeling out the whole thing in a spreadsheet. I got discouraged, and then I realized: I have a year to build this game!

So I’m starting with the basics: strength, agility, intelligence, and stamina as primary attributes (those you add points to when you level up), and health, attack, defense, dodge, critical, and MP as secondary attributes (determined by the primary attributes but enhanced by items).

Rather than meticulously modeling out the player stats in a spreadsheet, I’ll just play this game for the next few months and make sure it feels balanced and fun. I can always add or remove or change attributes later, so let’s approach this iteratively and not over-think things.

On the tech side, we set up a click handler on the enemy class. The handler is simple, responsible only for calling the melee method against the enemy.

this.inputEnabled = true;
this.input.useHandCursor = true;
this.events.onInputUp.add(
	function() {
		var callback = function() {
			// Context of player.
			enemy.melee(self); // enemy === player
		};
		// Context of player.
		this.setTarget(self, callback, true);
	},
	enemy // We're in the context of the enemy, so `enemy` here is actually the player.
);

The melee method itself does some checks to make sure we’re allowed to attack, launches a melee animation, sets an “attacking” flag, and sets two timers to unset the attacking flag (using the weapon’s attack speed) and then actually perform the attack. The attack itself is performed in a timer so that the damage and death animation feels natural and aligns with the animation itself.

There’s also some logic to handle critical hits, dodged attacks, and the calculation of the attack damage.

Character.prototype.melee = function(target) {
	if (!this.alive) { return; }
	if (this.attacking === true) { return; }

	var self = this;
	var angle = Phaser.Point.angle(this, target);

	if (angle <= 1*Math.PI/4 && angle > -1*Math.PI/4) {
		this.animations.play('attackleft', 15, false);
	} else if (angle <= 3*Math.PI/4 && angle > 1*Math.PI/4) {
		this.animations.play('attackup', 15, false);
	} else if (angle >= 3*Math.PI/4 || angle < -3*Math.PI/4) {
		this.animations.play('attackright', 15, false);
	} else {
		this.animations.play('attackdown', 15, false);
	}

	this.attacking = true;
	this.game.time.events.add(Phaser.Timer.SECOND * this.attackSpeed, function() { self.attacking = false; });

	// Dodge has to happen before damage but after attacking variable.
	if (target.doesDodge()) { return; }

	this.game.time.events.add(Phaser.Timer.HALF, function() {
		if (!target.alive) { return; }

		var damage = self.calculateMeleeDamage(target);
		target.damage(damage);
		if (target.health < 0) {
			target.health = 0;
		}
	});
};

The last step was to implement a health bar over each character. I used a plugin I found for this, the https://github.com/codevinsky/phaser-HudManager/ plugin by Jeremy Dowell.

Here’s my weekly progress update, check it out below!