问题
I am relatively new to Action Script, and I am trying to make a game of Snake. Obviously I need to implement a global key listener, but I am having odd problems. I tried adding the listener to the application tag but it didn't seem to have any effect (the movie was still able to compile). Whenever I call
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, key, true);
my program crashes. Below is the content of my main.mxml file:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="800"
height="600"
frameRate="15"
creationComplete="creationComplete();"
enterFrame="enterFrame(event);"
currentState="MainMenu">
<mx:states>
<mx:State
name="Game"
enterState="enterGame(event)"
exitState="exitGame(event)">
</mx:State>
<mx:State
name="LevelEnd">
<mx:AddChild relativeTo="{myCanvas}" position="lastChild">
<mx:Button x="380" y="344" label="Continue" id="btnContinue" click="btnContinueClicked(event)" width="90" height="30"/>
</mx:AddChild>
<mx:AddChild relativeTo="{myCanvas}" position="lastChild">
<mx:Label x="10" y="10" text="Congratulations, you finished the level."/>
</mx:AddChild>
</mx:State>
<mx:State name="MainMenu">
<mx:AddChild relativeTo="{myCanvas}" position="lastChild">
<mx:Button x="381" y="344" label="Start" id="btnStart" click="startGameClicked(event)" width="90" height="30"/>
</mx:AddChild>
<mx:AddChild relativeTo="{myCanvas}" position="lastChild">
<mx:Image x="10" y="49" source="@Embed('../media/mainmenu.png')"/>
</mx:AddChild>
<mx:AddChild relativeTo="{myCanvas}" position="lastChild">
<mx:Label x="10" y="10" text="Snake Pro" fontSize="20" fontWeight="bold"/>
</mx:AddChild>
</mx:State>
</mx:states>
<mx:Canvas x="0" y="0" width="100%" height="100%" id="myCanvas"/>
<mx:Script>
<![CDATA[
protected var inGame:Boolean = false;
protected var currentLevel:int = 1;
import flash.events.KeyboardEvent;
public function creationComplete():void
{
LevelDefinitions.Instance.startup();
addKeyEvent();
//stage.focus = stage;
}
private function addKeyEvent():void
{
this.stage.addEventListener(KeyboardEvent.KEY_DOWN, key, true);
}
public function enterFrame(event:Event):void
{
if (inGame)
{
GameObjectManager.Instance.enterFrame();
myCanvas.graphics.clear();
myCanvas.graphics.beginBitmapFill(GameObjectManager.Instance.backBuffer, null, false, false);
myCanvas.graphics.drawRect(0, 0, this.width, this.height);
myCanvas.graphics.endFill();
}
}
private function key(event:KeyboardEvent):void {
//t1.text = event.keyCode + "/" + event.charCode;
GameObjectManager.Instance.setDirection(0, 1);
currentState = "MainMenu";
inGame = false;
}
protected function startGameClicked(event:Event):void
{
currentState = "Game"
}
protected function enterGame(event:Event):void
{
Mouse.hide();
GameObjectManager.Instance.startup();
Level.Instance.startup(currentLevel);
inGame = true;
}
protected function exitGame(event:Event):void
{
Mouse.show();
Level.Instance.shutdown();
GameObjectManager.Instance.shutdown();
inGame = false;
}
protected function btnContinueClicked(event:Event):void
{
currentLevel = LevelDefinitions.Instance.getNextLevelID(currentLevel);
if (currentLevel == 0)
{
currentLevel = 1;
currentState = "MainMenu";
}
else
{
currentState = "Game"
}
}
]]>
</mx:Script>
</mx:Application>
Also, it seems I am getting this stack trace:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at main/addKeyEvent()[C:\Users\Me\Desktop\Flash\Snake\src\main.mxml:58]
at main/creationComplete()[C:\Users\Me\Desktop\Flash\Snake\src\main.mxml:52]
at main/___main_Application1_creationComplete()[C:\Users\Me\Desktop\Flash\Snake\src\main.mxml:10]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:12528]
at mx.core::UIComponent/set initialized()[E:\dev\4.x\frameworks\projects\framework\src\mx\core\UIComponent.as:1627]
at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\4.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:759]
at mx.managers::LayoutManager/doPhasedInstantiationCallback()[E:\dev\4.x\frameworks\projects\framework\src\mx\managers\LayoutManager.as:1072]
I am at my wit's end here, and I appreciate your time and efforts. Thanks!
回答1:
You are getting a runtime error because you attach an event listener to the "stage" property, which is null at the time you try it. Instead of doing this on the "creationComplete" event, try to do this on the "applicationComplete" event. The stage object will be available then.
回答2:
Your application is probably not added to the stage yet, which is why there's an exception being thrown in addKeyEvent. That being said, you don't really need to add the event listener to the stage in this case, you can add it to the application instead, like so:
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="800"
height="600"
frameRate="15"
creationComplete="creationComplete();"
enterFrame="enterFrame(event);"
currentState="MainMenu"
keyDown="key(event)">
As is implied, you also need to remove the call to addKeyEvent in your creationComplete handler, otherwise you'll still get the exception.
回答3:
It is not obvious to me that to implement this game you need to implement a global key listener. From a context of a Flex Application, wouldn't it make more sense to add the listener to the application tag, not the stage?
What is your full stack trace, what line are you getting the error on? Most likely you just need to add a condition so that you aren't accessing an object that hasn't been initialized yet.
来源:https://stackoverflow.com/questions/4481314/adding-a-key-listener-in-action-script-3