I have to program a game for college and I am trying to get a static wall to be an obstacle for the player so the player cannot move through it.
if (rectangle1.Right == (wallRect.Left) && rectangle1.Bottom >= wallRect.Top && rectangle1.Top <= wallRect.Bottom)
{
rightMovement = false;
}
else
{
rightMovement = true;
}
Below is the code for the control input.
if (rightMovement == true)
{
if (currentKeyboardState.IsKeyDown(Keys.Right) || currentGamePadState.DPad.Right == ButtonState.Pressed)
{
player1.Position.X += playerMoveSpeed;
}
}
Currently, if I start from the left of the screen and move into the wall the collision works fine, then when I move to the other side of the wall the collision doesn't work then when I move to the right hand side edge of the screen and move into the wall collision works on the right side of the wall but then I can move through the left hand side of the wall. I have written code for the collision on the left and right side of the wall.
1) define 8 vertices, 4 at the coordinates of the player's bounding rectangle original location and 4 for it's new location.
2) define all posible triangles made of these vertices.
3) if one of the triangles intersects with one of the wall's edges than they have collided in this frame.
4) by getting the intersection's min and max positions you can know the collision's coordinates.
Related
I am making a basic Breakout game and using the following code to detect if the collision between the Capsule Collider 2d and circle collider 2d has happened on the top:
bool FindIfTopCol(Collision2D other)
{
print("collider.y " + collidersize.y / 2);
ContactPoint2D[] contacts = other.contacts;
if (contacts[0].point.y - transform.position.y > collidersize.y / 2)
{
print("top " + (contacts[0].point.y - transform.position.y));
return true;
}
else
{
print("not top " + (contacts[0].point.y - transform.position.y));
return false;
}
}
For the most part the detection was working fine but after running the game a while and especially after the circle collider gets into a non top collision, the method seems to return all the collisions as non top collision.
To figure out the issue i placed print statements and this is the result:
collidery 0.2610874
top 0.2885695
collidery 0.2610874
not top 0.2552783 First actual non top collision
collidery 0.2610874
not top 0.2542975 It's a top collision, but shows as not top
collidery 0.2610874
not top 0.2558844 It's top collision, but shows as not top
And the rest of the collisions for the session is also wrong like this, until i restart the game.
I am not sure whats going wrong here.
And also if there is a better way to detect collision side, please let me know.
I'm not really sure what's happening here but I would use OnCollisionEnter2D() event to detect collisions. Then compare the contact point with the collider center to figure out what surface it hit. Here's an example from kacyesp.
Vector3 contactPoint = collision.contacts[0].point;
Vector3 center = collider.bounds.center;
bool right = contactPoint.x > center.x;
bool top = contactPoint.y > center.y;
I'm having a glitch with this simple collision algorithm. I'm doing the rpg game tutorial from codingmadeeasy, and the collision is much alike any algorithm collision I've done in previous platformer style games. I've had this problem with previous games as well, just don't remember the fix. I have a map, it has lots of tiles, some are flagged as solid. their Update method checks for collision with the player.
If the tile is solid, it should stop the player and move him to a valid location.
Problem is when I go up or down, stick to the tile, and press a left or right movement key.
For example:
I'm pressing the Down key, I'm on top of the solid tile, and I press to go Left. at that moment, the player is relocated to to the Right of the tile.
This wouldn't happen if I go left or right and press up or down because of the if order in the collision method.
public void Update(GameTime gameTime, ref Player player)
{
if (State != TileState.Solid) return;
Rectangle tileRect =
new Rectangle((int)Position.X, (int)Position.Y,
SourceRect.Width, SourceRect.Height);
Rectangle playerRect =
new Rectangle((int)player.Sprite.position.X, (int)player.Sprite.position.Y,
player.Sprite.SourceRect.Width, player.Sprite.SourceRect.Height);
HandleCollisionWithTile(player, playerRect, tileRect);
}
/// <summary>
/// Repositions the player at the current position after collision with tile
/// </summary>
/// <param name="player">the player intersecting with the tile</param>
/// <param name="playerRect">the rectangle of the player</param>
/// <param name="tileRect">the rectangle of the tile</param>
private static void HandleCollisionWithTile(Player player, Rectangle playerRect, Rectangle tileRect)
{
// Make sure there's even collosion
if (!playerRect.Intersects(tileRect)) return;
// Left
if (player.Velocity.X < 0)
player.Sprite.position.X = tileRect.Right;
// Right
else if (player.Velocity.X > 0)
player.Sprite.position.X = tileRect.Left - player.Sprite.SourceRect.Width;
// Up
else if (player.Velocity.Y < 0)
player.Sprite.position.Y = tileRect.Bottom;
// Down
else if (player.Velocity.Y > 0)
player.Sprite.position.Y = tileRect.Top - player.Sprite.SourceRect.Height;
// Reset velocity
player.Velocity = Vector2.Zero;
}
Obviously, If I switch the two first ifs with the last, that would happen if I come from the side and press up or down.
What exactly am I missing?
As you've noted, this issue occurs because of the order in which you check the condition for collision. In particular, while visually your player sprite appears to be above a tile, your code is detecting the sprite as intersecting, and since the first check is for horizontal collisions, the player sprite's position is moved to the right of the tile's sprite (above and to the right, actually, so you only adjust the coordinate in the axis of the detected collision).
It seems to me that this exposes a fundamental flaw in the code: while one might argue that having resolved the collision that occurred in the vertical direction, by placing the player sprite at the top of the tile sprite, now the player sprite should not be in a collision state with the tile sprite, instead your code detects this condition as a collision.
Without a better code example, it's hard to know what the best fix might be. But an obvious quick-and-dirty solution would be to ensure that when you resolve a collision, you are not putting the player sprite in a position that intersects with the tile sprite. For example:
private static void HandleCollisionWithTile(Player player, Rectangle playerRect, Rectangle tileRect)
{
// Make sure there's even collosion
if (!playerRect.Intersects(tileRect)) return;
// Left
if (player.Velocity.X < 0)
player.Sprite.position.X = tileRect.Right + 1;
// Right
else if (player.Velocity.X > 0)
player.Sprite.position.X = tileRect.Left - player.Sprite.SourceRect.Width - 1;
// Up
else if (player.Velocity.Y < 0)
player.Sprite.position.Y = tileRect.Bottom + 1;
// Down
else if (player.Velocity.Y > 0)
player.Sprite.position.Y = tileRect.Top - player.Sprite.SourceRect.Height - 1;
// Reset velocity
player.Velocity = Vector2.Zero;
}
In other words, give yourself a 1 pixel margin around the tile into which the player sprite may not enter.
An alternative would be to "deflate" the tile rectangle (i.e. call Inflate() with negative values) by 1 pixel before checking for the intersection that defines a collision. Then when a collision does occur, the placement will be as before (i.e. without the +1 and -1 adjustments shown above), but that placement will not itself be detected as a collision.
There are many other ways to handle collision detection, but a) without more specifics about your scenario it's hard to know whether and which of those might be better choices, and b) given the apparently simple nature of your current implementation, a relatively simple fix as I've proposed above seems more likely to be warranted and useful.
I'm developing a 2D game with XNA game studio 4.0 and I need to make my "Hero" sprite shoot a shot sprite, which is a rectangle.
When I press left control to shoot, the shot is starting from my player. So far, it's ok, but the problem is that it never stops - its position never goes to theVoid.
Here is my code for shooting:
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.LeftControl) && isShotted == false)
{
isShotted = true;
shotPosition = playerPosition;
}
if (isShotted == true && (shotPosition.X <= shotPosition.X+150) )
{
shotPosition.X += shotSpeed.X * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
else
{
isShotted = false;
shotPosition = theVoid;
}
}
Some clarification:
playerPosition is my "Hero" sprite position.
theVoid is Vector2 (700,700), when I set shotPosition = theVoid the shot dissapears.
The shot never disapears because you are updating shotPosition.x every update. You are checking:
if (isShotted == true && (shotPosition.X <= shotPosition.X+150) )
And then inside that if you increment shotPosition.X:
shotPosition.X += shotSpeed.X * (float)gameTime.ElapsedGameTime.TotalSeconds;
One option to fix this would be to check shotPosition.X against the player position - per #jonhopkins comment. If the player can move near the same speed as the shot though, they could just follow it and then the shot would never disappear, this may or may not be what you want.
Your other option is to store the position of where the shot was fired, and compare something like:
if (isShotted == true && (shotPosition.initialX+150 >= shotPosition.currentX) )
Make sure you think about this in terms of how your players and objects move around the coordinate system though. If your player is always stationary in regards to the x-axis that could simplify things compared to if they can run around the screen..
Okay, so, I am making a small tile-based digging game, now I want to do collision. How would I go about doing this correctly? I know how to check if the player collides with a tile, but I don't know how to actually make the player stop when it hits a wall.
This is the game, I got 20x20 tiles here.
This is the code I'm using atm:
foreach (Tile tiles in allTiles)
{
if (ply.rect.Intersects(tiles.rect))
{
if (tiles.ID != -1 && tiles.ID != 1)
{
if (ply.X > tiles.X)
{
Console.WriteLine("Right part.");
ply.X = tiles.pos.X + 30;
}
if (ply.X <= tiles.X)
{
Console.WriteLine("Left part.");
ply.X = tiles.pos.X - 30;
}
if (ply.Y > tiles.Y)
{
Console.WriteLine("Bottom part.");
ply.Y = tiles.pos.Y + 30;
}
if (ply.Y <= tiles.Y)
{
Console.WriteLine("Upper part.");
ply.Y = tiles.pos.Y - 30;
}
}
}
}
What type of collision detection are you using?
If your using Rectangles and the '.intersects' method you can always declare a bool to make sure your character is touching the floor. If he isn't you apply a Gravity Vector to make it fall to the next Tile with a different Rectangle so when he hits it he's going to stop falling.
If you want to block him from side to side just test to see which side of the rectangle he is touching and block him from moving on the 'X' axis.
E.g if he is going right and intersects with the left part of a rectangle, block is 'GoingRight' movement.
if(myCharacterRectangle.Intersects(tileRectangle)
{
if(myCharacterPosition.X > (tilePosition.X)
{
//You know the character hits the Right part of the tile.
}
if(mycharacterPosition.X <= tilePosition.X)
{
//You know the character hits the Left Part of the tile.
}
}
And same goes for the Position.Y if you want to test the Top or Bottom.
If you want to use Pixel by Pixel collision detection using Matrices I know a good tutorial here.
The detection will return a 'Vector2(-1,-1)' if there is no collision.
If there is a one the method will return the coordinates of the collisions which makes it even easier to determine what part of the tile your character is touching.
Hope this helps. Good Luck with your game.
The colision is working but its something wrong with theese lines since the player is just standing still at the start position x10 y10
for (int i = 0; i < sprites.Length; i++)
{
if (player.Top > sprites[i].Top && player.Bottom < sprites[i].Top) //Checking for intersection at the top of the player
{
player_Collision1 = true; //Found collision
}
else if (player.Bottom > sprites[i].Top && player.Bottom < sprites[i].Bottom) //Checking for intersection at the bottom of the player
{
player_Collision2 = true; //Found collision
}
else if (player.Left > sprites[i].Right && player.Left < sprites[i].Left) //Checking for intersection at the left of the player
{
player_Collision3 = true; //Found collision
}
else if (player.Right > sprites[i].Left && player.Right < sprites[i].Right)//Checking for intersection at the right of the player
{
player_Collision4 = true; //Found collision
}
}
Im using the XNA's rectangle and player is name of one rectangle and sprites is an array of all the rectangles that player can collide with, The XNA rectangle lets you get the cordinates of the sides of the rectangle as you se me do: player.Top player.Bottom etc etc.
The logic is really messed up. The first if will never be true as the player.top cant be below the sprite.top AND the player.bottom above the sprite.top. What I think you meant was if (player.Top > sprites[i].Top && player.Bottom < sprites[i].Bottom) Even still, it will evaluate to true when they don't collide. Look at this picture as to why. You also need to check the X axis to determine a proper collision.
The other ifs have the same issue as the first. Both in comparing bottom/top and top/bottom and returning true when there is no collision. That being said, I you are trying to do a poor-man "line of sight" scenario where you just want to see if the player is standing in a location that the sprite could "see", I am wrong.
I suggest taking a look at the platformer starter kit provided on the App Hub site as well as some documention on it. Specifically, look at the collision detection (in Player.cs CheckCollision()...or HandleCollision() I foget the exact name. It should be obvious.) You will be able to see how they determine which direction the player is colliding. They use it to see if a player can jump through a platform, but not fall through it.