什么是在ActionScript 3.0来测试组合键盘上的箭头方向的最有效方法是什么?是在、组合、箭头、最有效

2023-09-08 15:32:49 作者:没心没肺总好过撕心裂肺

我需要监视方向的用户使用ActionScript 3.0中的键盘上的四个方向箭头键表示,我想知道的最有效的方式来做到这一点。

I need to monitor the direction a user is indicating using the four directional arrow keys on a keyboard in ActionScript 3.0 and I want to know the most efficient and effective way to do this.

我已经有了如何做到这一点的几个想法,我不知道这将是最好的。我发现,跟踪Keyboard.KEY_DOWN事件时,该事件只要键被按下,所以事件的功能重复和重复。这打破了我原本选择了使用方法,我已经能够想到的方法都需要大量的比较操作符。

I've got several ideas of how to do it, and I'm not sure which would be best. I've found that when tracking Keyboard.KEY_DOWN events, the event repeats as long as the key is down, so the event function is repeated as well. This broke the method I had originally chosen to use, and the methods I've been able to think of require a lot of comparison operators.

我已经能够想到的是使用位运算符在UINT变量的最好方法。下面是我在想什么

The best way I've been able to think of would be to use bitwise operators on a uint variable. Here's what I'm thinking

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

这就是电流的方向变化。在Keyboard.KEY_DOWN事件处理程序我要检查它的关键是什么了下来,并用一个位与操作,看看它是否已经触发的,如果不是的话,我会使用基本另外添加。因此,行动将在0x1和下跌将是0X2和向上和向下将是0x3中,例如。它看起来是这样的:

That's the current direction variable. In the Keyboard.KEY_DOWN event handler I'll have it check what key is down, and use a bitwise AND operation to see if it's already toggled on, and if it's not, I'll add it in using basic addition. So, up would be 0x1 and down would be 0x2 and both up and down would be 0x3, for example. It would look something like this:

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不需要的,如果操作因为它只触发,而不是重复一次,当钥匙上升。我马上就可以使用标有数字从0到15的十六个可能的组合switch语句测试电流方向。这应该工作,但它似乎不是非常优雅的我,给所有的if语句中的重复keyDown事件处理程序,以及庞大的开关。

The keyUpHandler wouldn't need the if operation since it only triggers once when the key goes up, instead of repeating. I'll be able to test the current direction by using a switch statement labeled with numbers from 0 to 15 for the sixteen possible combinations. That should work, but it doesn't seem terribly elegant to me, given all of the if statements in the repeating keyDown event handler, and the huge switch.

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...
    }
}

有没有更好的方式来做到这一点?

Is there a better way to do this?

推荐答案

您可以跟踪是否每个键关机或未通过侦听所有KEY_DOWN和KEY_UP事件,并存储每个键的状态在数组中。我前段时间写了一个类来做到这一点(包括我的回答结束时)。

You can keep track of whether each key is down or not by listening for all KEY_DOWN and KEY_UP events, and storing each key state in an array. I wrote a class a while ago to do just that (included at the end of my answer).

这样,你就不再依赖于事件模型知道某个键关机或未;你可以定期检查每帧(或每一个计时器间隔)。所以,你可以有这样一个功能:

Then you are no longer tied to the event model to know if a certain key is down or not; you can periodically check every frame (or every timer interval). So you could have a function like:

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;
}

这将考虑到方向键presses所有可能的组合。如果你想在网上位移是恒定的(例如,将在同一时间向右和向下的时候,对象使X的像素对角,在水平和垂直方向上反对于X像素)时,code就变成了:

which would take into account all possible combinations of arrow key presses. If you want the net displacement to be constant (e.g. when going right and down at same time, the object moves X pixels diagonally, as opposed to X pixels in both horizontal and vertical directions), the code becomes:

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;
}

下面是输入类我写的(不要忘了从文档类调用初始化)。需要注意的是它也跟踪鼠标的东西;您可以删除,如果你不需要它:

Here is the Input class I wrote (don't forget to call init from the document class). Note that it also keeps track of mouse stuff; you can delete that if you don't need it:

/*******************************************************************************
* 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;
        }
    }
}