I am playing around with ActionScript 3 and trying to build a very simple prototype for a video game (top-down action/shooter) and realized that handling bullets is a little bit more challenging than I originally imagined.
In order to get a fairly decent “flight” of the bullet between the character and the target, I ended up using a highly modified version of Bresenham’s Line Algorithm to determine the flight path of the bullet and then merely draw a tiny flash.geom.Rectangle object at the appropriate place on that “flight path” during the draw-frame stage of my application.
I haven’t noticed any real problems, but I just can’t imagine this being the best way to handle bullets in a Flash game. I imagine that once there are multiple enemy players on the screen and lots of bullets flying around (especially once I code in automatic weapons) that things could come grinding to a halt.
What am I missing here? I’m not really a game developer and so most of the things I’m doing I’ve just “made up” on the spot, but I can’t figure out how to effectively handle bullets in Flash.
EDIT: As requested, here is “my” Bresenham code. I say “my” in quotes, because I basically ripped this from somewhere on the internet. My changes to the algorithm basically involve the lines at the bottom. The original implementation would find the path from player character to the target, except that every once in a while (and I wasted a little bit of time trying to figure this out but never got anywhere) it will generate the path from the target to the player. To “fix” this, I ended up just checking the first X/Y values from the path array and reversing the array if those values didn’t match the X/Y values of my player character.
public function bresenham(fromX:int, fromY:int, toX:int, toY:int, value:int):Array
{
// store the character's location
var orig_x:int = fromX;
var orig_y:int = fromY;
var error:int;
var bullet_path:Array = new Array;
var dx:int = toX - fromX;
var dy:int = toY - fromY;
var yi:int = 1;
if ( dx < dy ) {
// swap end points
fromX ^= toX; toX ^= fromX; fromX ^= toX;
fromY ^= toY; toY ^= fromY; fromY ^= toY;
}
if ( dx < 0 ) {
dx = -dx;
yi = -yi;
}
if ( dy < 0 ) {
dy = -dy;
yi = -yi;
}
if ( dy > dx ) {
error = -( dy >> 1 );
for ( ; toY < fromY; toY++ ) {
bullet_path.push( { 'x' : toX, 'y': toY } );
error += dx;
if ( error > 0 ) {
toX += yi;
error -= dy;
}
}
} else {
error = -(dx >> 1);
for ( ; fromX < toX; fromX++ ) {
bullet_path.push( { 'x' : fromX, 'y': fromY } );
error += dy;
if ( error > 0 ) {
fromY += yi;
error -= dx;
}
}
}
// reverse the bullet path if it was generated from target to player.
if ( bullet_path[0].x != orig_x && bullet_path[0].y != orig_y ) {
return bullet_path.reverse();
}
return bullet_path;
}
Can you post your implementation (of Bresenham’s) code here? I would like to make a benchmark test if my implementation is faster :D…
Weird thing – I DID do a benchmark comparing my implementation with AS3.0’s native Graphics.drawLine()… It was LITERALLY 5 to 10 times faster. It is even anti-aliased, but I guess nativity here does the thing.
But anyway – as long as the bullets… Let’s say MISSILES (bullets, rockets, lasers…) here aren’t anything slowly moving, big which is supposed to look good too (not just line), use MovieClip, or even better Sprite when no animation is needed. Everywhere else use Graphics.drawLine().
Also, for hit-testing with the lines, and finding the points to draw the lines to (not Sprites), you would have a range of that bullet (if infinite, use something like Stage.width, or Stage.height if it’s bigger), where it can still hit. Then you would also have its angle. If it is along X or Y axes, it is fairly easy to get the points of the line. For the different ones, use Point.polar(range, angle) [liveDocs], to which you add the original position of that bullet.
Hit-testing would be done with Point.interpolate() [liveDocs]. Point 1 would be the original position / start point, the second would be the point that you got from Point.polar(). Finally, the last param must be the distance from start (no need for Math.atan2() here – just increment this value each frame by the bullet’s speed) divided by the distance between start and end points (again, no Math.atan2() – just the “range”. This Point.interpolate() would give you a point, that you will finally use with each possible target for the bullet (either loop through all, or, for performance, check if the X and Y distances are smaller or equal to their width and height) – target.hitTestPoint(interX, interY, true) [liveDocs].