Launching Pad: Redesigning a Retro Classic #1: Pacman
The last retro classic I redesigned was Asteroids when I created the game Retro Blaster. While I love early classic games, I also completely understand and appreciate how Nintendo, Sega, and other late 80's innovators built upon classic themes to re-ignite the video game industry. Not only did they create stories for most games, but they fueled re-playability with cheat codes, hidden secret rooms, extra bonus weapons, and more. Some 2600 (and other early console) games did include some of these elements, but it was the late 80's "new" thinkers that really pushed them to the limits and opened up what was a previously stale set-top box game arena. This was nothing new, because the 80's computer games for the C=64, Atari ST, and Amiga had been doing this well before the new TV game systems had hit the shores in the USA. The problem was that the C=64 was a fading giant, and the ST and Amiga were soundly outsold by Turbo PC clones and Macintosh systems. While the 80's PCs and Macs could play a pretty good arcade game (The Keen Series for the PC is a good example), not one computer system arcade game sold in enough numbers to be called a household name. In Europe it was was a different story, as cheap computers fueled a giant gaming industry that really never hit a true "crash". Even with the absolute best games being imported from Europe for USA Amiga. ST, and C=64 owners (as well as a few home grown hits like Dungeon Master) computer arcade games never made a dent in the general consciousness of the American public. That public had been burned on computers and simple video games, so Nintendo, and some extent Sega, TG-16, and a refreshed Atari brought a fresh coat of paint, challenges, and ingenuity to USA home gaming.
Why am I rehashing ancient history in this forum? It is the foundation for why I love to re-build retro classics. I love to research what went through the early game designers mind, and then try to code a game similar, but with some added late 80's extras. That's why Space Eggs (my pre-cursor to Retro Blaster) was a relatively simple Asteroids variant with the added bonus of increasing the fire power of your ship (and I deleted the dreaded Hyperspace functionality). When I built upon Space Eggs to create Retro Blaster, I did it with Nintendo in mind. I asked my self how Nintendo would have taken Ed Logg's original ideas and made something expanded. So, I added a story, levels progression, various different aliens ships and rocks to fight, boss levels, cheat codes, the ability to purchase ship upgrades, and a final battle with a difficult super boss. That is my plan for Pacman. I am going to first build a Flash AS3 engine that plays the basics of Pacman, and then extend that engine to create a much more expanded game in much the same way that Space Eggs was updated to become Retro Blaster.
![]() |
![]() |
|
Space Eggss >>>>
|
Became Retro Blaster
|
Pacman to Mazeman
Ok, so my next step will be to write down all of the significant things I remember about Pacman (and Ms. Pacman as the case may be). These can be both game design related. technical related, or just features that I liked about the game. I don't actually have to play the original game yet, I just need to organize some thoughts about the game into a list:
1. Pacman was tile based. I don't know how many tiles, but I think there were more vertical tile rows than horizontal tile columns.
2. The "hero, Pacman, was always moving unless he was stuck in a corner. He started out in the maze moving in one direction and there was no way to stop him unless the player moved him back and forth rapidly, or he got stuck in one of those aforementioned corners.
3. Pacman move freely from tile to tile. I have seen quite a few "maze" chase games where the player and the enemy sprites jump from tile to tile. While this is an interesting and maybe easier implementation, I want to tackle my maze game with free flowing motion.
4. Pacman can not move around in a passage way, he is always in the middle. Also, he cannot rotate his body in the 4 directions allowed unless there is an open tile in the direction he is trying to move.
5. Pacman doesn't seem to need to have his entire body exactly in the middle of an opening to turn and move into it, that would make the game much too difficult to play as the Pacman sprite is pretty close to the size of a back ground tile.
6. Pacman is chased by 4 distinct ghosts, each chases him in a unique manner (I will have to research this further).
7. The ghosts have 4 frames of animation (a least). Their eyes face the directly they are heading.
8. All ghosts turn the same color when Pacman eats an "energy pellet" and they run from him.
9. The ghosts have a "home" that I will refer to as an Enemy Generator.
10. The maze is the same in each level of Pacman, although Ms. Pacman has a number of different mazes. The mazes have tunnels that act like a side warp in Asteroids.
11. There are special bonus fruit and keys that give the player extra points when eaten.
That's my first stab at the remembering key features of the original, now here is my first list of what I want to make in Flash:
1. Mazes are loaded via xml. Maze graphics are contained in a sprite sheet.
2. The game can have any number of mazes and levels that will repeat after all level definitions have been run through.
3. I will have a tile that is an enemy generator, and multiple of those tiles can be in a maze.
4. My Enemy (ghosts) will not float back to a generator, but will disappear. More enemy (up to max per level or unlimited) will be created from the maze generators to take the place of the destroyed ones.
5. Enemy types, including sprites for 4 way animation (unlimited cells), speed, and intelligence will be defined in the xml.
6. Each level can specify what enemy types will be used for that level.
7. I want more that just one power up, but will settle for one in this first engine.
8. I will attempt to follow all of the movement rules of the original game, and investigate how to model those in AS3.
9. I want the "intelligence" of the ghosts to be based on some sort of real AI.
Ok, with that in mind, I went ahead of spent a coupe weeks coming up with the below demo. Now, I know the ghosts are very fast, and also dumb, and no player / ghost collision detection has been implemented yet. Plus, this is my first attempt at pixel art for a Pacman game, so there isn't any interesting shading or consistent light source for the tiles yet. I hope to create some better tiles in the future. Anyhow, here is my quick and dirty implementation:
Mochiads: Maybe The Best Thing For Flash Game Developers Since…Well…Flash

I've been experimenting with the beta version of MochiMedia's Mochiads system for the past few weeks. My first impression is that, when Mochiads finally rolls out to the public, it will help revolutionize the viral/free Flash game landscape.
Mochimedia have already been providing a very useful product named Mochibot for a couple years now. Mochibot is a way to track portals sites that have accepted (or stolen) your Flash games and put them on their own site. Mochibot is extremely easy to use. You just put some code in one of the frames of your .fla, compile, and Voila! You can track the online usage of your creations. Add encryption to your .swf file with something like SWF Encrypt 4.0 and you have a robust method for distributing and tracking your Flash games while remaining fairly certain that your code won't be stolen or your preloaders/credits stripped out.
However, tracking your games is only 1/2 the battle, it would also be nice to get some benefit from them once they are "in the wild". There are some already established ways to do this through through sponsorships and contests on portal sites, but not every game gets sponsored, and not every game can win a contest. This is where Mochiads steps in. Mochiads is way for you to insert ads into your own games, distribute them in any way you see fit. However, it goes beyond just that. With Mochimedia you get the feeling that there is now someone "on the side of the game developer", and it makes all the difference.
After you sign-up for Mochiads (at this point, get accepted into the beta, but come October 2007 it will be open to the anyone), you have the three options: [Dashboard][Game Setup][My Account]
[Dashboard] : This is where you track the performance of your games and see how much money you have accumulated.

[My Account]: This where you set your contact details so you can be contacted and paid
[Game Setup]: The heart of Mochiads. This is where you create the listings for your games and get the code for the ads. You have two choices of ads : preloader and in-game (i.e. between levels). You can use both in a game if you like. To put ads in your game you copy the provided code that is automatically generated for you, download the proper mochiads.as file (AS1, AS2, AS3), then re-export your .SWF with ads included. It's also a good idea to encrypt the .SWF, because rogue game portals will have even more incentive to disassemble your work and rip-out code when they see your ads. Your games are not automatically usable as soon as this process is complete. You must also provide a URL for Mochiads to view and approve your game before it goes into their system. Game approval usually comes within 12-24 hours. To be approved, your .swf must be a game, and the content cannot be deemed "objectionable" by Mochimedia. Fair enough, since they are making the deals with companies doing the advertising. You also have the ability to filter-out domains that will not show the ads, so if you do have an exclusive deal with a portal site, you can still support that agreement while showing ads on other sites or your own. Mochiads uses this feature themselves with Kongregate, as both companies have a partnership that goes beyond ad serving. You also have the option to upload your own "ad" that will be shown on the network when there are no other ads to be shown. This can net you a little extra traffic to your own site, which cannot hurt. There is not a lot of documentation available at this point for Mochiads, but what exists is sufficient for a moderately experienced developer. There also seem to be features to system that have not been finished or fleshed out quite yet. For instance, there are some tantalizing functions in the mochiads.as file, including a global high score system, that beg further explanation. On the good side, the Mochiads site offers a well-used forum filled with friendly and seemingly like-minded developers ready to offer help and support.
So, if this was all that Mochiads offered, it would be a good, maybe even a great tool, but it would not be revolutionary. The revolutionary part is that Mochiads will also act on your be-half as a distributor of your games, but demands no exclusivity or any other kind of licensing arrangements. It's in their best interest to get your games in-front of as many people as possible, and they have taken this to heart. Mochiads sets up distribution deals for games with their ads in them, and allows you to opt-in or out of the system. As well, Mochimedia is working with game portals to make sure they benefit too, making them more open adding games with embedded Mochiads.
In effect, what Mochimedia have successfully created is a full service revenue generation and distribution network for indie Flash game developers. The system is extremely easy to use, friendly, and when combined with Mochibot, indispensable. You can track your game usage with Mochibot, get revenue from Mochiads, and help get distribution from Mochimedia. For the first time as an indie game developer I feel like someone is a partner and not just trying to rip me off. I firmly believe that the tools Mochimedia has created will pioneer a new era for independent Flash game developers.
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 { public class PixelHitTestDemo extends MovieClip { public function PixelHitTestDemo() { } private function tilesLoadInit (e:Event):void { tilesBitmapData=Bitmap(loader.content).bitmapData; private function loadMapXML():void { private function xmlLoadComplete(e:Event):void { //loop through xml and add rows and columns to aTileMap array for (rowCtr=0;rowCtr for (colCtr=0;colCtr } screenBitmap=new Bitmap(screenBitmapData); } function createPlayerSprite():void { addEventListener(Event.ENTER_FRAME, run); function run(e:Event):void { function renderScreen():void { function getKeys() { } function checkCollisions():void { } } }[/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.
"Free Fireworks" Flash Engine Launches
Today we are launching our SECOND in a series of free, configurable game/activity engines for the web (following closely on the heels of "Free Jigsaw"). This one a further evolution of our "fireworks show" engine that can now be configured for almost any purpose.
You can watch fireworks launch, and/or launch your own with the mouse. Configure with your own music, background, flying image, colors, location, amount of fireworks, etc. Download and configure to your liking.
The engines are written in Flash and can be configured using XML. The engines are FREE and can be used for any application, as long as you do not remove our ads, preloaders, or links. If you would like to use the engines without these limits, email us at info@8bitrocket.com for licensing information. Our FREE fireworks show engine.
A Free license is granted for use as long as the .swf is not altered in anyway, and all ads, preloaders, title graphics and links remain unaltered. Again, To further configure the engine or obtain the source code, contact us info@8bitrocket.com
Download the files here: freefireworks.zip
Here are two other reskins of the same engine using different .mp3, .jpg, .pgn files and with a few simple tweaks of the configuration xml file.
The above skin sets the colors of the fireworks to an appropriate orange and purple for the occasion. It also increases the "glow" factor, and sets the fireworks to explode higher, to be near the moon.
The above skin locks the interface so colors cannot be changed, but still allows users to launch their own with the mouse.
As you can see, using some simple graphic and XML tweaks, you can configure this engine to be for almost any occasion.
The XML (config.xml) file to configure the engine looks like this:
<GAME_BACK>background.jpg</GAME_BACK> : Configure background image<BUTTON_PLAY>b_play.jpg</BUTTON_PLAY>: Configure "Play" button image<SONG_LOOP>1812edit.mp3</SONG_LOOP> : Looping soundtrack. Must be .mp3<MOUSE_FIRE>true</MOUSE_FIRE> : Allow users to use mouse to fire their own fireworks<BLIMP_GRAPHIC>blimp.png</BLIMP_GRAPHIC> : Configure "blimp" image (flys across the screen)<BLIMP_TEXT>Free Fireworks Show!!</BLIMP_TEXT> : Blimp scrolling text<BLIMP_TEXT_X>35</BLIMP_TEXT_X> : X position of blimp text<BLIMP_TEXT_Y>12</BLIMP_TEXT_Y> : Y position of blimp text<BLIMP_TEXT_SCALE>100</BLIMP_TEXT_SCALE> : scale of blimp text<BLIMP_TEXT_VISIBLE>true</BLIMP_TEXT_VISIBLE> : Set blimp text visible<BLIMP_Y>200</BLIMP_Y> : Y position on screen of blimp<BLIMP_DIRECTION>left</BLIMP_DIRECTION> : Blimp direction (left or right)<BLIMP_SPEED>1</BLIMP_SPEED> : blimp speed (in pixels)<FREQUENCY>35</FREQUENCY> : How frequency of new fireworks. A higher number means more fireworks will appear. Toggle for performance.<HEIGHT>70</HEIGHT> : Height of fireworks detonation zone (1-100)<WIDTH>50</WIDTH> : Width of firework detonation zone (1-100)<GLOW>15</GLOW> : Percentage of fireworks that will glow. Glowing is cool, but kills the processor.<AUTO>true</AUTO> : fireworks fire automatically. Kepp this on for a "show", turn it off if you just want the user to generate fireworks with the mouse.<MUSIC>true</MUSIC> : Play music (true/false)<USER_CONTROLS>true</USER_CONTROLS> : Allow the [Space Bar] to launch user control panel<RANDOM_COLORS>true</RANDOM_COLORS> : All random colored fireworks (this negates all color settings below)<AQUA>true</AQUA> : Allow this color of fireworks to launch initially (true/false)<BLUE>true</BLUE>: Allow this color of fireworks to launch initially (true/false)<GOLD>true</GOLD>: Allow this color of fireworks to launch initially (true/false)<GREEN>true</GREEN>: Allow this color of fireworks to launch initially (true/false)<LIGHT_AQUA>true</LIGHT_AQUA>: Allow this color of fireworks to launch initially (true/false)<LIGHT_BLUE>true</LIGHT_BLUE>: Allow this color of fireworks to launch initially (true/false)<LIGHT_GREEN>true</LIGHT_GREEN>: Allow this color of fireworks to launch initially (true/false)<LIGHT_ORANGE>true</LIGHT_ORANGE>: Allow this color of fireworks to launch initially (true/false)<LIGHT_PINK>true</LIGHT_PINK>: Allow this color of fireworks to launch initially (true/false)<LIGHT_PURPLE>true</LIGHT_PURPLE>: Allow this color of fireworks to launch initially (true/false)<LIGHT_RED>true</LIGHT_RED>: Allow this color of fireworks to launch initially (true/false)<LIGHT_VIOLET>true</LIGHT_VIOLET>: Allow this color of fireworks to launch initially (true/false)<LIGHT_YELLOW>true</LIGHT_YELLOW>: Allow this color of fireworks to launch initially (true/false)<ORANGE>true</ORANGE>: Allow this color of fireworks to launch initially (true/false)<PINK>true</PINK>: Allow this color of fireworks to launch initially (true/false)<PURPLE>true</PURPLE>: Allow this color of fireworks to launch initially (true/false)<RED>true</RED>: Allow this color of fireworks to launch initially (true/false)<SILVER>true</SILVER>: Allow this color of fireworks to launch initially (true/false)<VIOLET>true</VIOLET>: Allow this color of fireworks to launch initially (true/false)<WHITE>true</WHITE>: Allow this color of fireworks to launch initially (true/false)<BLACK>false</BLACK>: Allow this color of fireworks to launch initially (true/false)<YELLOW>true</YELLOW>: Allow this color of fireworks to launch initially (true/false)<MUSIC_CREDIT>Public Domain Music (1812 Overature : Performed by the Skidmore College Orchestra) Used Courtesy of http://www.musopen.com</MUSIC_CREDIT> <INSTRUCTIONS>Watch The Fireworks Show. Press [Spacebar] To See Control Panel. Increase "Frequency" For More Fireworks. Set "Glow" for the amount of "glowing" fireworks. Use Mouse To Launch Your Own Fireworks. Toggle [Auto] To Turn Automatic Show On And Off. Toggle [Music] Off If Show Is Running Slow. Toggle [Random Colors] for random fireworks colors. Click off/on colors that you want for your fireworks</INSTRUCTIONS>
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.
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.




