Как наиболее эффективно проверить комбинированное направление стрелки на клавиатуре в ActionScript 3.0? - PullRequest
0 голосов
/ 23 марта 2010

Мне нужно отслеживать направление, которое указывает пользователь, используя четыре клавиши со стрелками на клавиатуре в ActionScript 3.0, и я хочу знать наиболее эффективный и действенный способ сделать это.

У меня есть несколько идей, как это сделать, и я не уверен, что будет лучше. Я обнаружил, что при отслеживании событий Keyboard.KEY_DOWN событие повторяется до тех пор, пока клавиша нажата, поэтому функция события также повторяется. Это сломало метод, который я первоначально выбрал для использования, и методы, о которых я мог думать, требуют большого количества операторов сравнения.

Лучший способ, который я смог придумать, - это использовать побитовые операторы для переменной uint. Вот что я думаю

var _direction:uint = 0x0; // The Current Direction

Это текущая переменная направления. В обработчике событий Keyboard.KEY_DOWN я проверю, какая клавиша нажата, и использую побитовую операцию И, чтобы увидеть, включена ли она, и если нет, я добавлю ее с помощью базового добавления. Таким образом, up будет 0x1, а down будет 0x2, а up и down будут, например, 0x3. Это будет выглядеть примерно так:

private function keyDownHandler(e:KeyboardEvent):void
{
    switch(e.keyCode)
    {
        case Keyboard.UP:
            if(!(_direction & 0x1)) _direction += 0x1;
            break;
        case Keyboard.DOWN:
            if(!(_direction & 0x2)) _direction += 0x2;
            break;
        // And So On...
    }
}

Для keyUpHandler не понадобится операция if, поскольку она запускается только один раз, когда клавиша поднимается, вместо повторения. Я смогу проверить текущее направление, используя инструкцию switch, помеченную цифрами от 0 до 15 для шестнадцати возможных комбинаций. Это должно сработать, но это не кажется мне очень элегантным, учитывая все операторы if в повторяющемся обработчике события keyDown и огромный переключатель.

private function checkDirection():void
{
    switch(_direction)
    {
        case 0:
            // Center
            break;
        case 1:
            // Up
            break;
        case 2:
            // Down
            break;
        case 3:
            // Up and Down
            break;
        case 4:
            // Left
            break;
        // And So On...
    }
}

Есть ли лучший способ сделать это?

1 Ответ

1 голос
/ 23 марта 2010

Вы можете отслеживать, не работает ли каждый ключ, прослушивая все события KEY_DOWN и KEY_UP и сохраняя каждое состояние ключа в массиве. Я написал класс недавно, чтобы сделать это (включен в конце моего ответа).

Тогда вы больше не привязаны к модели событий, чтобы знать, нажата ли определенная клавиша или нет; Вы можете периодически проверять каждый кадр (или каждый интервал таймера). Таким образом, вы можете иметь такую ​​функцию:

function enterFrameCallback(e:Event):void
{
    var speed:Number = 1.0;     // net pixels per frame movement

    thing.x += (
        -(int)Input.isKeyDown(Keyboard.LEFT)
        +(int)Input.isKeyDown(Keyboard.RIGHT)
    ) * speed;
    thing.y += (
        -(int)Input.isKeyDown(Keyboard.UP)
        +(int)Input.isKeyDown(Keyboard.DOWN)
    ) * speed;
}

, которая учитывает все возможные комбинации нажатий клавиш со стрелками. Если вы хотите, чтобы чистое смещение было постоянным (например, при движении вправо и вниз одновременно, объект перемещается по диагонали на X пикселей, а не на X пикселей в горизонтальном и вертикальном направлениях), код становится:

function enterFrameCallback(e:Event):void
{
    var speed:Number = 1.0;     // net pixels per frame movement
    var displacement:Point = new Point();

    displacement.x = (
        -(int)Input.isKeyDown(Keyboard.LEFT)
        +(int)Input.isKeyDown(Keyboard.RIGHT)
    );
    displacement.y = (
        -(int)Input.isKeyDown(Keyboard.UP)
        +(int)Input.isKeyDown(Keyboard.DOWN)
    );

    displacement.normalize(speed);

    thing.x += displacement.x;
    thing.y += displacement.y;
}

Вот класс ввода, который я написал (не забудьте вызвать init из класса документа). Обратите внимание, что он также отслеживает работу мыши; Вы можете удалить это, если вам это не нужно:

/*******************************************************************************
* DESCRIPTION: Defines a simple input class that allows the programmer to
*              determine at any instant whether a specific key is down or not,
*              or if the mouse button is down or not (and where the cursor
*              is respective to a certain DisplayObject).
* USAGE: Call init once before using any other methods, and pass a reference to
*        the stage. Use the public methods commented below to query input states.
*******************************************************************************/


package
{
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.display.Stage;
    import flash.geom.Point;
    import flash.display.DisplayObject;


    public class Input
    {
        private static var keyState:Array = new Array();
        private static var _mouseDown:Boolean = false;
        private static var mouseLoc:Point = new Point();
        private static var mouseDownLoc:Point = new Point();


        // Call before any other functions in this class:
        public static function init(stage:Stage):void
        {
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown, false, 10);
            stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp, false, 10);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 10);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp, false, 10);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove, false, 10);
        }

        // Call to query whether a certain keyboard key is down.
        //     For a non-printable key: Input.isKeyDown(Keyboard.KEY)
        //     For a letter (case insensitive): Input.isKeyDown('A')
        public static function isKeyDown(key:*):Boolean
        {
            if (typeof key == "string") {
                key = key.toUpperCase().charCodeAt(0);
            }
            return keyState[key];
        }

        // Property that is true if the mouse is down, false otherwise:
        public static function get mouseDown():Boolean
        {
            return _mouseDown;
        }

        // Gets the current coordinates of the mouse with respect to a certain DisplayObject.
        // Leaving out the DisplayObject paramter will return the mouse location with respect
        // to the stage (global coordinates):
        public static function getMouseLoc(respectiveTo:DisplayObject = null):Point
        {
            if (respectiveTo == null) {
                return mouseLoc.clone();
            }
            return respectiveTo.globalToLocal(mouseLoc);
        }

        // Gets the coordinates where the mouse was when it was last down or up, with respect
        // to a certain DisplayObject. Leaving out the DisplayObject paramter will return the
        // location with respect to the stage (global coordinates):
        public static function getMouseDownLoc(respectiveTo:DisplayObject = null):Point
        {
            if (respectiveTo == null) {
                return mouseDownLoc.clone();
            }
            return respectiveTo.globalToLocal(mouseDownLoc);
        }

        // Resets the state of the keyboard and mouse:
        public static function reset():void
        {
            for (var i:String in keyState) {
                keyState[i] = false;
            }
            _mouseDown = false;
            mouseLoc = new Point();
            mouseDownLoc = new Point();
        }


        /////  PRIVATE METHODS BEWLOW  /////

        private static function onMouseDown(e:MouseEvent):void
        {
            _mouseDown = true;
            mouseDownLoc = new Point(e.stageX, e.stageY);
        }

        private static function onMouseUp(e:MouseEvent):void
        {
            _mouseDown = false;
            mouseDownLoc = new Point(e.stageX, e.stageY);
        }

        private static function onMouseMove(e:MouseEvent):void
        {
            mouseLoc = new Point(e.stageX, e.stageY);
        }

        private static function onKeyDown(e:KeyboardEvent):void
        {
            keyState[e.keyCode] = true;
        }

        private static function onKeyUp(e:KeyboardEvent):void
        {
            keyState[e.keyCode] = false;
        }
    }
}
...