Tuesday, August 23, 2005

From my recent experiments with frame rate on browsers, I found that the so-called magic frame rate of 31fps doesn't actually work for me (maybe at one point it did). On my machine, if I publish my movie at 30fps, I get about 22fps on IE. Publishing it at 40, I get about 32. Beyond 40, the frame rate actually goes down. So make sure to check your actual browser's fps. They don't behave the same way as a Flash player (or in test movie) would. It certainly doesn't make sense to publish your movie at 60fps and hope the browser would push the fps toward that rate.

Sometimes when you code collision detection in your game, you need the bounding box of your movieclip to be of different size or shape than the bound of the movieclip itself. One quick way to do this is to create a new layer in your mc, say hitarea or whatever you like. Insert a clip (call it mcHitArea) in that layer, resize it to your liking. Within mcHitArea, put this code in the first frame of your actionscript layer:

this._parent.hitarea = this;
this._visible = false;

There is no need to name the mcHitArea instance, because you will be using the MovieClip.hitArea property to get to it.

if (mc.hitArea.hitTest(obj))
{
...
}

Sunday, August 21, 2005

Some people do their frame rate meter like this (at least I did when I first did it):

this.frames = 0;
this.startTime = getTimer();
this.onEnterFrame = function() {
this.frames++;
var now = getTimer();
var timeElapsed = (now-this.startTime)*0.001;
// find fps and truncate results to 2 decimal
places;
var fps = Math.round(100*this.frames/timeElapsed)*0.01;
txtFPS.text = "fps: "+fps;
};
stop();

Can you see any problem with the code?

The problem with the code is that it's getting the frame rate via the # of frames since the app starts divided by the time that has elapsed SINCE the app starts. The problem with this approach is that you are only getting average fps, not the current fps. So if your app has run for a few hours with a good frame rate, and suddenly the frame rate drops for a few seconds, you won't see it because the sudden drop in frame rate is "diluted" by the huge time elapse.

What you need to do instead is to find out the frame counts in the last sec elapsed.

this.frames = 0;
this.startTime = getTimer();
this.onEnterFrame = function()
{
this.frames++;
var now = getTimer();
var timeElapsed = (now - this.startTime) * 0.001;
if (timeElapsed >= 1.0)
{
var fps = Math.round(this.frames / timeElapsed);
txtFPS.text = "fps: " + fps;
this.startTime = getTimer();
this.frames = 0;
}
}

Saturday, August 20, 2005

Wow...
http://members.shaw.ca/flashprogramming/wisASLibrary/wis/doc/index.html

Neoswiff seems like a darn nice product for creating client side program using as2: http://www.globfx.com/products/neoswiff/samples.php

Wednesday, August 10, 2005

From my experiments with checking the progress of loadMovie, the most reliable progress check is as follows:

Assuming you have set up an onEnter
var prevBytesLoaded:Number = undefined;
// setup onEnterFrameBeacon
mx.transitions.OnEnterFrameBeacon.init();
target.loadMovie(url);
MovieClip["addListener"](this);

// check progress
function onEnterFrame()
{
var bytesLoaded = Math.round(_target.getBytesLoaded());
var bytesTotal = Math.round(_target.getBytesTotal());
if (bytesLoaded > 0 && bytesLoaded >= bytesTotal)
{
// Checking to make sure the bytesLoaded is the same as the one reported in
// previous frame is the most reliable way in getting an accurate value of bytesLoaded
if (bytesLoaded != prevBytesLoaded)
{
trace(bytesLoaded + ", " + bytesTotal);
prevBytesLoaded = bytesLoaded;
}
else
{
MovieClip["removeListener"](this);
}
}
}

Saturday, August 06, 2005

Dynamically constructing class in AS2.0

When would you want to dynamically create a class? You want to do it when you aren't sure at compile-time what class you want to instantiate. For example, different levels of your games might have different types of characters, and you want the ability to read in an XML file that specifies what character class you should instantiate.

For example, in level 1, you may want to do this:

var hero = new Dragoon();

level 2, you want to do this:

var hero = new Zealot();

Wouldn't it be nice if this is determined at run-time (e.g. via XML)?

You can dynamically create a class (and instantiate an object off of it) using one of these syntax:

function dynclass(o):Object
{
var ctor:Function = o.class;
return new ctor();
}

e.g.

levelInfo = [ { name: level1, class: hero.dragoon }, { name: level2, class: hero.zealot } ];
var obj = dynclass(levelInfo[currentlevel].class);

The only caveat to this approach is that all the level info is hardcoded in your code. If you need the flexibility of being able to specify all these in an XML file or from a database feed, if you need a way to instantiate a class based on string.

function dynclass(classname:String)
{
var ctor:Function = eval(classname);
return new ctor();
}

e.g. var obj = dynclass("classpath.myclass");

The second approach is definitely more flexible because it allows you to pass in a string, which means the user can literally type in the class name in a textbox to create something.

The only caveat with the second approach is that you must make sure your swf compiles the class code into it by including a reference of the class somewhere in your timeline, like so:

classpath.myclass;

EventDispatcher, BroadcasterMX, OnEnterFrameBeacon, TransitionManager and Tween are some of the most useful classes that came bundled with Flash MX 2004. If nothing else, just reading the code can teach you a lot of coding techniques in AS2.

If you want to add event dispatching functionality to your app, and you want the client to have the ability to listen on a specific message you are dispatching, use the mx.event.EventDispatcher class. If you are interested in adding the ability to broadcast all messages to registered listeners, use mx.transitions.BroadcasterMX.

If you want your class to receive onEnterFrame, use mx.transitions.OnEnterFrameBeacon.

You can add these the broadcasting capabilities to your class like this:

class MyClass
{
static var _initBroadcaster = BroadcasterMX.initialize(MyClass.prototype, true);

// add function references so Broadcaster can decorate your class later
// by assiging the actual functions to these function references
public var addListener:Function;
public var removeListener:Function;
public var broadcastMessage:Function;

...
}

Thursday, August 04, 2005

Interesting findings!

If you have an init function in your child class that you call from your constructor, and you have another init function in your superclass that your superclass's constructor calls, calling init() in your superclass actually calls the child class init!

Also, when trying to do this:

var f:Function = eval(func);

Make sure func is a simple string. When I try to extract it from an array of object: eval(config[i].func), it won't work!

Wednesday, August 03, 2005

Cool sites:

http://www.ultrashock.com/
http://www.emllabs.com/

Tuesday, August 02, 2005

The Flash Math Creativity published by FriendsOfEd has a lot of neat procedurally created arts, but the authors often time did a very poor job at explaining the code, especially the equations used.

Here is one example by David Hirmes on Spring: http://www.friendsofed.com/fmc/davidhirmes/index.html#

Most of the math code for movement are usually simplified version of physics, if you take the time to understand it, you will realize they are in fact very easy to understand and derive. Often times it's the code the obscures the simplicity of things (bad coding that is).

onClipEvent (load) {
xHome = _x;
yHome = _y;
zHome = 100;
springiness = .2;
decay = .8;
}
onClipEvent (enterFrame) {
y = ((yHome-_y)*springiness)+(y*decay);
_y += y;
x = ((xHome-_x)*springiness)+(x*decay);
_x += x;
z = ((zHome-_xscale)*springiness)+(z*decay);
_xscale += z;
_yscale += z;
_alpha = z+100;
}
onClipEvent (keyDown) {
_x = random(550)-225;
_y = random(400)-200;
z = random(200)-100;
}
onClipEvent (mouseDown) {
_x = random(550)-225;
_y = random(400)-200;
z = random(200)-100;
}

The only code that might be confusing to you are these: (and if you are not confused, you should be reading something else now)
y = ((yHome-_y)*springiness)+(y*decay);
_y += y;
x = ((xHome-_x)*springiness)+(x*decay);
_x += x;
z = ((zHome-_xscale)*springiness)+(z*decay);

What is it trying to do here? the equation for x and y are pretty much the same. They both represent the x and y component of the velocity. A velocity is a vector that has a direction and a magnitude (the speed). It basically tells us how fast something moves in a particular direction (signifies by x, y)

In the code above, _y is the new position has been assigned to your movieclip when you mousedown, yHome is the position (the target position). yHome - _y forms a vector (if you remember your vector math), which is basically gives the direction for the movieclip to move toward and how fast it should move -- the further away it is from the dest, the faster it moves. It's then scaled down by a factor called the springiness. The springiness component is what will cause an overshoot. If springiness is 1, then you will get an oscillation around the yHome location.
And you should remember form your highschool physics that v = u + at, meaning velocity at time t equals the sum of the initial velocity and the acceleration (assuming constant) over a period of time t. So in the above equation, you see v = at, but where is the time t? The time t is inherent in the equation because this code is being executed every frame. Assuming your movie always plays at 10fps, then the time t is 1/10 = 0.1 msec. In other words the movement code is frame dependent.

What about the second component y*decay? That's to make sure the velocity will get slower and slower as time goes by a factor of "decay". If you don't have this component, things will continue to oscillate between the destination point and never slow down.

Once you figure out the velocity, it's then time to add it to the current location _y, this corresponds to your highschool physics equation: s(t) = ut (where u is the average velocity)

y = ((yHome-_y)*springiness)+(y*decay);
_y += y;

The above code might be easier to understand if written like this:

vy = (ynew - _y) * factor; // gets the current velocity, slow it down by a certain factor since it's executing every 100msec
_y += vy; // gets the new location
vy *= decay; // reduces vy as time goes