8bitrocket.com
12Sep/070

Flash CS3: Actionscript 3 (AS3) Game Primer #3: Bitmap Collision Detection

Flash CS3: Actionscript 3 (AS3) Game Primer #3: Bitmap Collision detection

One of the great features of Flash AS2 and AS3 is the ability to use the non-transparent colored pixels in a bitmapData object to accomplish pixel level hit detection. In this tutorial, we will build upon the last last two lessons : Flash CS3: Actionscript 3 (AS3) Game Primer #2: Asynchronous key detection for arcade games and Flash CS3: Actionscript 3 (AS3) Game Primer #1: Tile Maps, XML, and bitmapData to create a relatively simple but powerful example.

In the Game Primer #2, I discussed building some rudimentary code to re-create the key.isDown functionality that was removed in AS3. Since that tutorial was published, I have been informed that Flashgamecode.net has released a very slick key polling class that does this job very elegantly. We'll explore using this class, as well as build on the tile map and xml code we created in Primer #1.

The Tile Map
I created I unique set of simple tiles and xml map for this example. They were created using the same process as in the Flash CS3: Actionscript 3 (AS3) Game Primer #1: Tile Maps, XML, and bitmapData tutorial.

The tile set looks like this:

This is a 320x64 set of 20 32x32 tiles. I am only using 13 of the 20 tiles in this example. 14 actually, as #14 is a blank tile.

I used Mappy to create this tile map from the the above tile set.:

jpg example of the tile map created in Mappy.

This is a relatively simple map on a 10 x 10 grid. The red + is the player in this instance. As you can see, I have purposely created some tiles that do not take up the entire tile square and also ones that are odd (at least not square) shapes. Normally, if you did a pure tile based hit detection, you would be forced to accept a "hit" when the player enters the tile with a blue wall or object. The example below demonstrates this:

User arrow keys to move the player (red +) around the screen.

Basically, if the player's nextx and nexty values (the center of the +) are in a tile that is not blank, then a hit is detected and the player cannot move. Notice how inaccurate this test is. Some false positives show hits, and some true hits are not detected. It makes for an ugly experience. If you decide to make all tiles perfect squares, then this type of hit detection might work fine. In the case above, this really is not the ideal method to detect collisions between the player and the walls. We could build on this tile-based detection by adding more hit spots to check (we check the origin of the tile right now only). We could check the outer most point on the four points of the +, and that might actually do the job. Instead, we are going to try something a little different.

The next example is a more ideal method to detect these collisions:

User arrow keys to move the player (red +) around the screen.

In this example you will notice that the collisions are pretty much pixel perfect. Any transparent area on the player or a wall will not be used in the collision test. For this example, the entire wall and obstacle structure was read from the xml, copied from the tile set, and placed in a bitmapData object. When the user presses a key to move the player, the player is not immediately moved. The nextx and nexty variables are updated to reflect where the player will be in the future if this move is valid. The collision test is fired off based on these new values. If the next position is a valid one, the move is allowed. The collision is based on the ENTIRE bitmapData object (non-transparent areas) for the walls, and just the non-transparent bitmapData of the player. The entire code for this is below:

[cc lang="javascript" width="550"]/**
* ...
* @author Jeff Fulton
* @version 0.1
*/

package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.geom.*;
import flash.display.BitmapData;
import flash.net.URLRequest;
import flash.events.*;
import flash.net.*;
import flash.display.Loader;
import flash.ui.Keyboard;
import fgc.input.KeyPoll;
//http://flashgamecode.net/free/key-polling-class

public class PixelHitTestDemo extends MovieClip {
private var tilesBitmapLoader:Loader;
//private var tilesBitmap:Bitmap;
private var loader:Loader; // The bitmap loader
private var mazeData:XML;
private var xmlLoader:URLLoader;
private var aTileMap:Array=new Array();
private var mapRows:int=10;
private var mapCols:int=10;
private var screenBitmapData:BitmapData;
private var screenBitmap:Bitmap;
private var tileMapWidth:int=320;
private var tileMapHeight:int=64;
private var tileSize:int=32;
private var screenWidth:int=320;
private var screenHeight:int=320;
private var tilesBitmapData:BitmapData;
private var player:MovieClip=new MovieClip();
private var playerBitmap:Bitmap;
private var tilesPerColumn:int;
private var key:KeyPoll;

public function PixelHitTestDemo() {
//load in tile sheet image
loader = new Loader( );
loader.contentLoaderInfo.addEventListener(Event.INIT,tilesLoadInit);
loader.load(new URLRequest("primer3_tiles.png"));

}

private function tilesLoadInit (e:Event):void {

tilesBitmapData=Bitmap(loader.content).bitmapData;
//load in xml file for map
loadMapXML();
}

private function loadMapXML():void {
xmlLoader=new URLLoader();
xmlLoader.addEventListener(Event.COMPLETE, xmlLoadComplete);
xmlLoader.load(new URLRequest("primer3_maze.xml"));
}

private function xmlLoadComplete(e:Event):void {
mazeData=new XML(xmlLoader.data);

//loop through xml and add rows and columns to aTileMap array
//var rowXmlList:XMLList=mazeData.ROWX;
for (var rowCtr=0;rowCtr
var tempArray:Array=new Array();
for (var colCtr=0;colCtr tempArray.push(mazeData.tilerow[rowCtr].tilecol[colCtr]);
}
aTileMap.push(tempArray);
}
tilesPerColumn = tileMapWidth / tileSize;
trace ("tilesPerColumn=" + tilesPerColumn);
trace("aTileMap[4][4]=" + aTileMap[4][4]);
//using the data in the array, and add to screenBitmapData
screenBitmapData=new BitmapData(screenWidth,screenHeight,true,0x00000000);

for (rowCtr=0;rowCtr

for (colCtr=0;colCtr var tileNum:int=int(aTileMap[rowCtr][colCtr]);
var destY:int=rowCtr*tileSize;
var destX:int=colCtr*tileSize;
var sourceX:int=(tileNum % tilesPerColumn)*tileSize;
var sourceY:int=(int(tileNum/tilesPerColumn))*tileSize;
trace("tileNum=" + tileNum);
trace("destX=" + destX);
trace("destY=" + destY);
trace("sourceX=" + sourceX);
trace("sourceY=" + sourceY);
//code broken up below for formatting purposes
screenBitmapData.copyPixels
(tilesBitmapData,new Rectangle(sourceX,sourceY,tileSize,tileSize),
new Point(destX,destY));
}

}

screenBitmap=new Bitmap(screenBitmapData);
addChild(screenBitmap);
createPlayerSprite();

}

function createPlayerSprite():void {
//player sprite will contain a bitmap
var playerBitmapData:BitmapData=new BitmapData(tileSize,tileSize,true,0x00000000);
playerBitmapData.copyPixels(tilesBitmapData,new Rectangle(64,32,tileSize,tileSize),new Point(0,0));
playerBitmap=new Bitmap(playerBitmapData);
player.addChild(playerBitmap);
playerBitmap.x=-tileSize*.5;
playerBitmap.y=-tileSize*.5;
player.x=32;
player.y=32;
player.nextx=player.x;
player.nexty=player.y;
player.speed=2;
player.bitmapHitOffset=16;
addChild(player);

addEventListener(Event.ENTER_FRAME, run);
key = new KeyPoll( stage );
}

function run(e:Event):void {
getKeys();
checkCollisions();
renderScreen();
}

function renderScreen():void {
player.x=player.nextx;
player.y=player.nexty;
}

function getKeys() {
if( key.isDown( Keyboard.LEFT ) )
{
player.nextx-=player.speed;
}
if( key.isDown( Keyboard.RIGHT ) )
{
player.nextx+=player.speed;
}
if( key.isDown( Keyboard.UP) )
{
player.nexty-=player.speed;
}
if( key.isDown( Keyboard.DOWN ) )
{
player.nexty+=player.speed;
}

}

function checkCollisions():void {
//code broken up below for formatting purposes
if (playerBitmap.bitmapData.hitTest
(new Point(player.nextx-player.bitmapHitOffset,player.nexty-player.bitmapHitOffset),
255,screenBitmap.bitmapData,new Point(screenBitmap.x,screenBitmap.y))) {
trace("hit wall!");
player.nextx=player.x;
player.nexty=player.y;
}

}

}

}[/cc]

This is a lot of code, and much of it (the xml load and the tilesheet.png load and creation) was discussed in Game primer #1. For a simple review, here is a brief discussion of what the methods do:

public function PixelHitTestDemo()
This is the constructor. In this relatively simple example, its job is to load in the primer3_tiles.png tile map, and create a listener for the INIT event on the load.

private function tilesLoadInit (e:Event):void
This function is fired off when the tile png file is loaded. It then assigns a bitmapData object to hold the tile set.

private function loadMapXML()
This method begins the xml load of the map data. It creates an event listener (xmlLoadComplete) that is fired off when the data has been loaded.

private function xmlLoadComplete(e:Event)
This method does some real work. First it assigns the loaded in data to an xml object (mazeData) then it loops through the tilerow and tilecol xml nodes to assign a value to the aTileMap array. This array holds the 2d row and column single digit tile sheet location for each tile on the final maze to be displayed.

Next it loops through the aTileMap array using the tile set id number assigned above to find the tile in the tile set png file and copy it to to correct location in the screenBitmapData object. After the screenBitmapData has been created, it is assigned to the bitmapData property of the screenBitmap display object through the constructor - screenBitmap=new Bitmap(screenBitmapData). It is then added to the screen. This is a far as we got in Primer #1. We will now create a player object, a game loop, check for user input, check for collisions, and update the screen.

function createPlayerSprite():void
This method creates a player movieClip using the tile on the tile set as the surface bitmapData: playerBitmapData.copyPixels(tilesBitmapData,new Rectangle(64,32,tileSize,tileSize),new Point(0,0));
This data will be used in the collision detection with the screenBitmapData created in the method above. I have used a moveclip here only as a simple example. The main reason I did so is that is it the only display object that is a dynamic class. For this simple tutorial, I didn't want to create a separate player class. If I had, the player would be a Sprite because no timeline is needed. Using a movieclip as a display object is a quick and dirty method to prototype the types of attributes I would later create in my Player class.

This method also creates an ENTER_FRAME event that will call the "run" method (our basic game loop) repeatedly. Also, an instance of the Flashgamecode.net KeyPoll class is created to easily replicate the deprecated (and removed) key.isDown() method from AS2.

addEventListener(Event.ENTER_FRAME, run);
key = new KeyPoll( stage );

function run(e:Event):void {
getKeys();
checkCollisions();
renderScreen();
}

The run method does a lot of work, even though it looks rather simple. Basically it collects key input, then checks to see if the key input will cause a collision in the future, and then it renders the screen based on the result of the collision. Without this method, there would be no game.

function renderScreen():void
This method merely copies the nextx and nexty values to the x and y values of the player.

function getKeys()
Using the KeyPoll class, this method updates the nextx and nexty values by adding the player.speed variable where appropriate.

function checkCollisions()
This is the meat of the collision detection and it is pretty simple at first glance, but don't be deceived, a lot is going on here. We'll take the one call in little bites to describe what is going on. Here is the hitTest call in its entirety.

if (playerBitmap.bitmapData.hitTest(new Point(player.nextx-player.bitmapHitOffset,player.nexty-player.bitmapHitOffset),255,screenBitmap.bitmapData,new Point(screenBitmap.x,screenBitmap.y))) {

if (playerBitmap.bitmapData.hitTest - Here we are using the bitmapData stored in the player object and calling the hitTest method of the bitmapData object. Don't be confused, just because I used a movieClip instance to hold the player attributes, I am not doing a hitTest on the movieClip, I am doing it on the bitmapData inside the clip.

(new Point(player.nextx-player.bitmapHitOffset,player.nexty-player.bitmapHitOffset) - The first parameter in the bitmapData.hitTest method is a Point object representing the upper left-hand corner of the object being tested. In this case that object is the player and the point is the player.nextx and player.nexty values - meaning where that point WIIL BE, not where is currently is on the screen. Also, we subtract a "bitmapHitOffset" from each because I placed the player at an origin point of (-.5*width) for x and (-.5*height) for y. That put the players x and y value in the middle of the red +.

,255 - This represents the "alphaThreshold" for the test. That is the highest alpha channel value that is considered opaque for this hit test. In this case I want no transparency to detect a hit, so the number is 255.

,screenBitmap.bitmapData,new Point(screenBitmap.x,screenBitmap.y))) { - This is the second object for the collision detection. The entire screen of screenBitmap data, and a point representing the top left corner of the object (0,0).

player.nextx=player.x;
player.nexty=player.y;

If a hit is detected, then the nextx and nexty y values are reset back to the original values. This way, when the renderScreen() method fires, the player will not move. I am sure there are more sophisticated methods for do this, such as setting a boolean to true if the move is to happen, etc. I chose the simplest version for the tutorial.

That's it for this time. You can download all of the files for the tutorial here.

7Sep/070

Atari-infogrames, On The Ropes?

"Retro Rogue" martyg, a frequent visitor to our fourms ("frequent" is a relative term on our forums) has written a very detailed and insightful article about the fate of the Atarinfogrames.    In the article, martyg writes:

Atari management has had more changing faces and directions than a chameleon stuck in a room full of fun house mirrors. This is besides the fact that most of the fly by night management has come from Sony Music, the powerhouse of the video ga...I mean music industry. People from an industry notorious for being dragged kicking and screaming in to new technology and business models running a technology company and not succeeding?

You can read the entire article here: Atari Is Down For The Count

I, myself have always been very skeptical of Infogrames intentions with the Atari name.  Apparently, from I heard the only reason Infogrames renamed themselves Atari in 2003 (after buying the name and properties from from Hasbro in 2001) was because of backlash against anything French in the USA prior to the Iraq war.  At the time, I was very excited that the name Atari was going to appear on games again.   When I went to E3 in 2003, Atari had a HUGE presence outside the LA Convention Center.  The had bought an enormous flag with their "new" fuji logo and placed it in a primary spot, right above the entrance.    I was excited to see what "Atari" had in store at the show.  However, I was very disappointed to find out their booth was closed to "media only".   It reaked of "we've got something to hide".  They did:   The terrible "Matrix" game that almost bankrupt the company that year.  

Atarinfogrames was never able to make use of some of the properties that should have kept them in the black.  They bought "Humongous Entertainment", then cancelled most of their best product lines (i.e. "Pajama Sam") only to sqeeze every last bit of life out of "Backyard Sports".  They also bought the "Roller Coaster Tycoon" products from Hasbro, some of the best selling PC games EVER, and could not manage to make profit from those either.  They also seemed to drive any bit of life or interest from the "Neverwinter Nights" PC series. 

I hate to see the Atari name die once again, but maybe this time it is for the best.  Unless someone who really cares (like,  say, Nolan Bushnell,the guys at Atariage.com or Curt Vendel) could buy the remants and breath some real life back into the name "Atari", I'd rather just see it go away forever.  

What do you think?  Tell us in the forums or via email.

Filed under: Atari Nerd No Comments
2Sep/071

Flash CS3: Actionscript 3 (AS3) Game Primer #2: Asynchronous key detection for arcade games.

In Adobe's attempt to "improve" every aspect of Actionscript, they deleted some features that arcade game programmers have relied on for years. One of the most fundamental aspects in most arcade games is accurately timed user input detection. Sadly, this has been made much more difficult (but not impossible) in AS3. Before AS3, one only needed to use the key.isDown(keycode) global method to detect a key press. The beauty of this method was that is didn't pause before detecting the next key press. This was a subtle, but very import feature of most action games. To replicate the "arcade" experience, the keyboard needs to allow the "down" state to fire repeatedly without interruption. In Adobe's defense, the key.isDown(keycode) method was not good for detecting text input as the repeating nature of the key presses was terrible for that purpose. Also, Adobe has explained, there are some security reasons why this method was eliminated. It has been replaced with a new keyboard listener that is much better for text input, but terrible for arcade game input. The new listener pauses after the initial key down event on a key, and waits a few milliseconds to fire off a repeat of the key. While this is wonderful for text input, it makes a game like Asteroids play very strange. When a user holds down the left or right "rotate" button in Asteroids, the result should be a smooth repeating rotation. The rotation should not increment once, then pause, then start incrementing again. This is impossible with a plain vanilla implementation of the new key listener model.. On top of that, the synchronous nature of the new event model makes game loop timing almost impossible. So, even if they had added in some sort of key repeat setting in the key listener, game loops would still be difficult to create. All is not lost though, in this lesson will examine a efficient method of using this new key listener and still detect non-pausing, repeatable key presses.

Why asynchronous key detection is needed for an action game loop.

Arcade games require very exact timing. The basic code for an AS2 arcade game loop might look like this:[cc lang="javascript" width="550"]private function gameLoop():void {
getKeys();
moveObjectsInMemory()
checkCollisions();
render();

}[/cc]

In a simple shooter style game, the above would function like this:

1. Check for some user input
2. Update positions of player and enemy objects in memory only. Don't physically move them on the screen. For example, variables such as nextx and nexty can be used to hold the next location in memory.
3. Use math collision detection methods, circle - circle, square - square, tile based, pixel level, or other methods using the new locations stored in memory (not the current physical locations of objects).
For instance, if the user tries to go in a direction or to a location he cannot go, the nextx and nexty would be changed back to the original x and y before the objects positions are updated on the screen. This is a simple way to prevent the player from moving onto a tile that is not passable without physically moving him first, then checking his new location against rules and collisions, and the moving him back again. There is no need to display those actions on the screen to the user, and it is much cleaner to do it before it is visually represented on the screen.
4. Copy the nextx and nexty locations to the x and y properties of the onscreen objects and put them on the screen.
5. Repeat.

All four of these methods must be timed to fire off asynchronously. This is where the new key listener model becomes a problem. If the program is constantly listening for key listen events, the player can update his/her position during the other phases of the game loop, and not just during the "getKeys" method. One possible solution would be the repeatedly add and delete the key listener so keys are only checked during the getKeys phase. Even if this idea worked (I tried it with no success), it wouldn't solve the next problem - detecting repeating keys.

Here is a basic example of an Asteroids style ship rotation using just the new listener model:

Hold down the left or right arrow key to rotate the ship. You will notice a little hiccup after the first key response before the smooth rotation begins.

[cc lang="javascript" width="550"]
/**
* ...
* @author Jeff Fulton
* @version 0.1
*/

package {
import flash.display.MovieClip;
import flash.events.*;

public class Mainloop1 extends MovieClip {

static const RIGHT = 39;
static const LEFT = 37;

public function Mainloop1() {

addEventListener(Event.ENTER_FRAME, run);
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
ship_mc.nextrotation=ship_mc.rotation;
}

function run(e:Event):void {
//moveObjectsInMemory();
render();
}

function keyDownListener(e:KeyboardEvent):void {
trace("e.keyCode=" + e.keyCode);
if (e.keyCode==LEFT) {
trace("left");
ship_mc.nextrotation=ship_mc.rotation-5;
}else if (e.keyCode==RIGHT) {
trace("right");
ship_mc.nextrotation=ship_mc.rotation+5;
}

}

function moveObjectsInMemory() {
//not needed because key listener does memory update
}

function render() {
ship_mc.rotation=ship_mc.nextrotation;
}
}

}
[/cc]

In this simple example, the "run" method is the main game loop. Normally, we would have three methods for it to call to just update rotations:

getKeys();
moveObjectsInMemory();
render();

We have eliminated the getKeys() and moveObjectsInMenory methods because there is nothing for them to do. If we had enemy ships and asteroids on the screen, then the moveObjectsInMemory() function would still be needed, but the keyKeys() would still be not be needed because the keyDownListener supposedly works in its place. Obviously, the ship rotation is NOT ideal, so let's try another approach.

Hold down the left or right arrow key to rotate the ship. This version rotates much smoother than the previous example.

[cc lang="javascript" width="550"]
/**
* ...
* @author Jeff Fulton
* @version 0.1
*/

package {
import flash.display.MovieClip;
import flash.events.*;

public class Mainloop2 extends MovieClip {

static const RIGHT = 39;
static const LEFT = 37;
private var keyPressed:Boolean;
private var keyNum:int;
private var shipIncrement:int=0;
public function Mainloop2() {

addEventListener(Event.ENTER_FRAME, run);
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpListener);
ship_mc.nextrotation=ship_mc.rotation;
}

function run(e:Event):void {
getKeys();
moveObjectsInMemory();
render();
}

function keyDownListener(e:KeyboardEvent):void {
keyPressed=true;
keyNum=e.keyCode;
}

function keyUpListener(e:KeyboardEvent):void {
keyPressed=false;
keyNum=undefined;
}

function getKeys() {

if (keyPressed) {
switch (keyNum) {
case LEFT:
//trace("left");
shipIncrement=-5;
break;
case RIGHT:
//trace("right");
shipIncrement=5;
break;
}
}else{
shipIncrement=0;
}
}

function moveObjectsInMemory() {
ship_mc.nextrotation=ship_mc.rotation+shipIncrement;
}

function render() {
ship_mc.rotation=ship_mc.nextrotation;
}
}

}

[/cc]

The above example has re-implemented the game loop properly and the key detection is much better. Also, there is no collision detection in this quick example, but if added, the the above example would perform much better than the first example because the entire game loop runs asynchronously.

Here is what i did.

1. I created 3 new variables:

private var keyPressed:Boolean;
private var keyNum:int;
private var shipIncrement:int=0;

If the keyDownListener is fired off, the keyPressed var is set to true until the keyUpListener is fired off. The keyDownListener sets the keyNum var to be the keyCode of the key pressed.

2. The game loop contains all three asynchronous methods:

getKeys();
moveObjectsInMemory();
render();

The getKeys() function now does a switch on the key pressed and changes the shipIncrement:int var to the appropriate new value.
The moveObjectsInMemory() function now uses the shipIncrement value to rotate the ship left or right in memory. If we needed the collision detection, we would do it next before we call the render() function.

 

Detecting Multiple Key Presses

That's all find and dandy, Jeff, you say, but the ship in Asteroids does much more than just rotate. How do would the ship be able to rotate AND thrust (or fire, or all three) at the same time with code like this. One answer would be to change the keyDownListener and keyUpListener to detect individual key presses, and set boolean values for each. So, we would eliminate the keyPressed and keyNum variables and add in boolean checks for all of the separate keys that need to be detected. Another possible solution would be to create an array of pressed keys and loop through it on each interval. I think they are both valid solutions, and we'll explore the former here and leave the array version up to you. I haven't tried it yet, but I can imagine there might be some trouble with responding to multiple of the same key press. You would need some boolean variables set to true or false so a key isn't fired off twice (at first thought), so I don't think it would be too much better than this next version. If you have a great way to do this, please email me. This method is the first one I thought of, and it works, so I'm using it for the foreseeable future.

Hold down the left or right arrow key to rotate the ship. Press up to thrust the ship in the direction it is facing. With boolean variables controlling all key presses individually you will have no trouble doing both at the same time.

[cc lang="javascript" width="550"]
/**
* ...
* @author Jeff Fulton
* @version 0.1
*/

package {
import flash.display.MovieClip;
import flash.events.*;

public class Mainloop3 extends MovieClip {

static const RIGHT = 37;
static const LEFT = 39;
static const UP = 38;
private var keyPressedRight:Boolean;
private var keyPressedLeft:Boolean;
private var keyPressedUp:Boolean;
private var shipIncrement:int=0;
public function Mainloop3() {

addEventListener(Event.ENTER_FRAME, run);
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpListener);
ship_mc.nextrotation=ship_mc.rotation;
ship_mc.dx=0;
ship_mc.dy=0;
ship_mc.speed=.2;
ship_mc.nextx=ship_mc.x;
ship_mc.nexty=ship_mc.y;
}

function run(e:Event):void {
getKeys();
moveObjectsInMemory();
render();
}

function keyDownListener(e:KeyboardEvent):void {
switch (e.keyCode) {
case LEFT:
keyPressedRight=true;
break;
case RIGHT:
keyPressedLeft=true;
break;
case UP:
keyPressedUp=true;
break;

}

}

function keyUpListener(e:KeyboardEvent):void {
switch (e.keyCode) {
case LEFT:
keyPressedRight=false;
break;
case RIGHT:
keyPressedLeft=false;
break;
case UP:
keyPressedUp=false;
break;

}
}

function getKeys() {
shipIncrement=0;
if (keyPressedRight) {
shipIncrement=5;
}else if(keyPressedLeft) {
shipIncrement=-5;
}
if (keyPressedUp) {
ship_mc.dx=ship_mc.dx+ship_mc.speed*(Math.cos(2.0*Math.PI*(ship_mc.rotation-90)/360.0))
ship_mc.dy=ship_mc.dy+ship_mc.speed*(Math.sin(2.0*Math.PI*(ship_mc.rotation-90)/360.0))
}
}

function moveObjectsInMemory() {
ship_mc.nextrotation=ship_mc.rotation+shipIncrement;
ship_mc.nextx=ship_mc.x+ship_mc.dx;
ship_mc.nexty=ship_mc.y+ship_mc.dy;
if (ship_mc.nextx < 0) ship_mc.nextx=300;
if (ship_mc.nextx > 300) ship_mc.nextx=0;
if (ship_mc.nexty < 0) ship_mc.nexty=300;
if (ship_mc.nexty > 300) ship_mc.nexty=0;
}

function render() {
ship_mc.rotation=ship_mc.nextrotation;
ship_mc.x=ship_mc.nextx;
ship_mc.y=ship_mc.nexty;
}
}

}
[/cc]

In this version, we have created boolean variables to hold our three different key presses:

private var keyPressedRight:Boolean;
private var keyPressedLeft:Boolean;
private var keyPressedUp:Boolean;

The keyDownListener and keyUpListener switch on the event keyCode value and then set the boolean variables to true or false respectively. This enables the getKeys() function to work with both a left/right movement and a thrust movement at the same time. You can add booleans for each of your needed key presses and then be able to detect any number of keys, in asynchronous mode to keep your game loop and player movement timed perfectly.

There you have it. Nothing brilliant, nothing complicated, just some down home good 'ol Booleans and a plain old game loop and you have an AS3 version of AS2 keyDown functionality.

 

   
This site is protected by Comment SPAM Wiper.