A Flash Developer Resource Site

Results 1 to 2 of 2

Thread: [RESOLVED] Key.isDown equivient in AS3?

  1. #1
    Junior Member
    Join Date
    Aug 2007
    Posts
    23

    resolved [RESOLVED] Key.isDown equivient in AS3?

    I used the Search function to try and solve this problem, then posted in Mr Malee's old thread. But people seem to be ignoring the new activity in that old one, so I'm starting my own thread after all.

    Basically, I just want to run some code while a specific key is held down.

    The problem is, they removed the isDown method "for security reasons," and failed to provide a replacement method, despite the fact that every realtime Flash game in the known universe relies upon it. Thanks, Adobe.

    Anyway, Fall_X's solution was to implement his own keydown class, as follows:

    Code:
    package {
    	import flash.display.Sprite;
    	import flash.display.Stage;
    	import flash.events.KeyboardEvent;
    	class MyKey
    	{
    		private static var downArray:Array=[];
    		private static var pressedArray:Array=[];
    		private static var stg:Stage;
    
    		public static function set stage(value:Stage) {
    			if(stg) {
    				stg.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
    				stg.removeEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
    			}
    			stg=value;
    			stg.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler,false,0,true);
    			stg.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler,false,0,true);
    		}
    
    		public static function isDown(keyCode:int):Boolean {
    			// can't just return downArray[int] because it can be undefined or null,
    			// and we want to return a boolean
    			if(downArray[keyCode]) {
    				return true;
    			}
    			return false;
    		}
    		public static function isPressed(keyCode:int):Boolean {
    			// this one will only return true once per key
    			// which is handy in some cases, when you don't want to repeat an action
    			// if the key stays pressed
    			if(pressedArray[keyCode]) {
    				delete pressedArray[keyCode];
    				return true;
    			}
    			return false;
    		}
    		private static function keyDownHandler(event:KeyboardEvent):void {
    			downArray[event.keyCode as int]=true;
    			pressedArray[event.keyCode as int]=true;
    		}
    		private static function keyUpHandler(event:KeyboardEvent):void {
    			delete downArray[event.keyCode];
    			delete pressedArray[event.keyCode];
    		}
    	}
    }
    Fall_X's later comments suggest that he has tested and updated his class to make it work, and he offers the following presumably as part of a test-case:

    I updated the code above to something that actually works, lol. You'll have to set the static variable "stage" to the current stage in order to make it work - ie :

    Code:
    MyKey.stage=this.stage; // needed only once
    if(MyKey.isDown(38)) {
    	trace("up");
    }
    Unfortunately, I can't figure out how to even create an instance of this new class. Every time I try, I get various flavors of runtime errors. Also, he's inexplicably named his new class MyKey, when typically flash developers use my* to designate an instance name. Then he (apparently) used the word MyKey as an instance name in his main code.

    Someone please show me hot to set up an instance of Fall_X's myKey object. If his class is wrong, make it right. If the class is right, show me how to use it properly. I'm not an OOP whiz yet, as I'm still learning to use AS3 as a functional language. Implementing it in the timeline of a FLA would be preferable, since that's my comfort zone, but I'll settle for a generic game class intended to become a Document Class, if that's the only way you know how to help me.

    But please, I need to see a working example before I'll ever understand how to use this thing. Every attempt I've made (both as a Document Class and as functional code in my document's timeline) has resulted in one or more runtime errors.

    I've tried everything. I've tried importing the class AS file, I've tried including the class AS file, I've tried using the name MyKey as the instance name, and I've tried making up my own unique instance name. It all fails. I clearly don't know what I'm doing. Need help. Please send brains.

  2. #2
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Okay, I finally figured it out. But MAN, the solution was a surprise to me. Apparently I don't need an include statement OR an import statement. I just needed a Key.AS file to be in the same directory as whatever file references it. I was not aware that AS files got automatically included like that. It's WEIRD!

    I used senocular's custom key class for this:

    Code:
    // Key.as
    package {
        
        import flash.display.Stage;
        import flash.events.Event;
        import flash.events.KeyboardEvent;
        
        /**
         * The Key class recreates functionality of
         * Key.isDown of ActionScript 1 and 2. Before using
         * Key.isDown, you first need to initialize the
         * Key class with a reference to the stage using
         * its Key.initialize() method. For key
         * codes use the flash.ui.Keyboard class.
         *
         * Usage:
         * Key.initialize(stage);
         * if (Key.isDown(Keyboard.LEFT)) {
         *    // Left key is being pressed
         * }
         */
        public class Key {
            
            private static var initialized:Boolean = false;  // marks whether or not the class has been initialized
            private static var keysDown:Object = new Object();  // stores key codes of all keys pressed
            
            /**
             * Initializes the key class creating assigning event
             * handlers to capture necessary key events from the stage
             */
            public static function initialize(stage:Stage) {
                if (!initialized) {
                    // assign listeners for key presses and deactivation of the player
                    stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
                    stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
                    stage.addEventListener(Event.DEACTIVATE, clearKeys);
                    
                    // mark initialization as true so redundant
                    // calls do not reassign the event handlers
                    initialized = true;
                }
            }
            
            /**
             * Returns true or false if the key represented by the
             * keyCode passed is being pressed
             */
            public static function isDown(keyCode:uint):Boolean {
                if (!initialized) {
                    // throw an error if isDown is used
                    // prior to Key class initialization
                    throw new Error("Key class has yet been initialized.");
                }
                return Boolean(keyCode in keysDown);
            }
            
            /**
             * Event handler for capturing keys being pressed
             */
            private static function keyPressed(event:KeyboardEvent):void {
                // create a property in keysDown with the name of the keyCode
                keysDown[event.keyCode] = true;
            }
            
            /**
             * Event handler for capturing keys being released
             */
            private static function keyReleased(event:KeyboardEvent):void {
                if (event.keyCode in keysDown) {
                    // delete the property in keysDown if it exists
                    delete keysDown[event.keyCode];
                }
            }
            
            /**
             * Event handler for Flash Player deactivation
             */
            private static function clearKeys(event:Event):void {
                // clear all keys in keysDown since the player cannot
                // detect keys being pressed or released when not focused
                keysDown = new Object();
            }
        }
    }
    And here is a FULL WORKING EXAMPLE. It includes an initialization of the custom key class, and a timer-driven main loop that checks to see if a key is pressed. Just enter the above code into a AS file called Key.AS, and enter the code below into the main timeline of your FLA, and save both the FLA and the AS file to the same folder, then run the FLA with F5.

    Note: The timer is set up to fire 50 times per second, so you may want to set your FLA's FPS to 50 before you run this code. I think it will still work at a lower frame rate, but I haven't experimented with it yet!

    Code:
    // Initialize main game timer
    var gameTimer:Timer = new Timer(20);//20 ms = 1/50 second!
    gameTimer.addEventListener(TimerEvent.TIMER, gameMainLoop);
    gameTimer.start();
    
    //Main game loop
    function gameMainLoop(event:TimerEvent):void {
    	var timer:Number = event.target.currentCount;//Saves us from having to type this every time we want to know the current time.
    	Key.initialize(stage);
    	if (Key.isDown(Keyboard.LEFT)) {
    		// Left key is being pressed
    		trace("LEFT");
    	}
    	//trace("tick");
    }
    I'll enter this solution into my whiney post in the other thread, too. I suspect people were either as stumped as I am on this one, or didn't understand what information I was missing. This way both threads, if accessed using the forum Search, will contain the full working example I was after.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center