8bitrocket.com
31Jan/080

Mid-Core Gamer Manifesto

A few weeks back, we here at 8bitrocket.com declared ourselves to be Mid-Core Gamers. Jeff's declaration was met with a smattering of agreement from other sites, but it was not an earth shaking response. Still, it was encouraging, and since we not only believe in the theory of Mid Core Gamers , but also live it every day, we have decided to explore this idea a bit further. us.

Also, we are putting together a Manifesto of the top-10 things that we Mid-Core Gamers would like to see in games targeted to our demographic. This is in no-way final, but it is our best first guess from what we currently know.

1. Save Anywhere/Autosave/Respect Our Time:

We only have time to play games in roughly 5-60 minute increments. We need the ability to save our game at a moment's notice. If a game's difficulty is designed around the fact that is cannot be saved anywhere, it is too hardcore for us. Not only do we need to save anywhere, but we don't want to waste the time we have invested in the game if we can't save any where. An alternative or addition to "Save Anywhere" is an intelligently used 'autosave' feature.

We would like something significant to happen in a game during the time period we have allotted to play. A plot point, new item, finished race, completed mission or task should take roughly 30 minutes (give or take 15 minutes) to achieve. This allows us to see progress in a game, and keeps us interested in continuing. Games with long cut scenes (i.e Final Fantasy X 30 minute intro) are rendered unplayable because we never have enough time to get past the exposition and into the game.

Our free time is precious, and it needs to be respected.

2. Games Should be Affordable

We are not suggesting that new games should cost $.99 nor are we suggesting that state-of-the-art releases should only cost $29.99. But we are saying this: We can't justify spending $59.99 on games each month unless they can also be played with the rest of our families (read: Wii). For games targeted to us, $19.99 is a perfect price, but $9.99 is nicer while $29.99 is our upper limit. $.99 is great price for downloadable classic games. Also, we Mid-Core Gamers can be very patient. When Elder Scroll Oblivion was released, it fit perfectly into our demographic (see below), but the price was far too high. Now, after nearly two years, the price has come-down to $29.99. Bingo. We can bide our time for a good game.

3. Reasonable Graphic Choices

We don't buy computer hardware like we used to. We don't upgrade for the sake of upgrading, we don't care too much about getting top FPS scores. In fact, many of our games are played on laptops with good (but not the latest) graphics cards. Games do not need to employ the latest 3D graphic technology just for the sake of having it, or require the latest OS. Games can have nice graphics (2D or 3D), but the most important aspect of the graphics is that they fit the game and serve it well.

4. We Love Single Player Games

Single-player games are our bread-and-butter. We understand that the gaming world is filled with amazing hard-core and multi-player gaming experiences. We also realize that those games usually take more time and resources than we have available. For this reason, we eat-up single-player games. Even single-player games that appear to be "hard core" would fit the Mid-Core mold if they adhere to the other parts of this manifesto. A great example of a single-player game that fits the Mid-Core is Elder Scrolls Oblivion. It is an expansive, yet "light" RPG that fits many of the aspects of this manifesto: (engrossing depth, $29.99 price point, works on a good laptop, can save anywhere, etc).

5. Cooperative Games On One Screen Are Gold

Cooperative two-player games are gold. If they are deep enough to appeal the hard-core portion of our gamer-personality, but easy enough so we can get the wife/husband/significant other and/or the kids involved, we can probably play them beyond the 60 minute barrier. A very good example of this type of game is Lego Star Wars. It's appeals to our inner geek, has long and interesting levels, but allows two people to play on the screen at once. Of course, Lego Star Wars did not allow the game to be "saved any where", but it fit many of the other aspects of this manifesto.

6. Multi-player Games: Play Anytime, Find Friends Easily, No Fees, Voice Chat Not Necessary

We do enjoy playing multi-player games online with friends and sometimes, even strangers. However, there is a limit to what we can handle. First off, an "instant and anonymous multi-player mode" similar to the Wii version of Guitar Hero can work very well because it means we can compete quickly, but each game only takes a few minutes. However, if we do want to play against friends, you need to make it very easy. We need to be able to tell very quickly if someone we know is online, and if so, connect with and challenge them instantly. The Wii is terrible for this purpose, XBox Live is better, but it requires a monthly fee (see below). If Playstation Home remains free, it might be the perfect model. Also, one more thing. We don't want to hear 13 year old kids curse at us for not moving quickly enough. If your multi-player games requires us to participate in voice-chat, we are probably not interested.

7. "Casual" Games Don't Have To Be Simple Games

We Mid-Core Gamers love all types of games. To some extent, Mid-Core gamers are "casual" gamers in that we do enjoy many of the types of games that are geared towards the "casual" demographic. However, we tend towards "casual" style games with a bit more depth. For instance, Bejeweled is a passable diversion, but Puzzle Quest is an obsession. Bookworm Deluxe is nice way to kill some minutes, but Bookworm Adventures is an unshakable addiction. Where there is depth, but with the aforementioned save anywhere feature, we will be there.

8. Size Does Not Matter

The last two commercial games I have installed on my computer have been just about 5.5 GB in size each. 5.5 Gigabytes! I believe just about every single game ever made before 1994, could fit in 5.5 GB with room for 1000's more. Graphically those games could never compare with the modern 5.5 GB behemoth, but game-play and depth wise? A lot of those pre 1994 games had much more than in some modern games. The point here is not that "retro games are better" but that the size of the game on the hard drive is not necessarily proportional to its quality as piece of entertainment. Most good Flash games download in less than 1 megabyte. Good, downloadable PC games can be had that are under 20 megabytes (i.e.: New Star Soccer). Mid-Core Gamers do not need bloat, they need well designed games with solid game-play. If a game is worth the 5.5 GB required, that is fine, but if not, it eill probably be removed fairly quickly and never played again.

9. No need to be "mature" for the sake of being "mature"

Mid-Core Gamers are mostly adults. Mid-Core Gamers were also once 13 years old, and also once laughed about the name Lake Titticaca" in Social Science class. However, that does not mean we need resort to only consuming "mature" material, or that our in-game humor has to be at the scatological level. Yes we do play games, but we don't want to have to hide them, their boxes, or the game magazines we read from our families simply because they might have a cover featuring, for example, an artist' rendition of scantily-clad female robot tearing the intestines out of space marine. Mature content is not necessarily taboo, it just needs to be used to serve the story, not in place of it.

10. Yes To One-Time Fees, Rarely To Monthly Fees,

Mid-Core Gamers are not fond of monthly fees. We can not always subscribe to your game, live service, player matching server, etc. if it means we have to pay for it month after month. We can't afford it, and we don't want to have to explain this fee to our husband/wife/significant other. For the rare game, a monthly fee might be workable, but we won't last very long. However, if there is a compelling reason, we will pay one-time fees. One-time fees for updates, new chapters, sequels, power boosts (i.e. Adventure Quest), add-on modules etc. are acceptable. However, the one-time fees must be reasonable, and offer a significant benefit. A One-time fee that allows us to buy things that should have been included in the game in the first place
(i.e. Horse Armor) is not acceptable.

Axioms
1. There Are Exceptions To All These Rules
2. Midcore Gamers can be of any age
3. Any game can be a Midcore Game.
4. In some cases Midcore is not the game, but how you play the game

More On Mid-Core:

31Jan/080

Flash Game Development Blog World : January 31, 2008

The latest in Blog entries that might interest Flash game developers.

Gaming Your Way has a new entry on Wii Game Development in Flash. It is basically a link to another site that has compiled 73 tips and tutorials for making home-brew Wii games. I've been itching to pimp Squize and nGFX's blog here and I finally got my chance. These guys are top class. They plain know how to make great games.

Mike Grundvig (of Multiplayer Flash engine GODS, Elecrotank) extends a thread he started on Flashkit with a healthy discussion on using Binary Data for maps in Flash. It's A great read. Nice work, Mike!

Our very own series on advanced blit techniques applied to an Asteroids game should also be checked out if you have time. I just put Part 2 up yesterday.

30Jan/080

Tutorial: Using Flash CS3 and Actionscript 3 to create Atari 7800 Asteroids Part 2

In Part 1 we covered creating an array of pre-calculated vector values for 36 angles. These 36 angles were used to move the player ship on the screen in one of the 36 rotated directions. We also covered a basic animation cache from a library object by rotating its container and taking a BitmapData snapshot of each frame. We then created a simple game engine and got the player ship moving about the screen, thrusting in the right direction. We applied some simple friction and inertia principles and used a BLIT technique on every frame to to copyPixels to a single display object.

In Part 2, we will take a smaller bite and cover how to cache the animation of a library object with a frame based animation for our asteroid rocks. We will add the rocks to our game loop and see them animating on the screen, running through their cached animation frames and being BLITTED to our single display object with copy pixels.

I created the rock frames by in a round about manner. I am using the Atari 7800 version of Asteroids as my basis for this game, so I started by firing up my MESS emulator and playing the game. The 7800 version of Asteroids is not as well known as the arcade version, but it was my favorite version, and one of the best games released for the 7800. It has multiple different colored and shaded rocks to shoot, but I just need one for the tutorial, so I chose to model the green rock. To do this, I decided to record the screen while I played the game. I fired up my copy of Replay Video, and had it record the screen for 30 seconds while I played 7800 Asteroids in MESS. I then brought the video into Sony Vegas for editing. I dropped the video into the timeline in Vegas, and used the frame advance scroll bar to move a couple frames at a time through the video of the game play. I zoomed in on the green rock and at each key frame change, I saved a JPEG of the screen. I pulled all of these JPEGs into Fireworks and editing them each down to an 18x16 image. Then, I deleted the background of each frame (there were 12 good frames). I save each one out as a .PNG file and imported all of them into Flash CS3. I built clip in the library called "rock" with one frame by putting a PNG on each of 12 key frames.

The rock clip in the library looks like this (at 200% zoom):

As you can see, it is at 0,0 on the stage. To actually cache a library clip with timeline animation, we must add this clip to a holder clip that we can export. The holder clip is called "rockToCache" in the library, and its stage looks like this:

The "rockToCache" clip has an instance of the "rock" clip set at 0,0. I increased the size from 18x16 to 36x32. That will make it more pixilated, but I think the other version was too small. If this was for a commercial game, I might clean up all of the frames by tracing over vectors before and then zoom in if needed. I gave the ":rock" clip an instance name of "clip" and set the "rockToCache" linkage class name to "RockToCache".

Now, on to the Actionscript needed to cache he animation ands add rocks to our game loop.

In our Main.as class, I have added these lines in the variable declaration section (below the class definition and before the constructor).

[cc lang="javascript" width="550"]
//** part 2 variables
var aAsteroidAnimation:Array=[];
var asteroidAnimationTimer:Timer;
var asteroidHolder:RockToCache;
var asteroidFrames:int=12;
var aRock:Array=[];
var level:int=1;
var rockPoint:Point=new Point(0,0);
var rockRect:Rectangle=new Rectangle(0,0,36,36);
var levelRocksCreated:Boolean=false;
[/cc]

aAsteroidAnimation is an array that will hold 12 BitmapData objects representing the 12 frames of animation in the rock clip.
asteroidAnimationTimer is a Timer object that that will count up to 12.
asteroidHolder is an instance of the RockToCache library clip. We only need one and it will be used exclusively as a holder to run through the "rock" frames.
aRock
is an array that will hold all of the instances of our rock objects for game play.
level is a integer that will hold the current game play level. Eventually, when we add in collision detection, we will have the game move to a new level when all of the rocks are cleared.
rockPoint is a pre instantiated point object used in the copyPixels operation for all rocks to the canvasBD. The rockPoint will be changed to the x and y coordinates of the current rock before the copyPixels is completed.
rockRect is a static rectangle instance that simply represents a bounding box for the max size of our rock (36x36).
levelRocksCreated is the first of our game control variables. When we start a new level, this will need to be set to false;

[cc lang="javascript" width="550"]
private function animationTimerCompleteHandler(e:TimerEvent):void {
createAsteroidAnimation();
//startGame();
}

[/cc]That sets up the variables needed for this part. Now, there was a change to the animationTimerCompleteHandler from part 1. We have commented out the startGame() call and have replaced it with a call to a new createAsteroidAnimation() function.

[cc lang="javascript" width="550"]
private function createAsteroidAnimation():void {
animationCounter=1; // match frame on timeline
asteroidHolder=new RockToCache();
asteroidHolder.x=100;
asteroidHolder.y=100;
addChild(asteroidHolder);
asteroidAnimationTimer=new Timer(1,asteroidFrames);
asteroidAnimationTimer.addEventListener(TimerEvent.TIMER, cacheAsteroid);
asteroidAnimationTimer.addEventListener(TimerEvent.TIMER_COMPLETE,
asteroidAnimationTimerCompleteHandler);
asteroidAnimationTimer.start();
}

[/cc]

The createAsteroidAnimation() function sets up the Timer based loop that will jump to each frame of the "ship" library clip and cache (or store) the pixel data from that frame in a BitmapData object. In part 1, we stored all of the rotations of the ship clip my manipulating the rotation property of its holder clip called "shipHolder". For the rock, we will use a different method. On each iteration we will "gotoAndStop()" the next frame on the timeline and "draw()" those pixels to a BitmapData object, and then add that object to our aAsteroidAnimation. I did the rock this way because it is the most likely delivery method that a designer might give you for a tween-like animation. We will explore one more method of creating an array of BitmapData objects when we use a sprite sheet to create the animation loop for the playerShip's missiles.

animationCounter=1;
First we set out animationCounter to be 1. We don't start with 0 because we want to make it easier on ourselves to follow the timeline frame of the rock. Since the timeline is "1 based" rather than "0 based" we set this to 1.

asteroidHolder=new RockToCache();
We create an new instance of out RockToCache library item. Remember, this is basically a holder for a instance of our rock library item named "clip".

asteroidHolder.x=100;
asteroidHolder.y=100;
addChild(asteroidHolder);

These merely put the holder on the screen in a place we can see it. If we set the frame rate of the movie very low, we can see the actual cache happen. If not, this location doesn't matter. We also add the asteroidHolder to the display list to make sure we can see it and cache its contents.

asteroidAnimationTimer=new Timer(1,asteroidFrames);
asteroidAnimationTimer.addEventListener(TimerEvent.TIMER, cacheAsteroid);
asteroidAnimationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, asteroidAnimationTimerCompleteHandler);
asteroidAnimationTimer.start();
These 4 lines create a timer that will run 12 times. On each of the 12 iterations it will call the cacheAsteroid method and when it is complete with the 12 iterations it will call the asteroidAnimationTimerCompleteHandler. The final line starts the timer on its way.

 

[cc lang="javascript" width="550"]
private function cacheAsteroid(e:TimerEvent):void {
asteroidHolder.clip.gotoAndStop(animationCounter);
var spriteMapBitmap:BitmapData=new BitmapData(36,36,true,0x00000000);
spriteMapBitmap.draw(asteroidHolder,new Matrix());
aAsteroidAnimation.push(spriteMapBitmap);
//trace("caching " + animationCounter);
animationCounter++;

}

private function asteroidAnimationTimerCompleteHandler(e:TimerEvent):void {
trace("cacheAsteroid 7");
startGame();
}

[/cc]

The cacheAsteroid() method is called 12 times and on each call it draws the current frame of the rock clip (referenced as asteroidHolder.clip) to a new Bitmapdata object. That object is added to the aAsteroidAnimation array.

asteroidHolder.clip.gotoAndStop(animationCounter);
This line simply instructs the clip instance of the "rock" clip inside the asteroidHolder to move to the current frame represented by the animationCounter;

var spriteMapBitmap:BitmapData=new BitmapData(36,36,true,0x00000000);
Here we create a new BitmapData object and set it to 36x36 with transparency. And set the transparency threshold at 0 and the background fill color to black. Since the threshold is 0, we don't see any of the background color show through.

spriteMapBitmap.draw(asteroidHolder,new Matrix());
Here we draw the current state of the asteroidHolder to the new BitmapData object. The asteroidHolder contains the "clip" which is an instance of the rock library item that has been moved to the current frame of animation.

aAsteroidAnimation.push(spriteMapBitmap);
animationCounter++;

These two lines simply add the BitmapData object to the aAsteroidAnimation array and increase the animationCounter so the gotoAndStop will go to the next frame on the next interval.

The asteroidAnimationTimerCompleteHandler() method simply starts our game. The method that starts our game will change as we add to the game. It will always be the last method of the setup phase that calls startGame.

 

[cc lang="javascript" width="550"]
private function runGame(e:TimerEvent) {
checkKeys();
updatePlayer();
updateRocks();
drawBackground();
drawPlayer();
drawRocks();
}

[/cc]

The runGame() method has been modified from the part 1 version. We have added 2 functions to handle rocks. The updateRocks() method does all of the work in creating the initial rocks for the game (or level) and also updates all of the rocks on the screen based on their individual dx,dy, and speed variables.

 

[cc lang="javascript" width="550"]
private function updateRocks():void {
if (!levelRocksCreated) {
for (var ctr:int=0;ctr //create a rock;
var tempRock:Object=new Object();
var randInt:int=int(Math.random()*36);
var randInt2:int=int(Math.random()*asteroidFrames);
tempRock.dx=aRotation[randInt].dx;
tempRock.dy=aRotation[randInt].dy;
tempRock.x=20;
tempRock.y=20;
tempRock.animationIndex=randInt2;
tempRock.frameDelay=3;
tempRock.frameCount=0;
tempRock.speed = (Math.random()*level)+1;
trace("tempRock.speed=" + tempRock.speed);
aRock.push(tempRock);
}
levelRocksCreated=true;
}
for each (tempRock in aRock) {
tempRock.x+=tempRock.dx*tempRock.speed;
tempRock.y+=tempRock.dy*tempRock.speed;

if (tempRock.x > stage.width) {
tempRock.x=0;
}else if (tempRock.x < 0) {
tempRock.x=stage.width;
}

if (tempRock.y > stage.height) {
tempRock.y=0;
}else if (tempRock.y < 0) {
tempRock.y=stage.height
}

}
}

[/cc]

The updateRocks() method takes care of two main duties for the rocks. Currently, the first thing it does is create rocks for the level and once it is does, it sets levelRocksCreated to true; We do this here out of convenience, but in a later part of this tutorial, it will probably be moved to a section that inits all new levels. We haven't implemented our gameLoop or game control structure, so it is fine here for now.

The other important task for this method is to loop through all for our rocks on each game loop timer tick and update their x and y properties.

if (!levelRocksCreated) {
for (var ctr:int=0;ctr

These two lines begin the iteration to create the rocks for the level. I chose to create 3 rocks for the first level and then add one for each additional level. At some point we will put a cap on the total to start with, but for now we will not do so.

var tempRock:Object=new Object();
var randInt:int=int(Math.random()*36);
var randInt2:int=int(Math.random()*asteroidFrames);

tempRock.dx=aRotation[randInt]. dx;
tempRock.dy=aRotation[randInt]. dy;
tempRock.animationIndex=randInt2;
Here we create a generic object to hold our rock. Next we randomly choose a random number from 0-35. We will use this to index our aRotation array do obtain random dx and dy vectors for this rock. We also choose a random frame of animation for our rock to start on so all of the rocks don't rotate in sync.

tempRock.x=20;
tempRock.y=20;

tempRock.frameDelay=3;
tempRock.frameCount=0;
tempRock.speed = (Math.random()*level)+1;
aRock.push(tempRock);

This set of code takes care of some setup for the new rock. First, we currently are starting all new rocks at 20,20 on the screen. We set the frameDelay for the rock at 3. This will count 3 frames between each animation change so our rock won't appear to spin too fast. The final setup for the rock is to give it a random speed to multiply the dx and dy values by. We randomly choose a number between 0 and the current level, then add 1 so if a number below 1 is randomly selected . We do this so our multiple won't create a speed slower than the basic dx and dy values. Lastly, we push the rock to the aRock array.

The last part of this method moves the rock to its new position in memory and then checks to see if it is off the screen. If it is, it warps it back to the other side. I haven't put in the centerx and centery values for the rocks yet, but we we add them for collision detection in a later part of this tutorial series. When we do that, we will revisit this code and update the centerx and centery before.

tempRock.x+=tempRock.dx*tempRock.speed;
tempRock.y+=tempRock.dy*tempRock.speed;

These two lines multiply the rock's current movement vectors by the current rock speed. The final lines of the method handle the warping off the sides of the screen based on the current x and y values for the rock.

 

[cc lang="javascript" width="550"]
private function drawRocks() {
var rockLen:int=aRock.length-1;
var ctr:int;

for each (var tempRock:Object in aRock) {

rockPoint.x=tempRock.x;
rockPoint.y=tempRock.y;

canvasBD.copyPixels(aAsteroidAnimation[tempRock.animationIndex],
rockRect, rockPoint);

tempRock.frameCount++;
if (tempRock.frameCount > tempRock.frameDelay){

tempRock.animationIndex++;
if (tempRock.animationIndex > asteroidFrames-1) {
tempRock.animationIndex = 0;
}
tempRock.frameCount=0;
}
}

}

[/cc]

The final new method in part 2 draws the rocks to the canvasBD. It's basic job is to loop through all of the rocks, set the rockPoint variable to be the location of the current rocks upper left-hand corner, and then BLIT the pixels of the rock to the canvasBD.

Finally, after the BLIT, it increases the frameCount for the rock. If the frameCount is greater than the frameDelay, it changes the animation index for the next game timer tick. It checks to make such it hasn't increased passed its upper bounds, and if it has, it sets the animationIndex to 0.

That's it, below is the new working example. Use the up arrow to apply the thrust, and the right and left arrows to simulate the rotation of the ship.

 

The source files are here: 7800 Asteroids Tutorial Part 2 source files

Read Part 3

20Jan/080

Tutorial: Using Flash CS3 and Actionscript 3 to create Atari 7800 Asteroids Part 1

In this series of tutorials, we will explore some optimization techniques to create a fully blitted Asteroids style game. Although the game we will create will be a relatively simple version of Asteroids, the techniques we will use to optimize it will be advanced. We will explore these optimization techniques:

1. Pre-calculating and storing rotation and thrust delta x and delta y values in an array (so they don't need to be calculated on the fly)
2. Pre-caching sprite rotation animations in an array of BitmapData objects
3. Using one display object to "blit" (bit block transfer) all graphic images to.

In part 1, we will tackle all three of these and get the player ship moving about the screen. In part 2, we will add in blitted asteroid rocks animations. In part 3, we will add blitted ship missiles. In part 4, we will add the bitmap collision detection  a simple particle emitter and a pool/farm of particles.

I am modeling some of my graphics for this game from the Atari 7800 version of Asteroids. I am doing this because I want to create a version that might be familiar to some people but also because I don't plan to license or sell this game. If you plan to use this as a base for a game that you will submit for license opportunities, then you must change all of the graphics.

Getting Started
Usually I would create a series of classes for a game like this, but to show an optimized game, and for space reasons, I will forego this. I am going to create the entire game in one class called Main. I don't plan to use any other classes for game objects.

Main will be the "document class" of my .fla file. In my library for part 1, I have 4 basic objects:

The background is a 400x400 vector image of a black sky and various stars. It has a linkage id of Background. I want a semi-complicated background to show how to blit game objects on top with transparency. This is not the most complicated image, but it has enough detail for a demonstration. The stars are made with the white circle clip called star.

The player ship is a 20x20 png I imported called flash0.png. I actually will rename this later. This ship png file has been placed inside ship movieClip a -10,-10. The clip has an linkage id of Ship. We have placed it at its center on on 0,0. That will be the point of rotation.

The stage for the game is 400x400 with a white background, running at 120FPS. The 120 is important because it will allow us to "pre-cache" our animations as fast as our plug-in version will allow. The document class will be called Main.

 

The Main class
The Main class will be stored in a file called Main.as. We will go over some specific parts of the class next in detail. Afterward, I will give the full text of the current version for part one and the .fla file for download.

[cc lang="javascript" width="550"]
package {

import flash.display.Bitmap;
import flash.display.MovieClip;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.display.BitmapData;
import flash.geom.*;
import flash.events.KeyboardEvent;

public class Main extends MovieClip {

var aRotation:Array=[];
var aShipAnimation:Array=[];
var shipAnimationArrayLength:int;
var ship:Ship;
var shipHolder:MovieClip;
var animationTimer:Timer;
var animationCounter:int;
var playerObject:Object;
var canvasBD:BitmapData;
var canvasBitmap:Bitmap;
var backgroundBD:BitmapData;
var backgroundSource:Background;
var gameTimer:Timer;
var backgroundRect:Rectangle;
var backgroundPoint:Point;
var playerRect:Rectangle;
var playerPoint:Point;
var aKeyPress:Array=[];
var spriteHeight:int=20;
var spriteWidth:int=20;

public function Main() {
trace("main");
createObjects();
createRotationArray();
createShipAnimation();
}

[/cc]

The Main() constructor initializes the game by creating objects, and caching values and Bitmaps needed for rotation and animation. There are quite a few imported classes and variables that need initializing. I will go into detail on their use in the following sections.

[cc lang="javascript" width="550"]
private function createObjects():void {
//create generic object for the player
playerObject=new Object();
playerObject.arrayIndex=0;
playerObject.x=200;
playerObject.y=200;
playerObject.dx=0;
playerObject.dy=0;
playerObject.movex=0;
playerObject.movey=0;
playerObject.acceleration=.3;
playerObject.maxVelocity=8;
playerObject.friction=.01;
playerObject.centerx=playerObject.x+spriteWidth;
playerObject.centery=playerObject.y+spriteHeight;
playerRect=new Rectangle(0,0,spriteWidth*2,spriteHeight*2);
playerPoint=new Point(playerObject.x,playerObject.y);

//init canvas and display bitmap for canvas
canvasBD=new BitmapData(400,400,false,0x000000);
canvasBitmap=new Bitmap(canvasBD);

//init background
backgroundSource=new Background();
backgroundBD=new BitmapData(400,400,false,0x000000);
backgroundBD.draw(backgroundSource,new Matrix());
backgroundRect=new Rectangle(0,0,400,400);
backgroundPoint=new Point(0,0);

}
[/cc]

The createObjects() method begins by using a generic object called playerObject to hold attributes for our player ship.
playerObject.arrayIndex=0;
This is the current index of animation for the player. We will store 36 individual BitmapData images an array and this will be the index of that array to use for display. We will also store a pre-calculated array of delta x and delta y values for thrusting and firing to each of these 36 angles. This index will be used in that array also.
playerObject.x=200;
playerObject.y=200;

We will start that player at 200,200 on the screen. These will store the players x and y values as he moves across the play screen.
playerObject.dx=0;
playerObject.dy=0;

These hold the current delta x and delta y values for the player associated with the direction he is floating on the screen. Since the player is not floating at the beginning of the game, these values are set to 0.
playerObject.movex=0;
playerObject.movey=0;

These hold the current speed and direction that the player is heading. This combines the current acceleration with current direction and speed of the player ship.
playerObject.acceleration=.3;
This is the number of pixels added to the player x and y values when the UP arrow is pressed.
playerObject.maxVelocity=8;
This will limit the maximum speed of the ship in any x or y direction.
playerObject.friction=.01;
Air friction is added each frame to the player ship so inertia will not have it float on forever with out more acceleration.
playerObject.centerx=playerObject.x+spriteWidth;
playerObject.centery=playerObject.y+spriteHeight;

We will keep a calculation of the center x and y of the player because the current x an y represent the top left corner of the ship Bitmap. We need the center value to make calculations easier.
playerRect=new Rectangle(0,0,spriteWidth*2,spriteHeight*2);
playerPoint=new Point(playerObject.x,playerObject.y);

The playerRect and playerPoint are used in blitting with copyPixels to our display canvas. We pre-create these so they don't need to be created each frame.

Next we create a canvas to blit all of our game objects to.
//init canvas and display bitmap for canvas
canvasBD=new BitmapData(400,400,false,0x000000);
canvasBitmap=new Bitmap(canvasBD);

The canvasBD is a non transparent BitmapData object that will hold the current display. canvasBitmap is the only display object in the game. It holds the canvas, which in turn holds the ship and the background blitted images.

Finally, we create our background image.

//init background backgroundSource=new Background();
backgroundBD=new BitmapData(400,400,false,0x000000);
backgroundBD.draw(backgroundSource,new Matrix());
backgroundRect=new Rectangle(0,0,400,400);
backgroundPoint=new Point(0,0);

The background is initialized by creating an instance of the Background object in the library. It is a 400x400 non-transparent vector MovieClip. Because the background is a vector in the library, it needs to be drawn onto the backgroundBD with the draw() method. The backgroundRect and backgroundPoint are pre-created and pre-calculated to save cycles when we blit this back to the canvasBd each frame.

[cc lang="javascript" width="550"]
private function createRotationArray():void {
shipAnimationArrayLength=36;
var rotation:int=0;
for (var ctr:int=0;ctr
var tempObject:Object={};
tempObject.dx=Math.cos(2.0*Math.PI*(rotation-90)/360.0);
tempObject.dy=Math.sin(2.0*Math.PI*(rotation-90)/360.0);
trace(ctr+":dx=" + Math.cos(2.0*Math.PI*(rotation-90)/360.0));
trace(ctr+":dy=" + Math.sin(2.0*Math.PI*(rotation-90)/360.0));
aRotation.push(tempObject);
rotation+=10;
}

trace("aRotation[5].dx=" + aRotation[5].dx);
}
[/cc]

The createRotationArray() method is used to pre-calculate the delta x and delta y value for rotation and movement at a specific angle. The 36 angles we will create correspond to the 360 degrees in a circle, taken in 10 degree increments. If you want more precise rotation animation, you can change the shipAnimationArrayLength to be a multiple of 36 (such as 180. If you do that, you will need to change the rotation+=10; to rotation+=2; (180*2=360). The product of the 2 much be equal to 360. The loop calculates to dx and dy values in radians and places them into a generic object and then pushes that generic object into the aRotation array;

[cc lang="javascript" width="550"]private function createShipAnimation():void {
shipHolder=new MovieClip();
shipHolder.x=50;
shipHolder.y=50;
ship=new Ship();
ship.x=spriteWidth;
ship.y=spriteHeight;
shipHolder.addChild(ship);
addChild(shipHolder);
animationCounter=0;
animationTimer=new Timer(1,36);
animationTimer.addEventListener(TimerEvent.TIMER, cacheShip);
animationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, animationTimerCompleteHandler);
animationTimer.start();
}

[/cc]

The createShipAnimation() sets up our timer based cache of the ship. The ship will start at rotation=0 and be moved 10 pixels each iteration until all 36 rotated images can be placed in an array of BitmapData objects. First we create a display object (in this case a MovieClip) to hold the Ship from our library. We do this because if we simply added the ship to the display list and tried to rotate it, Flash would not cache the rotations and we would get 36 BitmapData objects of the Ship pointed up (the original position). Also, a BitmapData object uses only the positive portion of the coordinate system. To rotate an object around its center, 1/2 of it needs be be in the negative x and y space. So, we placed the ship at -10,-10 in its MoveiClip, but we can't just cache that because even if the rotation worked, it would only cache 1/2 of our ship (the portion in the positive coordinate space). So, we place the ship in the shipHolder, and then rotate the ship inside the shipHolder to get a clean rotation.

We create a Ship object called ship and place it at spriteWidth, spriteHeight. Those have been preset to be 20,20. The reason we do this to to accommodate for the changes in width and height as the ship is rotated. To be safe, use double the ships actual height and width as the size of the BitmapData to cache. So, we put the ship at 20,20 in a 40x40 BitmapData object and it has the freedom rotate without clipping the corners.. The ship is added to the shipHolder display list and the shipHolder to the main timeline display list.

Next, we create an timer object and some events that will allow us to move through 36 ticks of animation as fast as the frame rate will allow. On each of the 36 ticks, we call the cacheShip method, and when all 36 are complete, we call the animationTimerCompleteHandler.

[cc lang="javascript" width="550"]private function cacheShip(e:TimerEvent):void {
var spriteMapBitmap:BitmapData=new BitmapData(spriteWidth*2,spriteHeight*2,true,0x00000000);
spriteMapBitmap.draw(shipHolder,new Matrix());
aShipAnimation.push(spriteMapBitmap);
trace("caching " + animationCounter);
animationCounter++;
ship.rotation+=10;
}

private function animationTimerCompleteHandler(e:TimerEvent):void {
startGame();
}

[/cc]

After all of the set up, the cacheShip method is relatively simple. On each of the 36 timer events (ticks), it creates a new Bitmapdata object called spriteMapBitmap that is 40x40 (or the spriteWidth * 2, spriteHeight *2) and is transparent. Next it takes the current contents of the shipHolder movie clip and calls the draw() method of the BitmapData class to place it inside the fresh spriteMapBitmap Bitmapdata object. Its last jobs are to push the new BitmapData object to the ship's array pf animation frames (aShipAnimation), and set the ship up for the next frame by increasing the rotation by 10 (ship.rotation+=10);

The animationTimer calls the animationTimerCompleteHandler when it has moved through all 36 timer ticks. We are now complete with part 1's animation caching, and will now move onto the beginning of our game loop. We will have more animation and Bitmap Caching to perform as we add the rocks, and missiles, and the simple particle explosions.

[cc lang="javascript" width="550"]
private function startGame():void {
removeChild(shipHolder);
addChild(canvasBitmap);

stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpListener);

gameTimer=new Timer(50);
gameTimer.addEventListener(TimerEvent.TIMER, runGame);
gameTimer.start();

}

private function runGame(e:TimerEvent) {
checkKeys();
updatePlayer();
drawBackground();
drawPlayer();
}
[/cc]

The startGame() method begins the actual game loop. The loop is a method called runGame and it is called every 50 milliseconds. This can be increased or decreased as needed. We do this with the new AS3 Timer class here, but I have also had success with using the EnterFrame event. We also add a listener for both keyboard up and down events, remove the shipHolder from the main time line, and add in our canvas. The canvas is just a 400x400 BitmapData holder that all of our BitmapData images will be drawn to. It is the ONLY display object in the game.

The runGame method is currently pretty basic. It runs through checking for changes in keyboard input, updating the player ship position based on any key changes, and inertia, then it draws our objects to the screen in the order desired. First we draw the space star background, and then we draw the player. Effectively this is akin to setting depths on them in AS2.

[cc lang="javascript" width="550"]
private function keyDownListener(e:KeyboardEvent) {
//trace("down e.keyCode=" + e.keyCode);
aKeyPress[e.keyCode]=true;

}

private function keyUpListener(e:KeyboardEvent) {
//trace("up e.keyCode=" + e.keyCode);
aKeyPress[e.keyCode]=false;
}

private function checkKeys():void {
if (aKeyPress[38]){
trace("up pressed");
playerObject.dx=aRotation[playerObject.arrayIndex].dx;
playerObject.dy=aRotation[playerObject.arrayIndex].dy;

var mxn:Number=playerObject.movex+playerObject.acceleration*(playerObject.dx);
var myn:Number=playerObject.movey+playerObject.acceleration*(playerObject.dy);

var currentSpeed:Number = Math.sqrt ((mxn*mxn) + (myn*myn));
if (currentSpeed < playerObject.maxVelocity) {
playerObject.movex=mxn;
playerObject.movey=myn;
} // end speed check

}
if (aKeyPress[37]){
playerObject.arrayIndex ;
if (playerObject.arrayIndex <0) playerObject.arrayIndex=shipAnimationArrayLength-1;

}
if (aKeyPress[39]){
playerObject.arrayIndex++;
if (playerObject.arrayIndex ==shipAnimationArrayLength) playerObject.arrayIndex=0;

}
}
[/cc]

To avoid the pause created when a key is held down (the old key.up and key.down global methods have been removed in AS3) we have created an array called aKeyPress that will act somewhat like those global methods. When a key is pressed ( the UP arrow keyCode= 38, the LEFT arrow keyCode= 37, and the RIGHT arrow keyCode= 39) we store a Boolean true in our array at that index. When the the key is not pressed anymore, we store a Boolean false in the index of the aKeyPress array.

The checkKeys() method is actually quite complicated because it contains most of our logic for the rotation and forward motion of the ship.

First, if the up arrow is being held down : if (aKeyPress[38]) : we need to check what the dx (delta x) and dy (delta y) values are for that direction. We already pre-calculated all of these and placed them in the aRotation array. The current index for the player, playerObject.arrayIndex holds a number 0 to 35 referring to the current rotated position of the playerObject. That same index is used in the aRotation array to find the .dx and .dy values that will be applied to the playerObject.movex and playerObject.movey variables. When the game starts, the playerObject.movex and playerObject.movey values are both set to 0, but as soon as the up arrow is pressed we start to calculate what the new movex and movey values will be. That is done with these two lines:

var mxn:Number=playerObject.movex+playerObject.acceleration*(playerObject.dx);
var myn:Number=playerObject.movey+playerObject.acceleration*(playerObject.dy);

We create two temp variables to hold our new movex and movey values called mxn and myn. To create the new value we add our acceleration value (.3) * the new dx value and add it to the current movex value. We also do this with myn, the dy and movey values. These now equal our new delta x and y values or the change in x and y that will be applied to our x and y values respectively when the ship is put on the screen this frame timer tick. But wait a minute, we have something called playerObject.maxVelocity which keeps out ship from accelerating so fast that we can't see it.

Our next step is to test the mxn and myn values against the max velocity. To get our current speed we must use a little math. This is because we have essentially two vectors in dx and dy and we must add them together and take their square root of their squares to find a number that is our current constant velocity. That is done here:

var currentSpeed:Number = Math.sqrt ((mxn*mxn) + (myn*myn));

Now, our currentSpeed is a value that we can compare to our playerObject.maxVelocity value, if it is less than our max, we assign the playerObject.movey and movex to the respective mxn and myn values. If it is not (the ship is moving at the max velocity), we do nothing and the movex and movey remain unchanged and our ship continues to move in its current direction at max velocity.

The last two key checks are for the left and right arrow keys. If the left arrow is pressed, we change the playerObject.arrayIndex by subtracting one from it. If it goes below zero, we set it to the 35 (array length of 36 - 1). If we press the right arrow key, we do the opposite and add 1 to the playerObject.arrayIndex. If it goes above 35, we set it to be 0. We don't change the playerObject.dx and dy values yet. If we did that, then the ship would start to move off in the direction we rotate too, and not continue its inertia in the current thrusted direction. We only change the playerObject.dx and dy, and the movex and movey when the up arrow is pressed. This gives us an approximation of the classic Asteroids movement. I have no idea how Ed Logg actually programmed Asteroids, so I have to assume this is relatively close.

[cc lang="javascript" width="550"]
private function updatePlayer():void {

//add friction

if (playerObject.movex > 0) {
playerObject.movex-=playerObject.friction;
}else if (playerObject.movex < 0) {
playerObject.movex+=playerObject.friction;
}

if (playerObject.movey > 0) {
playerObject.movey-=playerObject.friction;
}else if (playerObject.movey < 0) {
playerObject.movey+=playerObject.friction;
}

playerObject.x+=(playerObject.movex);
playerObject.y+=(playerObject.movey);

playerObject.centerx=playerObject.x+spriteWidth;
playerObject.centery=playerObject.y+spriteHeight;

if (playerObject.centerx > stage.width) {
playerObject.x=-spriteWidth;
playerObject.centerx=playerObject.x+spriteWidth;
}else if (playerObject.centerx < 0) {
playerObject.x=stage.width - spriteWidth;
playerObject.centerx=playerObject.x+spriteWidth;
}

if (playerObject.centery > stage.height) {
playerObject.y=-spriteHeight;
playerObject.centery=playerObject.y+spriteHeight;
}else if (playerObject.centery < 0) {
playerObject.y=stage.height-spriteHeight;
playerObject.centery=playerObject.y+spriteHeight;
}

trace("centerx=" + playerObject.centerx);
}
[/cc]

We are hitting the home stretch of part 1 now. The updatePlayer() method is called every interval in our game loop to make sure that the ship is placed on the screen at the correct location. That location changes most interval ticks because we simulate inertia and friction with this function. The first thing we do is add friction with the appropriate sign to each of the movex and movey values. We ADD the friction value to a negative value and SUBTRACT it from a positive value. We do this each frame, and eventually, if the up arrow if not pressed again, the ship will stop moving.

Next, we add the movex and movey values to the current x and y values for the playerObject. This simulates our inertia. The x and y values are changed every tick no matter if the up arrow is pressed or not. We also recalculate the centerx and centery values for the playerObject.We need these recalculated every time the x and y values change to ensure that we have a proper center of our object. This is used for warping from left to right and up and down, but also used in collision detection and explosion placement. We don't want to use the upper left-hand corner x and y values for these calculations.

Next we check the centerx value against the stage.width value. If the centerx is greater than stage.width, we place the ship at the other side of the screen at -spriteWidth. That gives the illusion that the ship is floating from the right side to the left side of the screen. We do the same with the x value and the left side of the screen by checking if the centerx is less than 0, and then changing the it to be the stage.width - the spriteWidth. We do this in the y direction by checking the centery values also.

[cc lang="javascript" width="550"]
private function drawBackground():void {
canvasBD.copyPixels(backgroundBD,backgroundRect, backgroundPoint);
}

private function drawPlayer():void {
playerPoint.x=playerObject.x;
playerPoint.y=playerObject.y;
canvasBD.copyPixels(aShipAnimation[playerObject.arrayIndex],playerRect, playerPoint);
}
[/cc]

We have made it to the last two methods in part one. Every frame tick, with the drawBackground() method, we need to redraw the background image, and this is done by using the copyPixels() method of the canvasBD BitmapData object We copy all of the pixels from the backgroundBD BitmapData object to the canvasBD by specifying the pre-calculated rectangle of 0,0,400,400 and always using the point 0,0.

The drawPlayer() method is slightly more complicated. We need to first set the playerPoint x and y values to equal the current playerObject x and y values. Once we have done that, we again call the copyPixels method of the canvasBD. This time we specify the current ship animation frame in the aShipAnimation array using the playerObject.arrayIndex value. Then we use the pre-calculated rectangle of 0,0,40,40 and the point calculated above.

If all of that code is correct, we get the below exported .swf file. Use the up arrow to apply the thrust, and the right and left arrows to simulate the rotation of the ship.

The source files are here: 7800 Asteroids Tutorial Part 1 source files

Read Part 2

17Jan/080

Moving From Flash AS2 To Flash AS3: MovieClip Buttons In MovieClip Classes

(Note: I'm converting my Flash game "Spin City" from AS2 to AS3 so it can be re-skinned for another project. I've decided to document this activity in a series of tutorials so they might benefit anyone else who is going through the same development process)

OK, this one drove me crazy today, but I finally discovered the answer. I try as hard as possible to keep all actions related to my Flash code in my classes and not place any code on the time line. this includes buttons and their related code for handling events. I got it to work in AS3, but I could not get the hand cursor to show-up when hovering over buttons. Here is what I found out.

Flash AS2

In AS2, handling button actions in a class that is associated with a MovieClip that contained that button (i.e. A TitleScreen class that includes a [PLAY] button) was done like this:

  1. Define a variable for the button in your class so you can set its properties. The name must be the same name as you named the button in your MovieClip. Even though you never define the variable, at run-time it will be associated with the button because they have the same name.
  2. Set the onRelease handler of the button to a function in your class
  3. Have the button handler call _parent[function] so that you can operate within the scope of your class (and not the button) (Note: You can eliminate this by using a delegate)
  4. Perform action
[cc lang="javascript" width="550"]
class TitleScreen extends MovieClip {
var button_play:MovieClip;

function TitleScreen() {
button_play.onRelease = play_button_release;
}

function play_button_release() {
_parent.playagainButtonRelease();
}
function playagainButtonRelease() {
//Do Play Action
}
}

[/cc]

AS2 considers the MovieClip defined by button_play as a "button" because we have assigned a call-back function to its onRelease handler. This means that when hovering over the button, the cursor will change to the "hand" that instantly informs the user that this is a button than can be pressed.

Flash AS3

In AS3, there are few more steps you have to take to simulate the same functionality. In some ways it is much simpler than AS2, and in some ways, a bit more involved. At any rate, it is different than AS2, and that is why I'm covering it in this blog. Here are the steps you need to perform to make it work:

Easier:

AS3 is easier for two reasons:

  1. The event handler you assign to your button is called in the context of where that function exists. This means you no longer have to call _parent[function] or use a delegate to get back into the context of your class.
  2. You do not have to define a MovieClip that exists in the MovieClip associated with your class as a variable in your class. These MovieClips are already defined for you.

However, there are a couple complications with AS3:

  1. There are no longer onRelease and onPress events to handle. You use MouseEvent.CLICK, MouseEvent.MOUSE_DOWN, MouseEvent.MOUSE_UP and MouseEvent.DOUBLE_CLICK (among others) for this purpose.
  2. You need to set the useHandCursor property to true so the cute little useful hand will show-up when the cursor hovers over the button.
  3. You need to set the buttonMode property to true so the MovieClip that defines the button will act like one (i.e. the useHandCursor property will actually have an effect)

Here is what the code looks like:

[cc lang="javascript" width="550"]
package fashiondash {
import flash.events.MouseEvent;
public class TitleScreen extends flash.display.MovieClip {
public function TitleScreen() {
button_play.addEventListener(MouseEvent.CLICK, playagainButtonRelease);
button_play.useHandCursor = true;
button_play.buttonMode = true;
}

function playagainButtonRelease(e:MouseEvent) {
//Do Play Action
}

}

}
[/cc]

 

So there goes another short lesson. I had no idea that little things I took for granted such as the hand cursor would pose problems like this in AS3. There certainly is a lot to re-learn with this generation of ActionScript.

 

Filed under: Tutorials No Comments
17Jan/080

Moving From Flash AS2 To Flash AS3: GetURL()

(Note: I'm converting my Flash game "Spin City" from AS2 to AS3 so it can be re-skinned for another project. I've decided to document this activity in a series of tutorials so they might benefit anyone else who is going through the same development process)

 

Flash AS2

One of the most basic functions in AS1 & AS2 was getURL() . The simple ability to send users to another page in the same browser window ( or a new instance of one) is also one of the very foundations of web functionality. AS1 and AS2 used a very simple implementation for it, and we were all happy because it was all so simple. The basic, global function call looked like this

[cc lang="javascript" width="550"]
getURL("catalog.aspx", "seetoys", "GET");
[/cc]

The three parameters were:

  • URL (where to go)
  • target (the name of browser to open the page into)
  • method (GET or POST)

That was it. Simple, easy, straightforward, nobody got hurt.

Flash AS3

In AS3 there is no global getURL() function, there is no easy, one line equivalent that you can replace it with. A simple getURL() style action takes a 4 lines of code (2 lines if you want to minimize your code, but make it unreadable). Here are the steps you need to take to simulate getURL()

  1. Everything required for URL actions is AS3 is contained in the flash.net package. So the first thing you need to do is import that package into your class.
  2. Second, you need to create an instance of a URLRequest object and set it's url property
  3. Third you must use the new navigateToURL() function is a close approximation to to getURL();

 

[cc lang="javascript" width="550"]
import flash.net.*;
...

var url:String = "catalog.aspx";
var req:URLRequest = new URLRequest(url);
navigateToURL(req, 'seetoys');
[/cc]

 

Of course, you could economize that code like this and make it one line (plus the import)

 

[cc lang="javascript" width="550"]
import flash.net.*;
...
navigateToURL(new URLRequest("catalog.aspx"), 'seetoys');
[/cc]

URLRequest is actually a very useful class, as it allows you to so things that were never possible in AS2, like set HTTP Headers for the request. Still, it's a bit disconcerting when something so simple and basic as getURL() needs to be updated along with everything else. However, that seems to be the norm with converting AS2 to AS3.

Filed under: Tutorials No Comments
16Jan/080

Moving From Flash AS2 To Flash AS3: Update

This is just a quick update to say that the Moving From Flash AS2 To Flash AS3 series will continue this week. I had to spend some time implementing the things I learned last week, and work on a few more changes. I've now tackled adding movie clips to the screen, events, MovieClip properties, replacement for getURL and a few other things that I will start blogs on tomorrow. Thanks for being patient.

-Steve

Filed under: Tutorials No Comments
14Jan/080

Trading Games The Easy Way : Goozex + Scotch Size 0, + APC

Goozex

If you are like me (and Lord help you if you are) you have been buying and playing video games for the past 25 years and have amassed quite a collection of , PC, PS1, PS2, GBA, DS, Wii, etc titles that you no longer play. In your personal phantasie (sic) world, you would be able to keep these games forever in the hopes that one day you will dust off an old console, load the old game, and enjoy it like the halcyon days when it was a significant part of your life. In this dream world you would pull out a game, show it to your friends, and either bask in the glow of it's significance to your life ("Hey, remember when we stayed up all night the day before we left for college and beat Duke Nuke'em on cooperative mode...I love you man") or share a sophisticated guffaw of ironic indifference over how lame the game seems in modern times ("Ho ho, Charles, do you recall the days when when words Wipeout XL meant something ?!?, By the way, have you seen my my monocle?"). Maybe you hold onto the games so you can share them with your kids when they are old enough, hoping to see that same spark in their eyes that you had when you first played them ("yes honey there are only 4 buttons, and you have to plug the controller into the console to make it work. Waving it in the air will not make Rayman do anything. Sorry"). Either way, you'd hate to miss those moments if they ever occur, and so you never get rid of any old games. They fill drawers, boxes, closets, space in the garage, and most significantly, are never played, ever, and probably never will be. Deep-down, you know you can't keep them forever.

At some point you may finally realize that you have simply run out of space. Your wife complains about them constantly, and you can no longer hide your game collection from the conservative parents of your kids' friends when they come to visit ("So Steve, what does that plastic guitar with the Kiss 'God Of Thunder' face-plate actually do again?"). Furthermore, the expenses of being an adult (mortgage, loans, kids's activities, memberships, etc.) have forced you to buy games only on rare occasions, or possible, not at all. You still want to play new and different games, it's just that reality has blunted your ability to actually acquire them. Some people would say: "Grow up, stop playing games, and face the world like a man!". I say, "yeah sure, do those things,but also start trading your video games away and have the best of both worlds!".

Let me explain. When I first decided that I had to get rid of my old games, I looked at both eBay and GameStop, as they seemed to be my only options. However, for a lazy programmer like myself, eBay is just too much of a hassle. Each listing has to be specially crafted, requiring prices to be set, and photos added, plus you need use PayPal, and then you actually have to mail the stuff out. It just seemed like too much work. GameStop on the other hand, is very easy. You just take your pile of games there, let them give you $1 each for them, realize you have not done the game industry any favors , come back the next day to see your games on the shelf for $14.99 each, and then feel raped. Plus, GameStop now does not trade in PSX games, so the wealth of unwanted games people have for that system would be useless.

There had to be another answer. I recalled a year or so back, someone mention Goozex over at gamerdad.com. At the time they were offering some kind of free-trade deal or something, but I did not pay too much attention. At that point I was not interested in trading games via mail with weird strangers. I had tried that once, with Atari ST games in 1990, and it was a disaster. The hardest part was finding someone who wanted games on your list, who also had games you wanted from their list. This proved nearly impossible. I finally settled with a 'professional' who would only settle for a lopsided trade. He gladly took my $500 worth of brilliant games and sent me $90.00 worth of crap. However, in 2007, with my options exhausted from known sources, I checked Goozex.com out and their offering looked fairly interesting.

First of all, you do not have to deal personally with any  traders at all. All you have to do is create a list of games you want to banish from your life ("My Library"), and list of games you want magically appear at your door ("My Requests"). Each game has a point value associated with it based on several factors. Newer games, and games that are in heavy demand have a higher point value (200-1000), older games, and games that are not in demand have a lower point value (100-150). When you add a game to your "My Library", it will be automatically matched with someone (if they exist) who has added it to their "My Requests" list. If a match happens, and you agree to send the game to matched person, you get the amount of points the game is worth added to your Goozex points. You can then use those points to request other games and have them sent to you. That is basically all there is to it. You receive the actual value of your games (in Goozex terms), but don't have to find an exact trader with which to swap them.

It all sounded very good, so I started the process of finding games that I wanted to trade. With a new interest and dedication to trying Goozex.com, I dug out my container of old games, started sifting through them. I picked up each old game, looked at its cover, turned it over read the back, looked at the pictures and asked myself "will I ever want to play this game again?" It was an honest question, and if any part of me whimpered even a slight "no", I put the game back in storage. I wanted no regrets. When I was finished I had a pile of about 40 games, including Final Fantasy VII, for the PSX worth a whopping 1000 points (the most I've seen) on Goozex.com. With most older games going for 100 points, I could conceivably score 10 games for one trade. Of course, this would defeat the purpose of getting rid of my dusty stores of ancient gaming memories, but the option was still there.

My next step was to enter the games into My Library on goozex.com. This a fairly simply task. You search for the game in their system, and then click the [Add To My Library] button to make it available for trade. To add a game to your requests, you do the same thing but click the [Add To My Requests] button. After that, you choose the "condition" of the game you have to trade (or want to receive). The options are "Disc Only", "Disc And Manual", "Full Package". They all trade for the same number of points, but it is usually faster to trade away games that are "Full Package" (the greedy masses tend to want everything) and to receive games that are "Disc Only" (the careless masses can't seem to take care of anything).

Almost immediately after I added the 40+ games to [My Library] I received 3 emails saying I had been matched with people who wanted: Final Fantasy VII PSX (1000 points), Vandal Hearts PSX (200 points), Activsion Classics PSX (100 points). Since I was a new member, 3 trades was my maximum at any one time. I returned to Goozex.com and accepted all three trades. I was given the option to promise to send the games "Within 1 Day" or "Within 3 Days" (as well as other options that would result in no trade at all).

goozex1or3days.jpg

I chose "within 3 days", since actually packaging and mailing things is not one of my favorite things to do. I was also given the option to print out a mailing label and package insert for the trade. This proved invaluable. Goozex.com says on their site that they have worked with the US Postal Service to develop this label, and I have no reason to doubt them.

goozexmailing.jpg

One of my greatest fears with snail mail is that I will spell the name of a city wrong, or miss digit in an address or zip code, and send a package into oblivion. By having Goozex create the label and insert for me, all I had to do was cut the page in two, and find a mailing envelope in which to stuff the insert, and to which I could tape the label. I did not have any mailers on hand, so I went to Target and looked in their "office" section for something suitable to send a PSX or PS2 game. After searching for a bit, I discovered that the Scotch (3M) Size "0" Bubble Mailer is the perfect size.

goozex_scotch.jpg

I bought a 10-pack ($6.49), plus some mailing tape ($1.49) and returned home to get the games ready to ship. With the mailing labels already printed, it only took about 5 minutes to prepare the 3 packages. I put the packages in my car and planned to go the post office the next day at lunch time. My plan was thwarted by work however, and I did not make it to the post office until just after the 6:00 PM closing time. I went in anyway, just to see if they might be open later for the holidays. They were not, but on my way out I spotted this machine:

Automated Postal Center

The "Automated Postal Center" is a machine that was introduced in 2007 by the US Postal Service to allow savvy consumers a way to "self service" their own mailing needs. This is not just a stamp machine, or mail box, but a nearly full service post office available 24 hours a day, 7 days a week. Among other things, it allows you weigh and buy postage and other services for packages all with your credit card. After an initial "learning curve", I was able to buy postage ($1.60-$2.50 each) and Delivery Confirmation ($.75 each and recommended by Goozex.com) for each package in about 8 minutes, and send them off forever.

After about a week, all three packages had arrived at their intended recipients, and my feedback score at Goozex.com was raised to the next level (5 trades at one time). I continued this trading process until I had amassed over 4000 points. In that time I noticed that not many people were using the APC at the post office. In fact, even on really busy days around Christmas, while there were long lines for the actual postal employees, the APC sat lonely and unused to the side like well... like myself at any Junior High dance I attended in the 80's. For someone like me with such an aversion to mailing things, it was a God-send. The APC might be the greatest invention the U.S. Postal Service has ever produced. It's certainly my favorite machine of any type currently in existence.

Anyway at that point, I decided it was my turn to start searching for games to add to [My Requests]. One thing you need to know about Goozex.com, is that while you can send trade away as many games as you like for "free" (besides the postal costs), you have to pay to receive games. This is how they make their money, and I have no problem with it. The cost is a flat $1.00 per trade, no matter how many points the game is worth, which is a wise decision on their part. You receive a free trade for signing-up, and can buy more at your leisure. Since I had promised my wife that I was trading away games "so I could get good, new ones in exchange that we could play with the kids", I added some Wii and GameCube games to my list, as well as some very hard to find GBA games. You need to be warned though, that as soon as you add games to your list, they go into the system and matches are made. If someone has the game available in your chosen condition, it could be instantaneous (depending on your place in in the queue of requests) and your points are debited.. Before I knew it Star Wars Rebel Strike (Game Cube), Legend Of Zelda Wind Waker (Game Cube), SSX Blur (Wii) and Harry Potter Order Of The Phoenix (Wii) were matched-up and sent out to me. All were games that I wanted to play, but never had the time to get to the store and buy. Now I would never have to make the effort.

I received all the games within a week, and all were in fine and playable condition. Since that time, I have traded about a dozen more games and received several others. It almost feels like an "embarrassment of riches" because I can request any game I like, and eventually it will be sent to me. It has also made me re-think some of those games that I initially rejected for trading, since they now offer an opportunity for new and fairly easy to acquire gaming experiences, and not just memories of old ones. Since I have so many old games that I don't play, I could probably use the system for years before I "cut to the bone" with games that I actually might want to keep. Even if you don't have old games to trade, the system can still be useful. You can buy Goozex points at a rate of 100 for $5.00 (with discounts for bulk purchases), and you can receive trade credits for referring friends (full disclosure: if you click any link to Goozex.com in this blog post an sign-up, I will get credit for it...thanks!).While there are costs associated with it (about $3.50 per game sent, and $1.00 per game received), the benefits appear to out weigh them for anyone interested in trading away old games but not comfortable with other, albeit inferior , trading options.

And there you have it. Goozex.com plus 3M/Scotch Size "0" Bubble Mailers, plus the U.S. Postal Service Automated Postal Center equal the perfect collection of technologies and products for people like myself (inert and unmotivated pack rats who hate to part with anything) to finally enter the world of online video game bartering.

Below is my Goozex.com Profile, just in case you you want to see what one looks like:

 

stevefulton

Visit www.goozex.com

Filed under: Game Reviews No Comments
14Jan/080

Flash Game Programming Inter-Web Round up

I like to search the inter-web for juicy nuggets of Flash Game programming wisdom in my free time (what a boring date I must be). Here are some essential new and recent blog entries for Flash Game Programmers and Developers.

Interactive Crap has a pretty recent entry called Common Problems in AS3 Game Programming #3 Swarm Behavior (Following).
I really like simple to understand AI articles and this is a great one.

Mochiland is chock full of great stuff. The most recent being:
5 Simple Tips to Optimizing Your Flash Games Site
ActionScript Physics Engine Tutorial: Lesson 1
ActionScript Physics Engine Tutorial: Lesson 2
Our very own Steve Fulton, wrote this first part in a series on making games. - Anatomy of a Flash Game: Lesson 1 - Setting up the game

http://www.zeuslabs.us has a nice collection of tips on how to learn AS3 in this article: 12 Great Ways to Learn ActionScript 3 in Flash

Gary Rosenzweig's latest (and greatest) Flash Game Programming book as spawned a web site where he helps budding game programmers with all sorts of problems and questions. His site, http://www.flahsgameu.com/ some great new stuff since the last time I visited. For those interested in his methods behind making the classic SNAKE game, he has provided a two part video tutorial:
FlashGameU.com Video Tutorial: Creating a Snake Game, Part 1
FlashGameU.com Video Tutorial: Creating a Snake Game, Part 2

Gary's

site is chock full of great tid bits. He also has another video tutorial on making a matching card pairs game. I really like it when someone spends the time making a full game and then creates a tutorial around it.

http://www.tutorialized.com is another AWESOME resource for game and Flash game Tutorials. Their latest include:
Making a Catapult Game
Making a Turret Game
Making a Maze Game

13Jan/080

Planet Source Code For Flash Game Development

Recently, I needed to find possible methods to create accurate movement for a maze-chase Pacman variant that I am working on (Pumpkin Man). I have been working on perfecting the method of animating my main character while he turns to an adjacent tile. It may sound simple at first thought, and in some cases it might actually be, but I seemed to have painted myself into a corner with some of the choices I made early on. The best way for a character in a Pacman style game to turn and move in a new direction is to wait until the character is in the exact middle of his current tile, and then rotate (or swap out the animation) to the new direction. I painted myself into a corner here because

1. I choose a tile size that that is an even number.
2. I chose to use all integers for my calculations. This helps speed up Bitmap display operations.
3. My character moves more than one pixel at a time.

Why did all three of these paint me in a corner? Well, given the first one, I don't actually have a center of the tile. I could say that the center is 15 (0 based) or is it 16? 32 / 2 = 16, but since it is divisible by 2, both 15 and 16 are the center. I am using integers, so 15.5 is the 1 based center and 14.5 is the 0 based center. Any how, I can just choose to use 16, and so I did, even though it is not the exact center of the tile. Since my character moves at a rate of 3 pixels every frame, I can never be certain that he will ever actually hit the center (16) of a tile. Because of this I decided to use the speed of my character as a offset from the center. So as long as the character is with in 16+/- 3 (13-19), he is considered in the center of tile. Since Pacman is always in the middle of any passage way, no matter where the character turns from, even if it is not the exact center (in this base by foo foo center of 16), I must make sure he is in the center 16x 16y of the tile he is turing into. So, he is placed there on the next frame. This works most of the time, but occasionally, it looks strange.

Anyway, how does this relate to Planet-source-code.com? I have used the site before for .asp and some Java work, and even looked at Asteroids and Galaxian C++ code from there a while back, but for some reason, I forgot to use it with Pumpkin man. Low and behold, I found a couple decent Pacman games in C# and C++ to check out.

I don't have the results yet, as I don't have the right version of Visual Studio to compile either game, but I plan to install it later tonight (MSDN is a life saver sometimes).

Anyway, I just wanted anyone who is stuck on a game to check out Planet-source-code.com

It might be just the place to find what you are looking for. Even though they don't have any Actionscript code, I find that C# and Java games are pretty close and as long as I can compile them, I usually get some good ideas if I need them.

This site is protected by Comment SPAM Wiper.