HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Processing keyboard input for player movement in a game

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
keyboardplayerinputmovementgameforprocessing

Problem

The following code is part of a game I am making using the Phaser framework; the game is in the style of a top-down RPG, with the player moving their character in four possible directions using the arrow keys. This code appears in my update() method.

I like the user experience provided by this code a lot: the character moves on the screen exactly how I intend. However, I can't help but notice that there's a lot of repetition here and I'd like to explore ways of writing this more efficiently and avoiding repetition. I have already investigated case statements vs if/else statements and have found that a lot of repetition still occurs. I tend to encounter these same repetition issues whenever I need to process keyboard input, regardless of the programming language.

NB. I've come across this Code Review question which seems to be close to what I am looking for, but haven't been able to successfully apply the concept to my own project (ie. my version of that code isn't 'working', so isn't appropriate for Code Review).

```
if(!this.inputBlocked) {
if(this.cursors.left.isDown) {
this.playerInputDirection = 'W';
this.player.body.velocity.x = -this.PLAYER_SPEED;
}
if(this.cursors.right.isDown) {
this.playerInputDirection = 'E';
this.player.body.velocity.x = this.PLAYER_SPEED;
}
if(this.cursors.up.isDown) {
this.playerInputDirection = 'N';
this.player.body.velocity.y = -this.PLAYER_SPEED;
}
if(this.cursors.down.isDown) {
this.playerInputDirection = 'S';
this.player.body.velocity.y = this.PLAYER_SPEED;
}
}

//control player walking animation
if(this.player.body.velocity.x != 0 || this.player.body.velocity.y != 0) {
// check for direction, play appropriate animation
if (this.playerInputDirection == 'W'){
this.player.play('walkLeft');
}
if (this.playerInputDirec

Solution

Assuming you've used an associative array as discussed, you'll have some sort of walkingData object containing the velocity and animation information for each direction, keyed by the same keys as the Phaser cursors object (left/right/up/down).

In an event-driven system, you would go directly from the key that was pressed to the relevant data, however since you're doing this in Phaser's main loop, you need to list the keys you're checking (which is what your if statements are doing). The dry way of doing this is to loop over walkingData:

for (var direction in walkingData) {
    var directionData = walkingData[direction];
    // update player velocity etc. using direction data
}


The slight wrinkle here is that you also need to update the animations, which happens outside your inputBlocked conditional (and depends on the velocities set).

To get around this, you'll also need to declare an animationDirection variable outside the loop and store which direction to use for animation, then use that data in your second if to set the animations.

The end result will be along the lines of:

var walkingData = {
    left: { /* velocity and animation info */ },
    ...
};

var animationData;
if (!this.inputBlocked) {
    for (var direction in walkingData) {
        if (this.cursors[direction].isDown) {
            var directionData = walkingData[direction];
            /* configure velocities */
            animationData = directionData;
        }
    }
}

//control player walking animation
if (this.player.body.velocity.x || this.player.body.velocity.y) {
    // check for direction, play appropriate animation
    this.player.play(animationData.animation);
} else {
    // stop all animation
    this.player.animations.stop();

    // determine the correct sprite frame,
    // so player stops while facing appropriate direction
    this.player.frame = animationData.stopFrame;
}


(I've removed the != 0 since it is equivalent, assuming velocity.x/velocity.y are defined.)

Code Snippets

for (var direction in walkingData) {
    var directionData = walkingData[direction];
    // update player velocity etc. using direction data
}
var walkingData = {
    left: { /* velocity and animation info */ },
    ...
};

var animationData;
if (!this.inputBlocked) {
    for (var direction in walkingData) {
        if (this.cursors[direction].isDown) {
            var directionData = walkingData[direction];
            /* configure velocities */
            animationData = directionData;
        }
    }
}

//control player walking animation
if (this.player.body.velocity.x || this.player.body.velocity.y) {
    // check for direction, play appropriate animation
    this.player.play(animationData.animation);
} else {
    // stop all animation
    this.player.animations.stop();

    // determine the correct sprite frame,
    // so player stops while facing appropriate direction
    this.player.frame = animationData.stopFrame;
}

Context

StackExchange Code Review Q#124174, answer score: 3

Revisions (0)

No revisions yet.