Pergunta

I have a keyboard controlled character in a game which has a stationary frame when no
keys are pressed and four different animations for the up, down, left, right directions
(No diagonal movement).

So when left key is pressed, _character moves left across the screen and the left animation is played. When the key is released/Key up the stationary frame plays where the character is still.

This works fine at a slow pace but when multiple keys are being pressed to maneuver around an obstacle etc, the character often sticks to the stationary position and only plays the animations after a delay. The movement of the Movieclip is fine using velocity, but the animations suffer.

Its something to do with the key up handler surely. I’m a beginner so I’m sure I just can’t get my head around some simple logic, but I can’t figure it out! Help me please. No matter how fast I tap the keys I need that animation to play, and only when nothing is being pressed should I see the stationary image.

Character in its own class, with Velocity variables.

package
{
    import flash.display.MovieClip;
    import flash.display.DisplayObject

        [Embed(source="../swfs/characterRes.swf", symbol="Character")]
        public class Character extends MovieClip
        {
            //Public properties
            public var vx:int = 0;
            public var vy:int = 0;

            public function Character()
            {
            }
        }   
}

Keydown and KeyUp listeners added.

_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
            _stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); 

In enterFrame the characters X and Y position is linked to the velocity

private function enterFrameHandler(event:Event):void
        {   
            //Move the game character and check its stage boundaries
            _character.x += _character.vx; 
            _character.y += _character.vy;
        }

The keydown handler uses the arrows and WASD to control the velocity and plays that directions specific frame (with embedded animation)

private function keyDownHandler(event:KeyboardEvent):void
        {
            if (event.keyCode == Keyboard.LEFT || event.keyCode == 65 )
            {
                _character.vx = -4;
                _character.gotoAndStop(4);
            }
            else if (event.keyCode == Keyboard.RIGHT || event.keyCode == 68)
            {
                _character.vx = 4;
                _character.gotoAndStop(5);
            }
            else if (event.keyCode == Keyboard.UP || event.keyCode == 87 )
            {
                _character.vy = -4;
                _character.gotoAndStop(2);
            }
            else if (event.keyCode == Keyboard.DOWN || event.keyCode == 83)
            {
                _character.vy = 4;
                _character.gotoAndStop(3);
            }   
        }

Key up handler stops velocity and plays first frame which is the stationary image.

private function keyUpHandler(event:KeyboardEvent):void
        {
            if (event.keyCode == Keyboard.LEFT || event.keyCode == Keyboard.RIGHT 
                || event.keyCode == 65 || event.keyCode == 68)
            {
                _character.vx = 0;
                _character.gotoAndStop(1);
            } 
            else if (event.keyCode == Keyboard.DOWN || event.keyCode == Keyboard.UP 
                || event.keyCode == 87 || event.keyCode == 83 )
            {
                _character.vy = 0;
                _character.gotoAndStop(1);
            }
        }

I also made the stationary image bright red to make it easier for me to spot and once I start moving the character in different directions I see Red! (literally & figuratively!)

Update

Vesper's answer has solved the animation state problem brilliantly but this new control system seems to want to travel diagonally which sends the character on an unwanted path.

My stage is a grid of 50px squares. Character is 50px and 50px boxess (with collision detection) are around with a 50px border around them so the character can maneuver around the stage.

If I press/hold one direction the character moves no problem (left to right and Up to down is fine too.), but if I go left then down or up then right etc, the character will travel that direction then continue that direction around the boxes. When I tested without the boxes the character continues in that direction diagonally.

So if I want to go clockwise around a box (starting in the bottom left side of it), I'll press up, then right and if I dont press down VERY quickly, the character will travel up and right again, towards the top right of the stage. (Character does stop if key is released.)

So if I press two keys from the opposing updown or leftright variables, it wants to travel diagonally. Any ideas how to solve this?

Final Update

Vesper's answer solved my original animation problem. I'll ask new questions to deal with remaining queries.

Foi útil?

Solução

You actually have four de-facto independent key states, up key pressed/released, down key, left key, right key. Technically one can implement special actions in case of two opposite keys be pressed at one time, in your case it's not needed but it's still worth mentioning. So, you handle all of them separately, and only then choose where should your character face.

    var bDown:Boolean=false;
    var bUp:Boolean=false;
    var bLeft:Boolean=false;
    var bRight:Boolean=false;
    // declare vars to store key states. You can use an array if you want

    private function keyDownHandler(event:KeyboardEvent):void
    {
        if (event.keyCode == Keyboard.LEFT || event.keyCode == 65 )
        {
            bLeft=true;
            // now, instead of directly attaching the movement, just set flag
        }
        else if (event.keyCode == Keyboard.RIGHT || event.keyCode == 68)
        {
            bRight=true;
        }
        else if (event.keyCode == Keyboard.UP || event.keyCode == 87 )
        {
            bUp=true;
        }
        else if (event.keyCode == Keyboard.DOWN || event.keyCode == 83)
        {
            bDown=true;
        }   
    }

Same for key up handler, setting values to false. Now doing the parsing of the actual character's movement according to keys pressed. The best place is the enter frame handler - good thing you have it in place already.

    private function enterFrameHandler(event:Event):void
    {   
        var updown:Boolean=Boolean(!(bUp==bDown)); 
        // if both are true or both are false, this is false. If this is true, 
        // we are moving upwards or downwards
        var leftright:Boolean=Boolean(!(bLeft==bRight));
        // same here
        if (!updown && !leftright) {
            // not moving anywhere
            _character.gotoAndStop(1);
            _character.vy=0;
            _character.vx=0; 
            // other mechanics might be in place in case you decide to implement inertia, for example
        } else {
            if (bUp) {
                _character.vy=-4; // hardcoding this might get you issues later
                // will still do for today's task
                _character.gotoAndStop(2);
            } else if (bDown) {
                _character.vy=4;
                _character.gotoAndStop(3);
            } 
            // one side parsed. Note, with this sequence the leftwards or rightwards
            //animation supersedes up/down. But, we don't have diagonals, so there should be superseded animation
            if (bLeft) {
                _character.vx=-4;
                _character.gotoAndStop(4);
            } else if (bRight) {
                _character.vx=4;
                _character.gotoAndStop(5);
            } 
        }
        // Okay, now velocity and facing is set, proceed with move
        //Move the game character and check its stage boundaries
        _character.x += _character.vx; 
        _character.y += _character.vy;
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top