FIXED: Player collision with multiple objects

Started by
0 comments, last by FalconDragoon 11 years, 10 months ago
I wanted to implement some simple collision detection with rectangles into my project to see if it can handle collision with multiple objects of a list, because I already had a problem with displaying multiple objects of the same type at a time (Though I was able to fix that one myself). Unfortunately the worst I could imagine happened (Besides it not working at all): The game only checks for one wall, and it seems like it just aborts the for loop after that.

Here's the code that checks for the collision, but only checks for the first wall object created:

public void UpdatePlayer(GameTime gameTime)
{
for (int i = WallList.Count - 1; i >= 0; i--)
{
// Disable moving through walls on the right.
Rectangle playerrect = new Rectangle((int)(player.Position.X + player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y - player.PlayerAnimations.FrameHeight / 2), 0, 16);
if (playerrect.Intersects(WallList.CollisionBox)) player.AllowRight = false;
else if (!player.AllowRight) player.AllowRight = true;
// Disable moving through walls on the left.
playerrect = new Rectangle((int)(player.Position.X - player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y - player.PlayerAnimations.FrameHeight / 2), 0, 16);
if (playerrect.Intersects(WallList.CollisionBox)) player.AllowLeft = false;
else if (!player.AllowLeft) player.AllowLeft = true;
// ^Up
playerrect = new Rectangle((int)(player.Position.X - player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y - 1 - player.PlayerAnimations.FrameHeight / 2), 16, 0);
if (playerrect.Intersects(WallList.CollisionBox)) player.AllowUp = false;
else if (!player.AllowUp) player.AllowUp = true;
// ^Down
playerrect = new Rectangle((int)(player.Position.X - player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y + player.PlayerAnimations.FrameHeight / 2), 16, 0);
if (playerrect.Intersects(WallList.CollisionBox)) player.AllowDown = false;
else if (!player.AllowDown) player.AllowDown = true;
}

player.Update(ref ProjList, fireball, Woosh, GraphicsDevice.Viewport, gameTime, prevKeyboardState,
curKeyboardState, prevGamePadState, curGamePadState);
}


If I for example switch for (int i = WallList.Count - 1; i >= 0; i--) with for (int i = 0; i < WallList.Count; i++), it only checks for the last wall object created.

Even if I don't think that the problem could lie in the creation of the wall or the wall itself, here's the code used for both:
[spoiler]
/* The method used to add a rock to the game */
public void AddRock()
{
Rock rock = new Rock();
Animation RockAnim = new Animation();
rock.TexData = new Color[rockanim.Width * rockanim.Height];
rockanim.GetData(rock.TexData);
RockAnim.Initialize(rockanim, Vector2.Zero, 16, 16, 1, 1, 10, Color.White, 1f, true);
int i = (int)(random.NextDouble() * 10);
for (; i > 4; i = (int)(random.NextDouble() * 10)) ;
Vector2 RockPos = new Vector2((float)random.NextDouble() * (-graphics.GraphicsDevice.Viewport.Width / 2),
(float)random.NextDouble() * (-graphics.GraphicsDevice.Viewport.Height / 2));
Rectangle RockRect = new Rectangle((int)(RockPos.X - RockAnim.FrameWidth / 2),
(int)(RockPos.Y - RockAnim.FrameHeight / 2), 16, 16);
rock.Initialize(RockPos, RockRect, RockAnim, i);
WallList.Add(rock);
}



/* The Rock class */
class Rock
{
public Vector2 Position;
public Animation RockAnimations;
public Color[] TexData;
Rectangle FrameBox;
public Rectangle CollisionBox
{
get { return FrameBox; }
}
public bool Active;
public void Initialize(Vector2 pos, Rectangle rockrect, Animation anim, int variety)
{
Position = pos;
RockAnimations = anim;
FrameBox = rockrect;
RockAnimations.FrameVariety = variety;
RockAnimations.SetPosition(Position);
Active = true;
}
public void Update(GameTime gameTime)
{
RockAnimations.Update(gameTime);
}
public void Draw(SpriteBatch spriteBatch)
{
RockAnimations.Draw(spriteBatch, 0f);
}
}

[/spoiler]

Please let me know if you find a solution for this, because I'm running out of ideas how to fix this one.

EDIT: Fixed the problem myself! Had to place if (!player.AllowRight || !player.AllowLeft || !player.AllowUp || !player.AllowDown) break; at the end of the for loop or else it would just overwrite the AllowX bools for every wall, resulting in making only the last wall that's being checked in the loop affect the players movement.
Advertisement
One thing you might want to consider is using a local set of bools, updating those in the loop and assigning to your player item after the loop. Adding the IF to the top of the loop will prevent overwriting, however it will mean you can only collide with a singe iteration.
However, something like this:
[source lang="csharp"]bool allowUp = true, allowDown = true, allowLeft = true, allowRight = true;
for (int i = WallList.Count - 1; i >= 0; i--)
{
if(!allowUp && !allowDown && !allowLeft && !allowRight) break;
// Disable moving through walls on the right.
Rectangle playerrect = new Rectangle((int)(player.Position.X + player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y - player.PlayerAnimations.FrameHeight / 2), 0, 16);
if (playerrect.Intersects(WallList.CollisionBox)) allowRight = false;
else allowRight = allowRight && true;
// Disable moving through walls on the left.
playerrect = new Rectangle((int)(player.Position.X - player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y - player.PlayerAnimations.FrameHeight / 2), 0, 16);
if (playerrect.Intersects(WallList.CollisionBox)) allowLeft = false;
else allowLeft = allowLeft && true;
// ^Up
playerrect = new Rectangle((int)(player.Position.X - player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y - 1 - player.PlayerAnimations.FrameHeight / 2), 16, 0);
if (playerrect.Intersects(WallList.CollisionBox)) allowUp = false;
else allowUp = allowUp && true;
// ^Down
playerrect = new Rectangle((int)(player.Position.X - player.PlayerAnimations.FrameWidth / 2),
(int)(player.Position.Y + player.PlayerAnimations.FrameHeight / 2), 16, 0);
if (playerrect.Intersects(WallList.CollisionBox)) allowDown = false;
else allowDown = allowDown && true;
}
player.AllowUp = allowUp;
//etc...[/source]
Will allow you to check all the walls for collisions in all directions, while also breaking the loop when checking is no longer needed (the case where the player is blocked in all for directions)

My Games -- My Music 

Come join us for some friendly game dev discussions over in XNA Chat!

This topic is closed to new replies.

Advertisement