Wednesday, July 22, 2015

Adding Opponents in my Phaser Game

Up until now, my Phaser-based 404-page frog soccer game hasn't been much of a challenge. You just move the frog around the bump the ball. In a real game of frog soccer, there would be at least one opponent trying to take the ball away from you. Today I tried to add such an opponent.

Adding another frog was the easy part. In my create function, I just create a new sprite (named otherFrog) using the same sprite image as the first frog. With the exception of the starting position, all of its settings are the same as the first frog.

var frog, otherFrog;

// ... other variables ...

function create() {

    // ... other sprite creation ...
  
    otherFrog = group.create(600, 200, 'frog');
    game.physics.enable(otherFrog, Phaser.Physics.ARCADE);
    otherFrog.body.drag.set(300);
    otherFrog.body.setSize(60, 25, 0, 42);
    otherFrog.body.allowGravity = false;
    otherFrog.body.collideWorldBounds = true;
    otherFrog.body.maxVelocity.set(200);
    otherFrog.chase = true;

    // ... other stuff (see previous posts)

}

The only difference is that I set a boolean value called chase to true. This will be one of the flags I use to control the new frog's behavior. When chase is true, it means the frog should be chasing the ball and trying to line herself up for a shot. Yes, I've decided that the frogs in this soccer game are female. Women's soccer is very popular at the moment in this country, and the frog soccer was my daughters' idea.

In the update function, I made a few changes. First, this one to the collision check:

game.physics.arcade.collide(group, group, function(o1, o2) {
    if ((o1 === otherFrog && o2 === ball) || 
        (o2 === otherFrog && o1 === ball))
    {
        otherFrog.chase = false;
        otherFrog.kick = false;
        setTimeout(function() {
            otherFrog.chase = true;
        }, 250);
    }
});

I specify a function as the third parameter to game.physics.arcade.collide that gets called when any two sprites collide. In it, I check to see if those two sprites happen to be the ball and the opponent frog. If she did touch the ball, I turn off her chase and kick modes, wait 250 milliseconds, and then put her back into chase mode.

Also in the update function, I added this code to control her behavior:

if (otherFrog.chase) {

    var targetX, targetY;

    if (otherFrog.position.x > ball.position.x - 100) {
        targetX = ball.position.x - 100;
        targetY = otherFrog.position.y;
    } else if (otherFrog.position.y > ball.position.y ||
               otherFrog.position.y < ball.position.y - 25)
    {
        targetX = ball.position.x - 100;
        targetY = ball.position.y - 25;
    } else {
        otherFrog.chase = false;
        otherFrog.kick = true;
    }

    game.physics.arcade.moveToXY(otherFrog, targetX, targetY, 100);    

} else if (otherFrog.kick) {

    game.physics.arcade.moveToObject(otherFrog, ball, 150);

}

If she's in chase mode, I check to see if she's on the left side of the ball. If not, I set her target location to be her current y-coordinate and the ball's x-coordinate minus 100. This will move her to a good position on the left side. If she's already there, I check to see if she's lined up with the ball on the y-axis. If she's not within a 25-pixel zone near the ball, I set her target position to be the ball's x-coordinate minus 100 and the ball's y-coordinate minus 25. When she gets there, she'll be lined up perfectly for a kick. Which is why I turn off chase mode and turn on kick mode if neither of the first two conditions are true. After I determine the new target, I use the game.physics.arcade.moveToXY function to make the frog move towards that position. Since this function gets called pretty much constantly, she'll continuously be re-targeted towards wherever the ball might move to.

If she's in kick move, I simple use the game.physics.arcade.moveToObject function to make the frog move directly to the ball's position. This will result in her colliding with the ball, which will kick the ball, turn off chase and kick modes, and set the timer for a return to chase mode.

Here is a short video I made of the game in action now. It's not perfect yet, but you can see how the other frog tries pretty hard to get in my way and take the ball.


Obviously, I still have a way to go here. Those frogs still need some animation of their own, and I need to add goals and make the ground tiles actually look like a soccer field. I only have a few minutes each day to work on it, so whatever little progress I make is good. Remember that the full source code is on GitHub if you want to play around with it yourself!

Don't forget to read today's comic...and if you have a minute do me a favor and vote for Amphibian.com on the Top Webcomics site. Here's the link: Amphibian.com Voting Gateway.

Amphibian.com comic for 22 July 2015