0

我需要监视用户使用 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 操作,因为它只在键上升时触发一次,而不是重复。对于 16 种可能的组合,我将能够通过使用从 0 到 15 的数字标记的 switch 语句来测试当前方向。这应该可行,但考虑到重复 keyDown 事件处理程序中的所有 if 语句以及巨大的开关,这对我来说似乎不是非常优雅。

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

有一个更好的方法吗?

4

1 回答 1

1

您可以通过侦听所有 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;
}

这是我编写的 Input 类(不要忘记从文档类中调用 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;
        }
    }
}
于 2010-03-23T18:01:00.743 回答