What is the best way to program the path of a bullet?
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 p开发者_开发百科oints
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].
Before you try to find a faster method, see if your code is a bottleneck in the first place.
Keep increasing the number of objects fired per frame until you see unacceptable frames per second.
You should also check out GameDev.Stackexchange.com, as a lot of people there are more qualified to answer Game Dev questions.
No matter what you do, too many actors on the stage will degrade performance. I would personally try to create symbol instances as movieClips and move them along a path, deleting them when they come into contact with a target. (Doing it this way also gives you collision detection, which will be important if the targets can move out of the way. If a collision is detected the bullet can play its "explosion" scene, etc.)
Determine the distance the bullet should move in each frame once and let it go. If each bullet knows how far it should move on its x and y properties per frame, you don't need to calculate it again and the bullet will fly straight. If your using Bresenham's Line Algorithm every time the bullet moves, you are doing to much work. Just make sure the movement in x and y is stored as a Number otherwise the bullet wont end up where it should.
精彩评论