APE: ActionScript Physics Engine
Here’s a game built with the AS3 ActionScript Physics Engine. It’s easy to create a simple a car physics game with APE. Here’s my go at it: Kinetic Car Park. Make the car fly through the air and land in the parking space. Click the game to give it focus, then use the left/right arrow keys on your keyboard to control the game. It’s possible to put the car on every ramp in the game. Not too hard really.
This is a very rough go at a game so no scoring etc. at this point. You can download the source AS3 & Fla files here. You’ll also need the ActionScript Physics Engine. This little demo was created with APE v0.45.
Here’s the document class:
package
{
import org.cove.ape.*;
import flash.display.Sprite;
import flash.events.Event;
import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
public class APEcar extends Sprite
{
private var wheel1:WheelParticle = new WheelParticle(460,20,10,false,100,0.05);
private var wheel2:WheelParticle = new WheelParticle(500,20,10,false,100,0.05);
public function APEcar()
{
addEventListener(Event.ENTER_FRAME, run);
APEngine.init(1/4);
APEngine.container = this;
APEngine.addMasslessForce(new Vector(0,2));
var defaultGroup:Group = new Group();
defaultGroup.collideInternal = true;
defaultGroup.addParticle(wheel1);
defaultGroup.addParticle(wheel2);
var leftWall:RectangleParticle = new RectangleParticle(5,0,990,10,4.712389,true);
defaultGroup.addParticle(leftWall);
var rightWall:RectangleParticle = new RectangleParticle(695,0,990,10,4.712389,true);
defaultGroup.addParticle(rightWall);
// Left //
var planeLeft1:RectangleParticle = new RectangleParticle (10, 140, 200, 10, -0.2, true);
defaultGroup.addParticle(planeLeft1);
var planeLeft2:RectangleParticle = new RectangleParticle(10,200,200,10,-0.1,true);
defaultGroup.addParticle(planeLeft2);
var planeLeft3:RectangleParticle = new RectangleParticle(10,300,300,10,0.2,true);
defaultGroup.addParticle(planeLeft3);
// Center //
var planeCenter1:RectangleParticle = new RectangleParticle(420,245,200,10,0.1,true);
defaultGroup.addParticle(planeCenter1);
var planeCenter2:RectangleParticle = new RectangleParticle(503,240,50,10,-0.6,true);
defaultGroup.addParticle(planeCenter2);
var planeCenter4:RectangleParticle = new RectangleParticle(440,350,180,10,0.1,true);
defaultGroup.addParticle(planeCenter4);
var planeCenter5:RectangleParticle = new RectangleParticle(240,490,200,10,-0.4,true);
defaultGroup.addParticle(planeCenter5);
var planeCenter6:RectangleParticle = new RectangleParticle(380,483,80,10,0.6,true);
defaultGroup.addParticle(planeCenter6);
var planeCenter3:RectangleParticle = new RectangleParticle(340,330,50,10,0.7,true);
defaultGroup.addParticle(planeCenter3);
// Right //
var planeRight1:RectangleParticle = new RectangleParticle(670,160,70,10,0,true);
defaultGroup.addParticle(planeRight1);
var planeRight2:RectangleParticle = new RectangleParticle(620,360,70,10, 0.1,true);
defaultGroup.addParticle(planeRight2);
var planeRight4:RectangleParticle = new RectangleParticle(570,380,40,10, -0.8,true);
defaultGroup.addParticle(planeRight4);
var planeRight3:RectangleParticle = new RectangleParticle(560,390,260,10, -0.3,true);
defaultGroup.addParticle(planeRight3);
var speedBump:RectangleParticle = new RectangleParticle(670,156,4,10,0,true);
defaultGroup.addParticle(speedBump);
var floor:RectangleParticle = new RectangleParticle(300,500,1000,10,0,true);
defaultGroup.addParticle(floor);
// put the car together: 2 wheel particles joined by a spring constraint: //
var car:SpringConstraint = new SpringConstraint(wheel1, wheel2, 0.3, true, 3);
defaultGroup.addConstraint(car);
APEngine.addGroup(defaultGroup);
stage.addEventListener(KeyboardEvent.KEY_DOWN, key_pressed);
stage.addEventListener(KeyboardEvent.KEY_UP, key_released);
}
function key_pressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.RIGHT)
{
wheel1.angularVelocity = 0.3;
wheel2.angularVelocity = 0.3;
}
if (event.keyCode == Keyboard.LEFT)
{
wheel1.angularVelocity = -0.3;
wheel2.angularVelocity = -0.3;
}
}
function key_released(event:KeyboardEvent):void
{
wheel1.angularVelocity = 0;
wheel2.angularVelocity = 0;
}
private function run(evt:Event):void
{
APEngine.step();
APEngine.paint();
}
}
}
AS3 Model View Controller Slide Show
Here’s a Flash MVC slideshow in ActionScript 3. My goal here was to keep the code clean while adding the features the customer wanted: unobtrusive controls, drop shadows, optional info text, and smooth cross-fades between images. The MVC pattern makes keeping the code organized easy while TweenLite makes all the transitions super easy to manage.
See it in action at poseygirlflowers. Or download the source Flash files.
I’ve posted some of the code below. There are several additional classes you’ll need + the .Fla in the .zip archive.
SlideModel.as
package slideshow
{
import flash.events.Event;
public class SlideshowModel extends Model
{
public var images:XMLList;
public var currentImage:XML;
public var currentTitle:String;
public var currentFile:String;
public function SlideshowModel()
{
}
override protected function updateData():void
{
currentImage = images[currentIndex];
totalItems = images.length();
currentTitle = currentImage.title;
currentFile = currentImage.file;
}
override protected function dataLoaded(event:Event):void
{
data = new XML(loader.data);
images = data.image;
setCurrentIndex(currentIndex);
}
}
}
SlideView.as
package slideshow
{
import flash.display.*;
import flash.events.Event;
import flash.net.URLRequest;
import flash.filters.DropShadowFilter;
import gs.TweenLite;
// only need this for debug:
import flash.text.*;
public class SlideshowView extends View
{
private var loader:Loader;
private var bmp:Bitmap;
public var container:Sprite;
public var buttonsMc:MovieClip;
// store a reference to the _controller:
private var _controller:SlideshowController;
private var stageWidth:Number = 580;
private var stageHeight:Number = 520;
// we will only allow the user to getNext/Prev image if we
// are not currentlyanimating a transition between 2 images:
private var isAnimating:Boolean;
private var baseURL:String = "http://www.stevenloe.com/projects/flash/mvc-slideshow/";
public function SlideshowView(c:Sprite)
{
container = c;
container.buttonMode = true;
bmp = new Bitmap();
loader = new Loader();
container.addChild(bmp);
container.addChild(loader);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
}
override public function update(event:Event = null):void
{
if(loader.width > 0)
{
container.addChild(bmp);
bmp.alpha = 1;
bmp.x = loader.x;
bmp.y = loader.y;
bmp.bitmapData = new BitmapData(loader.content.width, loader.content.height);
bmp.bitmapData.draw(loader);
}
trace("IMAGE URL : " + baseURL + model.currentFile );
loader.load(new URLRequest(baseURL + model.currentFile));
//display the file name of the image being requested:
//buttonsMc.debug_txt.text = "\nLoad:: File: " + model.currentFile + " " + model.currentIndex;
}
private function imageLoaded(event:Event):void
{
var myDropShadowFilter = new DropShadowFilter (12,45,0x000000,0.5,10,10,1,2,false,false,false);
container.filters = [myDropShadowFilter];
container.addChild(loader);
loader.x = (stageWidth / 2) - (loader.width / 2);
loader.y = (stageHeight / 2) - (loader.height / 2) -30;
loader.alpha = 0;
TweenLite.to(loader,0.7,{alpha:1,onStart:onTweenStart, onComplete:onTweenComplete});
TweenLite.to(bmp, 0.7, {alpha:0});
_controller.startTimer();
//display request success:
//buttonsMc.debug_txt.text += "\nLoaded!:: Index: " + model.currentIndex;
}
public function getIsAnimating():Boolean
{
return isAnimating;
}
// set a flag that will allow us to ignore user input while
// an animation is in progress
private function onTweenStart():void
{
isAnimating = true;
}
private function onTweenComplete():void
{
isAnimating = false;
}
// show/hide the play & pause buttons to reflect the action currently avalible to the user:
// the two buttons are stacked on the stage
public function showButton(b:String):void
{
if(b == "play")
{
buttonsMc.play_btn.visible = true;
buttonsMc.pause_btn.visible = false;
}
else
{
buttonsMc.play_btn.visible = false;
buttonsMc.pause_btn.visible = true;
}
}
// pass in a reference to the controller so that it can call getIsAnimating:
public function setControllerReference(c:SlideshowController):void
{
_controller = c;
}
// pass in a reference to the MC that contains our buttons on stage
public function setButtonsReference(b:MovieClip):void
{
buttonsMc = b;
}
}
}
SlideController.as
package slideshow
{
import flash.display.DisplayObject;
import flash.events.*;
import flash.utils.Timer;
public class SlideshowController extends Controller
{
private var autoPlayEnabled:Boolean = true;
// set time to display each image here:
private var autoPlayTimer = new Timer(7000, 1);
// store a reference to the view:
private var _slideView:SlideshowView;
public function SlideshowController(m:Model)
{
super(m);
autoPlayTimer.addEventListener(TimerEvent.TIMER_COMPLETE, nextItem);
}
public function addNextButton(btn:DisplayObject):void
{
btn.addEventListener(MouseEvent.CLICK, nextItem);
btn.addEventListener(MouseEvent.CLICK, continueShow);
}
public function addPrevButton(btn:DisplayObject):void
{
btn.addEventListener(MouseEvent.CLICK, prevItem);
btn.addEventListener(MouseEvent.CLICK, continueShow);
}
public function addPlayBtn(btn:DisplayObject):void
{
btn.addEventListener(MouseEvent.CLICK, play);
}
public function addPauseBtn(btn:DisplayObject):void
{
btn.addEventListener(MouseEvent.CLICK, pause);
}
// ----- begin slideshow control functions -----
override public function nextItem(event:Event = null):void
{
if(!_slideView.getIsAnimating())
{
model.setCurrentIndex(model.currentIndex +1);
}
}
override public function prevItem(event:Event = null):void
{
if(!_slideView.getIsAnimating())
{
model.setCurrentIndex(model.currentIndex -1);
}
}
private function play(event:Event):void
{
if(!_slideView.getIsAnimating())
{
trace("play");
nextItem();
autoPlayTimer.start();
autoPlayEnabled = true;
_slideView.showButton("pause");
}
}
private function pause(event:Event):void
{
if(!_slideView.getIsAnimating())
{
trace("pause");
autoPlayTimer.stop();
autoPlayEnabled = false;
_slideView.showButton("play");
}
}
// when the user presses Next/Prev we want to reset the timer and start a new timer running
private function continueShow(event:Event):void
{
if(!_slideView.getIsAnimating())
{
trace("pause");
autoPlayTimer.reset();
autoPlayTimer.start();
autoPlayEnabled = true;
_slideView.showButton("pause");
}
}
public function startTimer():void
{
trace("start timer");
if(autoPlayEnabled)
{
autoPlayTimer.start();
trace("START");
}
}
public function setViewReference(v:SlideshowView):void
{
_slideView = v;
}
}
}
MAXpower USB WiFi Stick on OSX
I recently broke my “don’t buy old Macs” rule. I picked up a Power Mac G4 “Quicksilver” Dual 800 on craigslist for $130 for the system, complete with keyboard, mouse, and monitor. Ordinarily I wouldn’t go vintage mac like this, but this machine will be for the neighbor kids to play with when they are over here visiting. They enjoy playing Flash games, and it will I hope (please!!) keep them away from my precious Macbook Pro.
All’s well with this old mac. It’s surprisingly peppy given its minimal memory and dual G4s. Or so it seems ’till I launch Flash Player 10 for the first time and try to play an arcade-style game. Hmmm, maybe this wasn’t such a great idea…
Anyway, the Power Mac desperately needs 802.11g wifi. I googled around and didn’t see much by way of mainstream Mac USB wifi solutions that are 802.11g and low cost. Then I discovered the Newer Technologies MaxPower 802.11g/b USB wireless stick, and decided to give it a shot. I found this one over at Other World Computing at a pretty fair price.
Features and specs:
- It offers 802.11g and b and various flavors of security: 64/128/152 bit WEP, WPA, WPA2, WPA-PSK/WPA-PSK2
- Operating Channels: 1 thru 11
- It’s a little longer than your average USB thumb drive at 3.5″ in length
Box Contents:
- USB WiFi Stick
- Driver CD with OSX 10.3, 10.4 and 10.5 drivers (also includes Windows & linux drivers –which I did not test)
- Instruction booklet

What's in the box
Simple OSX WiFi Setup:
- Load the CD, install the driver for the version of mac OSX you’re running
- Reboot
- Open System Preferences and choose “Network”
- Click “OK” in the “Detected a new network port” dialog box
- Click “Apply” and close system preferences
- Plug the USB WiFi stick into a USB port, and the Wireless Utility application launches
- Click on the name of the Wifi network you want to use, click “Add Profile”, enter your WEP/WPA password
- Click “Activate”
- Start surfing the internet
The install process was that simple.

Network Utility displaying the site survey
Hardware:
The unit is built like a standard memory stick. It feels sturdy and has a tiny LED that flashes to indicate data is being transmitted.
Software:
3rd party devices like this live or die based on the quality of their drivers and end user software. I’m happy to report that Newer seems to have done a good job here. The install went very smoothly. The Wireless Utility is easy to understand and use. When you start your mac, the Wireless Utility launches, and connects to your network. The connection is reliable and as fast as I can hope for given that I’m doing this all through old school USB 1.1.
Minor niggles: Every time you boot up your mac, the Wireless Utility pops up front and center and shows you that it has connected to the network. Not a very Mac-like user experience. Bugs: I did experience one instance where I booted up the mac and the Wireless Utility had forgotten my network’s WEP.
Performance:
I did a quick speed test using www.speakeasy.net. Results are equivalent to the speed I see using my Macbook Pro when It’s plugged into the cable modem powered ethernet here (~4.4 Mbps down, ~350 Kbps up). Web surfing is still noticeably slower than on my Macbook Pro. However, I currently have the wifi stick plugged into the stock USB 1.1 port on my Power Mac. Newer Technology warns that throughput will be slower using a 1.1 port. Next upgrade: an inexpensive USB 2.0 card. Either that or a shiny new Mac Mini!
Conclusion:
Overall, I’m very happy with the performance, ease of set-up and cost.
Test System:
Power Mac G4 Dual 800 Running OSX 10.4.11. Wireless base station: Apple Airport Express, version 6.3.