A Better 2D Bouncing Ball Algorithm
One of my most popular articles on this blog so far has been my tutorial Bouncing Ball Movement in a 2D Level. While it did the job, it had some serious performance issues when you had multiple objects using this algorithm. I use this movement for some enemies in my game and was finding that on levels with a lot of blocks and a lot of enemies using this movement, frame rates would often drop into the teens (not good for a public that has grown accustomed to 60 fps).
This new version of the code is significantly faster. The previous version would always check if there was a collision above, below, left, and right of the object and then allow it to move accordingly. The new version will first check if there is a collision where the object wants to go. If not, then we allow the object to go there. If there is a collision, then we check (based on the direction the enemy is headed) up or down and left or right. Any collisions in these subsequent checks will result in that direction being reversed.
currentPosition is a Vector2 of where the object (enemy in this case) is located on the screen. futurePosition is also a Vector2 that we will use to detect if there is a collision where the object wants to go.
Also beware that Collision.checkLevelCollision() is a static method I use for checking collisions in my level (you'll see it in the code below). It loops through all the different blocks and returns if the source collided with them or not (I promise I will put code for all this up one of these days). You can substitute your own collision detection algorithms here and (assuming they return true or false) not affect the functionality of this code.
elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
futurePosition = currentPosition;
futurePosition.Y += enemyDirection.Y * enemySpeed.Y * elapsed;
futurePosition.X += enemyDirection.X * enemySpeed.X * elapsed;
if (Collision.checkLevelCollision(levelBlocks, futurePosition, source))
{
Vector2 futureVerticle = currentPosition;
futureVerticle.Y += enemyDirection.Y * enemySpeed.Y * elapsed;
if (Collision.checkLevelCollision(levelBlocks, futureVerticle, source))
{
enemyDirection.Y = -enemyDirection.Y;
}
Vector2 futureHorizontal = currentPosition;
futureHorizontal.X += enemyDirection.X * enemySpeed.X * elapsed;
if (Collision.checkLevelCollision(levelBlocks, futureHorizontal, source))
{
enemyDirection.X = -enemyDirection.X;
}
}
CurrentPosition += enemyDirection * enemySpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
// Wrap leaving the sides
if (this.CurrentPosition.X < GameObject.MinScreenSize.X - this.enemySize.X)
{
currentPosition.X = GameObject.MaxScreenSize.X;
}
else if (this.CurrentPosition.X > GameObject.MaxScreenSize.X + enemySize.X)
{
currentPosition.X = GameObject.MinScreenSize.X - this.enemySize.X;
}
// Wrap leaving the bottom
if (CurrentPosition.Y > GameObject.MaxScreenSize.Y + this.enemySize.Y)
{
currentPosition.Y = GameObject.MinScreenSize.Y;
}
else if (this.CurrentPosition.Y < GameObject.MinScreenSize.Y - this.enemySize.Y)
{
currentPosition.Y = GameObject.MaxScreenSize.Y;
}
In the old version, you
This article has been view 6174 times.
|