Reputation: 2822
I'm trying to create a good way to handle all possible collisions between two objects. Typically one will be moving and hitting the other, and should then "bounce" away.
What I've done so far (I'm creating a typical game where you have a board and bounce a ball at bricks) is to check if the rectangles intersect and if they do, invert the Y-velocity.
This is a really ugly and temporary solution that won't work in the long haul and since this is kind of processing is very common in games I'd really like to find a great way of doing this for future projects aswell. Any links or helpful info is appreciated.
Below is what my collision-handling function looks like right now.
protected void collision()
{
#region Boundaries
if (bal.position.X + bal.velocity.X >= viewportRect.Width ||
bal.position.X + bal.velocity.X <= 0)
{
bal.velocity.X *= -1;
}
if (bal.position.Y + bal.velocity.Y <= 0)
{
bal.velocity.Y *= -1;
}
#endregion
bal.rect = new Rectangle((int)bal.position.X+(int)bal.velocity.X-bal.sprite.Width/2, (int)bal.position.Y-bal.sprite.Height/2+(int)bal.velocity.Y, bal.sprite.Width, bal.sprite.Height);
player.rect = new Rectangle((int)player.position.X-player.sprite.Width/2, (int)player.position.Y-player.sprite.Height/2, player.sprite.Width, player.sprite.Height);
if (bal.rect.Intersects(player.rect))
{
bal.position.Y = player.position.Y - player.sprite.Height / 2 - bal.sprite.Height / 2;
if (player.position.X != player.prevPos.X)
{
bal.velocity.X -= (player.prevPos.X - player.position.X) / 2;
}
bal.velocity.Y *= -1;
}
foreach (Brick b in brickArray.list)
{
b.rect.X = Convert.ToInt32(b.position.X-b.sprite.Width/2);
b.rect.Y = Convert.ToInt32(b.position.Y-b.sprite.Height/2);
if (bal.rect.Intersects(b.rect))
{
b.recieveHit();
bal.velocity.Y *= -1;
}
}
brickArray.removeDead();
}
Upvotes: 4
Views: 650
Reputation: 243096
Here are a couple of suggestions that may help.
First of all, all your objects such as Player
, Bal
(not sure what that is) and Brick
have somewhat similar interface - they all have sprite
(defining the size of the object), rect
(bounding box of the object), position
(current position), velocity
(current velocity). This suggests that you could create a common base class to encapsulate this functionality.
Also note that you're always recalculating rect
based on the current position
and sprite
. This suggests that rect
should actually be a property that hides the recalculation (which is always the same!)
So, you can start by defining a common base class like this (I'll follow .NET standard coding style and use properties and CamelCase
names):
class GameObject {
Point Position { get; set; }
Vector Velocity { get; set; }
Sprite Sprite { get; set; }
Rectangle Rect {
get {
// Ecnapsulated calculation of the bounding rectangle
return new Rectangle
( (int)Position.X + (int)Velocity.X - Sprite.Width/2,
(int)Position.Y + (int)Velocity.Y - Sprite.Height/2,
Sprite.Width, Sprite.Height);
}
}
If you now use this type as a base class for all your game objects, you should be able to write this:
protected void Collision() {
#region Boundaries
if (bal.Position.X + bal.Velocity.X >= viewportRect.Width ||
bal.Position.X + bal.Velocity.X <= 0)
bal.Velocity.X *= -1;
if (bal.Position.Y + bal.Velocity.Y <= 0)
bal.Velocity.Y *= -1;
#endregion
if (bal.Rect.Intersects(player.Rect)) {
bal.Position.Y = player.Position.Y - player.Sprite.Height/2
- bal.Sprite.Height/2;
if (player.Position.X != player.PrevPos.X)
bal.Velocity.X -= (player.PrevPos.X - player.Position.X) / 2;
bal.Velocity.Y *= -1;
}
foreach (Brick b in brickArray.list) {
if (bal.Rect.Intersects(b.Rect)) {
b.RecieveHit();
bal.Velocity.Y *= -1;
}
}
brickArray.RemoveDead();
}
It also sounds like a good idea to split the function between two - one that checks bal
and player
and the other that checks the bricks.
Upvotes: 1