Collision detection and Rectangles - c#

I'm trying to get the velocity of my character to be zero when it collides with another sprite. It does this, however the distance between the textures increases when it collides if I choose a higher value for speed, the higher the value the further the distance between the textures when collision occurs.
At a speed of 1f the collision seems to work fine (both textures touching) but 1f is too slow for my game and I can't figure out how to increase it without increasing the distance of collision.
I believe this is because I use: rectangle.Right + Velocity.X in my Collision region but I'm not sure how to alter this to fix my problem. Help would be appreciated.
//In Sprite class
#region Collision
protected bool IsTouchingLeft(Sprite sprite)
{
return rectangle.Right + Velocity.X > sprite.rectangle.Left &&
rectangle.Left < sprite.rectangle.Left &&
rectangle.Bottom > sprite.rectangle.Top &&
rectangle.Top < sprite.rectangle.Bottom;
}
protected bool IsTouchingRight(Sprite sprite)
{
return rectangle.Left + Velocity.X < sprite.rectangle.Right &&
rectangle.Right > sprite.rectangle.Right &&
rectangle.Bottom > sprite.rectangle.Top &&
rectangle.Top < sprite.rectangle.Bottom;
}
protected bool IsTouchingTop(Sprite sprite)
{
return rectangle.Bottom + Velocity.Y > sprite.rectangle.Top &
rectangle.Top < sprite.rectangle.Top &&
rectangle.Right > sprite.rectangle.Left &&
rectangle.Left < sprite.rectangle.Right;
}
protected bool IsTouchingBottom(Sprite sprite)
{
return rectangle.Top + Velocity.Y < sprite.rectangle.Bottom &
rectangle.Bottom > sprite.rectangle.Bottom &&
rectangle.Right > sprite.rectangle.Left &&
rectangle.Left < sprite.rectangle.Right;
}
#endregion
//In MainChar class
foreach (var sprite in sprites)
{
if (sprite == this)
{
continue;
}
if (Velocity.X > 0 && IsTouchingLeft(sprite) || Velocity.X < 0 && IsTouchingRight(sprite))
{
Velocity.X = 0;
}
if (Velocity.Y > 0 && IsTouchingTop(sprite) || Velocity.Y < 0 && IsTouchingBottom(sprite))
{
Velocity.Y = 0;
}
if (sprite.rectangle.Intersects(rectangle))
{
hasDied = true;
}
}

Handling multiple collisions correctly will require sub-stepping, repeating the collision checks until there are no more collisions or a counter expires. This is how physics engines operate.
I am going to show a different method. It requires not doing the move that caused the collision and adjusting the velocity by half each step. Slow down until you get there a maximum of log2(Velocity) steps(for velocities < 32, 5 steps):
foreach (var sprite in sprites)
{
if (sprite == this)
{
continue;
}
// it is good practice to use () for mixed && and ||
if ((Velocity.X > 0 && IsTouchingLeft(sprite)) || (Velocity.X < 0 && IsTouchingRight(sprite)))
{
Velocity.X *= 0.5f;
// by halving, the velocity will exponentially decay to 0
}
if ((Velocity.Y > 0 && IsTouchingTop(sprite)) || (Velocity.Y < 0 && IsTouchingBottom(sprite)))
{
Velocity.Y *= 0.5f;
}
if (sprite.rectangle.Intersects(rectangle))
{
hasDied = true;
}
// use new velocity to update the position.
}
You may have to fix the death condition, it is unclear when it should be triggered. The code as written will move up to the other object, but never overlap on its own.
The following code is what I believe you intended(move at a speed of 1 until overlap)
foreach (var sprite in sprites)
{
if (sprite == this)
{
continue;
}
// it is good practice to use () for mixed && and ||
if ((Velocity.X > 0 && IsTouchingLeft(sprite)) || (Velocity.X < 0 && IsTouchingRight(sprite)))
{
if (Velocity.X >= 2) // cap it at a minimum above 1
{
Velocity.X *= 0.5f;
// by halving, the velocity will exponentially decay to 0
}
if (sprite.rectangle.Intersects(rectangle))
{
Velocity.X = 0; // probably need to do this for Y here as well.
hasDied = true;
}
}
if ((Velocity.Y > 0 && IsTouchingTop(sprite)) || (Velocity.Y < 0 && IsTouchingBottom(sprite)))
{
if (Velocity.Y >= 2) // cap it at a minimum above 1
{
Velocity.Y *= 0.5f;
// by halving, the velocity will exponentially decay to 0
}
if (sprite.rectangle.Intersects(rectangle))
{
Velocity.Y = 0; // probably need to do this for X here as well.
hasDied = true;
}
}
}

Related

Unity: Using Mouse Position To Make Angles For My Camera To Rotate Around An Object

I am trying to make a mouse-oriented 3d Agar.io. Right now, I am working on the basic movement and camera readjustments. I want the camera to be able to rotate around an object, but here is the catch: I want to use only the mouse to move the object and camera, and rotate the camera. I, however, was able to configure the logic of this using the distance formula twice and the law of cosines. I based this on the origin point (0, 0). I am positive that there is nothing wrong with the process that I did; however, I know that the way it is being outputted is wrong.
Every time you move the mouse left or right, I want the camera to rotate immediately after. I tried using a FixedUpdate and LateUpdate event to try to make this happen but both did not succeed. The code I tried using for the camera to rotate is this:
void LateUpdate ()
{
// Move Camera
transform.position = new Vector3(camX, 10.5f, camZ);
//Rotate Camera
//transform.eulerAngles = getRotation;
//transform.eulerAngles = Vector3.MoveTowards(currentRotation, getRotation, speed * Time.deltaTime);
}
The full code I have (updated):
public class CameraController : MonoBehaviour {
public float speed;
public GameObject player;
private Ray ray;
private RaycastHit hit;
private Vector3 mousePos;
private float camX;
private float camZ;
private float getA;
private float getB;
private float getC;
private float getAngle;
private Vector3 currentRotation;
private Vector3 getRotation;
void Start ()
{
}
void FixedUpdate()
{
}
void LateUpdate ()
{
if (PlayerController.movedPlayer)
{
if (Physics.Raycast(ray, out hit))
{
mousePos = new Vector3(hit.point.x, 1.3f, hit.point.z);
}
// MouseZ
if (mousePos.z >= player.transform.position.z)
{
// Camera Follow Z+
if ((player.transform.position.z >= 0 && player.transform.position.x >= 0) &&
player.transform.position.z >= player.transform.position.x)
{
camZ = player.transform.position.z - 10;
camX = 0;
}
else if ((player.transform.position.z >= 0 && player.transform.position.x < 0) &&
player.transform.position.z >= -player.transform.position.x)
{
camZ = player.transform.position.z - 10;
camX = 0;
}
else if ((player.transform.position.z >= 0 && player.transform.position.x >= 0) &&
player.transform.position.z < player.transform.position.x)
{
camX = player.transform.position.x - 10;
camZ = 0;
}
else if ((player.transform.position.z >= 0 && player.transform.position.x < 0) &&
player.transform.position.z < -player.transform.position.x)
{
camX = player.transform.position.x + 10;
camZ = 0;
}
// Camera Follow Z-
if ((player.transform.position.z < 0 && player.transform.position.x >= 0) &&
-player.transform.position.z >= player.transform.position.x)
{
camZ = player.transform.position.z + 10;
camX = 0;
}
else if ((player.transform.position.z < 0 && player.transform.position.x < 0) &&
-player.transform.position.z >= -player.transform.position.x)
{
camZ = player.transform.position.z + 10;
camX = 0;
}
else if ((player.transform.position.z < 0 && player.transform.position.x >= 0) &&
-player.transform.position.z < player.transform.position.x)
{
camX = player.transform.position.x - 10;
camZ = 0;
}
else if ((player.transform.position.z < 0 && player.transform.position.x < 0) &&
-player.transform.position.z < -player.transform.position.x)
{
camX = player.transform.position.x + 10;
camZ = 0;
}
}
//PlayerZ
else if (mousePos.z < player.transform.position.z)
{
// Camera Follow Z+
if ((player.transform.position.z >= 0 && player.transform.position.x >= 0) &&
player.transform.position.z >= player.transform.position.x)
{
camZ = player.transform.position.z + 10;
camX = 0;
}
else if ((player.transform.position.z >= 0 && player.transform.position.x < 0) &&
player.transform.position.z >= -player.transform.position.x)
{
camZ = player.transform.position.z + 10;
camX = 0;
}
else if ((player.transform.position.z >= 0 && player.transform.position.x >= 0) &&
player.transform.position.z < player.transform.position.x)
{
camX = player.transform.position.x + 10;
camZ = 0;
}
else if ((player.transform.position.z >= 0 && player.transform.position.x < 0) &&
player.transform.position.z < -player.transform.position.x)
{
camX = player.transform.position.x - 10;
camZ = 0;
}
// Camera Follow Z-
if ((player.transform.position.z < 0 && player.transform.position.x >= 0) &&
-player.transform.position.z >= player.transform.position.x)
{
camZ = player.transform.position.z - 10;
camX = 0;
}
else if ((player.transform.position.z < 0 && player.transform.position.x < 0) &&
-player.transform.position.z >= -player.transform.position.x)
{
camZ = player.transform.position.z - 10;
camX = 0;
}
else if ((player.transform.position.z < 0 && player.transform.position.x >= 0) &&
-player.transform.position.z < player.transform.position.x)
{
camX = player.transform.position.x + 10;
camZ = 0;
}
else if ((player.transform.position.z < 0 && player.transform.position.x < 0) &&
-player.transform.position.z < -player.transform.position.x)
{
camX = player.transform.position.x - 10;
camZ = 0;
}
}
// Make Triangle
getA = mousePos.x - player.transform.position.x;
getB = mousePos.z - player.transform.position.z;
getC = Mathf.Sqrt(Mathf.Pow((getA), 2) + Mathf.Pow((getB), 2));
// Get Rotating Angle.
if (getA == 0 && getB >= 0)
{
getAngle = 0;
}
else if (getA == 0 && getB < 0)
{
getAngle = 180;
}
else if (getB == 0 && getA >= 0)
{
getAngle = 90;
}
else if (getB == 0 && getA < 0)
{
getAngle = 270;
}
else
{
if (getA > 0)
{
getAngle = Mathf.Acos((Mathf.Pow((getB), 2) + Mathf.Pow((getC), 2) - Mathf.Pow((getA), 2)) /
(2 * (getB) * (getC))) * Mathf.Rad2Deg;
}
else if (getA < 0)
{
getAngle = -Mathf.Acos((Mathf.Pow((getB), 2) + Mathf.Pow((getC), 2) - Mathf.Pow((getA), 2)) /
(2 * (getB) * (getC))) * Mathf.Rad2Deg;
}
//getAngle = Mathf.Asin(getA * Mathf.Sin(90) / getC);
//Debug.Log("A: " + getA + " B: " + getB + " C: " + getC + " Angle: " + getAngle);
}
// Set Rotating Angle
currentRotation = transform.eulerAngles;
getRotation = new Vector3(45f, getAngle, 0f);
}
// Move Camera
transform.position = new Vector3(camX, 10.5f, camZ);
//Rotate Camera
//transform.eulerAngles = getRotation;
transform.eulerAngles = Vector3.MoveTowards(currentRotation, getRotation, speed * Time.deltaTime);
}
}
Let me elaborate on the code. I wanted the camera to face toward the origin when the mouse was the closest to it and vise versa. I am having some trouble with this because I don't think I set it up right. My attempt at trying to fix this was using reverse logic (i.e. when the mouse is closer to the origin the camera is the furthest away from the origin [mouse -> object -> camera]. The opposite would be true if the mouse was the furthest from the origin [camera -> object -> mouse].)
Now that you know some of the issues I am having, here is what I need answered (I would prefer you write a solution and tell me how it fixes the problem.): How do I fix the camera rotation so it rotates immediately when the mouse moves, and how can I specify whether the mouse is closer, or not, to the origin?
Update: I moved all the code to LateUpdate because that's when you should do your camera algorithms. I also "tried" to simplify the mouse location part, so it isn't so redundant. I also have a link to a screen capture of my project: https://gyazo.com/2f5ee8f94c0bc55bbdeaeafa8a8b35f4
I found the solution:
transform.rotation = Quaternion.RotateTowards(transform.rotation, getRotation, speed * Time.deltaTime);

Collision is skipping certain quads

I've formulated my own collision system in a modified version of OpenTK. It works by running a foreach loop which checks all the quads in the game (this runs when something moves) and sets their position back to where it was last frame, that is if it intersects this frame. I might not have explained that well, so here is the SetXVelocity code, called when a player moves right.
public void SetXVelocity(float x)
{
foreach (Quad quad in quads)
{
if (!quad.Equals(this))
{
if (Intersects(quad))
{
Velocity.x = 0;
Position = OldPosition;
continue;
}
if (!Intersects(quad))
{
OldPosition = Position;
Velocity.x = x;
continue;
}
}
else
{
OldPosition = Position;
continue;
}
OldPosition = Position;
continue;
}
}
Here is the code for Intersects:
public bool Intersects(Quad quad)
{
#region
if (TLCorner.x > quad.TLCorner.x && TLCorner.x < quad.BRCorner.x && TLCorner.y < quad.TLCorner.y && TLCorner.y > quad.BRCorner.y)
{
return true;
}
if (BRCorner.x < quad.BRCorner.x && BRCorner.x > quad.TLCorner.x && BRCorner.y > quad.BRCorner.y && BRCorner.y < quad.TLCorner.y)
{
return true;
}
if (TRCorner.x < quad.TRCorner.x && TRCorner.x > quad.BLCorner.x && TRCorner.y < quad.TRCorner.y && TRCorner.y > quad.BLCorner.y)
{
return true;
}
if (BLCorner.x > quad.BLCorner.x && BLCorner.x < quad.TRCorner.x && BLCorner.y > quad.BLCorner.y && BLCorner.y < quad.TRCorner.y)
{
return true;
}
#endregion // Corner Intersection
if (Math.Round(Left, 2) == Math.Round(quad.Right, 2) && TRCorner.y > quad.TRCorner.y && BRCorner.y < quad.BRCorner.y)
return true;
if (Math.Round(Right, 2) == Math.Round(quad.Left, 2) && TRCorner.y > quad.TRCorner.y && BRCorner.y < quad.BRCorner.y)
return true;
return false;
}
By the way, TRCorner is a Vector3 representing the Top Right Corner etc.
Last block of code is the Quad class, keep in mind, the actual class is huge, so I'll try not include all of it:
public Vector3 Velocity;
public Vector3 Position;
public int Index;
public VBO<Vector3> VertexData
{
get;
set;
}
public VBO<int> VertexCount
{
get;
set;
}
public VBO<Vector2> VertexTexture
{
get;
set;
}
For some reason, a few quads have no collision and some do. Some even have collision that makes the player stick to them.
I think some quads are missing because all possible conditions are not covered in your comparisons.
Since you && all your conditions, a collision needs to meet all your conditions to get detected.
if (TLCorner.x > quad.TLCorner.x && TLCorner.x < quad.BRCorner.x && TLCorner.y < quad.TLCorner.y && TLCorner.y > quad.BRCorner.y)
{
return true;
}
if( TLCorner.x == quad.TLCorner.x && TLCorner.y < quad.TLCorner.y && TLCorner.y > quad.BRCorner.y ) the rectangle still collides, but undetected.
Same for other conditions.
You might want to use >= and <= in your code in order to cover all conditions.
As for why they get stuck in one another, your velocity probably pushes them into a condition which makes them collide forever, since you detect the collision after they went into each other and not when the boundaries overlap.
Also you might want to reverse the velocity and "un-stuck" them when collision is detected in a way that does not make them stuck in other nearby rectangles.
I highly recommend you use better logic for collision detection
Link: https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
You can test it here http://jsfiddle.net/knam8/

Unity camera rotation

I have a camera in my scene I am controlling with a third party device. If I spin the device, pitch it forward etc the same action is replicated with my camera. However, I'm stuck working out how to always make sure my camera is facing forward and moving forward in spite of its Y rotation.
For example, my camera starts at point 0,0,0 with the same rotation value. If I rotate my camera 90 degrees (either side) and move my camera forward, my view now moves side ways. How can I get it so that where ever my camera is facing, that is my forward direction?
Here is my code so far:
private void MoveForward()
{
Debug.Log("yaw: " + yaw + " pitch: " + pitch + " roll: " + roll);
if( pitch > maxPitch.x && pitch < maxPitch.y && reversePitch == false)
{
camera.rigidbody.AddForce(0, 0,-pitch);
// camera.transform.position += new Vector3(0,0, -pitch);
}
else if ( pitch > maxPitch.x && pitch < maxPitch.y && reversePitch == true)
{
camera.rigidbody.AddForce(0, 0, pitch);
// camera.transform.position += new Vector3(0,0, pitch);
}
else
{
camera.rigidbody.velocity = Vector3.zero;
// camera.transform.position = new Vector3(0,0,0);
}
}
private void MoveSideways()
{
if( roll > maxRoll.x && roll < maxRoll.y && reverseRoll == false)
{
camera.rigidbody.AddForce( roll, 0, 0);
}
else if ( roll < maxRoll.x && roll > maxRollNegative && reverseRoll == false)
{
camera.rigidbody.AddForce( roll, 0 ,0);
}
else if( roll > maxRoll.x && roll < maxRoll.y && reverseRoll == true)
{
camera.rigidbody.AddForce( -roll, 0, 0);
}
else if ( roll < maxRoll.x && roll > maxRollNegative && reverseRoll == true)
{
camera.rigidbody.AddForce( -roll, 0 ,0);
}
else
{
camera.rigidbody.velocity = Vector3.zero;
}
}
private void RotateAround()
{
if(reverseYaw == true)
{
target = Quaternion.Euler(0, yaw,0);
}
else
{
target = Quaternion.Euler(0, -yaw,0);
}
transform.rotation = Quaternion.Slerp(camera.transform.rotation, target, Time.time *rotationSpeed);
}
This occurs because Rigidbody.AddForce takes a world space vector, but you are giving it a local space vector. Use Transform.TransformDirection to convert your vector from local space to world space.
Vector3 force = transform.TransformDirection(0, 0, pitch);
camera.rigidbody.AddForce(force);

Collision Block Movement

i have problem with blocking movement i already read question on Blocking Movement On Collision
but i dont have any idea for my own problem.
if you can give me the logic i will try to solve my own problem.
i hope you can help me
this my player class update
:EDIT: thanks for Kai Hartmann for reply
my problem is for 2D graphic and i want to know how to stop movement when object1 collision with object2
public void Update(GameTime gameTime)
{
// Ani Test
up_ani.Update(gameTime);
down_ani.Update(gameTime);
left_ani.Update(gameTime);
right_ani.Update(gameTime);
position += velocity;
if (Keyboard.GetState().IsKeyDown(key.MoveUp) && prevState.IsKeyUp(key.MoveDown) && prevState.IsKeyUp(key.MoveRight) && prevState.IsKeyUp(key.MoveLeft))
{
currentFace = FacePosition.Up;
velocity.Y = -3;
}
else if (Keyboard.GetState().IsKeyDown(key.MoveDown) && prevState.IsKeyUp(key.MoveUp) && prevState.IsKeyUp(key.MoveRight) && prevState.IsKeyUp(key.MoveLeft))
{
currentFace = FacePosition.Down;
velocity.Y = 3;
}
else if (Keyboard.GetState().IsKeyDown(key.MoveRight) && prevState.IsKeyUp(key.MoveDown) && prevState.IsKeyUp(key.MoveUp) && prevState.IsKeyUp(key.MoveLeft))
{
currentFace = FacePosition.Right;
velocity.X = 3;
}
else if (Keyboard.GetState().IsKeyDown(key.MoveLeft) && prevState.IsKeyUp(key.MoveDown) && prevState.IsKeyUp(key.MoveRight) && prevState.IsKeyUp(key.MoveUp))
{
currentFace = FacePosition.Left;
velocity.X = -3;
}
else
{
//currentFace = FacePosition.Down;
velocity = Vector2.Zero;
}
prevState = Keyboard.GetState();
}
and this my collision
public void IntersectWithScore(Vector2 vector1, Vector2 vector2, Texture2D object1, Texture2D object2, int doSomethingToScore, bool isIncrease)
{
if (vector1.X + object1.Width < vector2.X || vector1.X > vector2.X + object2.Width ||
vector1.Y + object1.Height < vector2.Y || vector1.Y > vector2.Y + object2.Height)
{
}
else
{
player1.Velocity = Vector2.Zero;
}
}
No need for a collision check Method as far as I'm concerned :) I've written this code really quickly but should work okay?(ish). I've assumed you want to check if something is in the player's way and also assumed that there are more than one objects that could be in your players way so to do this I suggest making a class for the 'Solid' object and giving it a position, width and height. Then make a list of this class to contain the multiple 'solid' objects.
// collidable object's Class name = SolidBlock
SolidBlock newSolidBlock;
List<SolidBlock> solidBlocksList = new List<SolidBlock>();
// This will create 10 'solid' objects and adds them all to a list
// This would preferably go in the Load() function so you can set the positions of
// the blocks after creating them (after the loop)
int i = 0;
while (i < 10)
{
newSolidBlock = new SolidBlock(Vector2, position) // Assuming width and height
// are set within class
solidBlocksList.Add(newSolidBlock);
i++;
}
// It doesn't matter how you create them, the important lines here are the creation of a
// newSolidBlock and then the line adding it to the list of blocks.
solidBlocksList[0].position = new Vector (20, 50); // < for example this is how you would set
// a block's position.
Then in your players update function you refer to this list of objects.
// Input a list of the objects you want your player to collide with
// this is a list in case you have multiple object2s you want to check
// for collision.
// An Object2 should have a position, height, and width, yes?
public void Update(GameTime gameTime, List<Object2> object2List)
{
// Ani Test
up_ani.Update(gameTime);
down_ani.Update(gameTime);
left_ani.Update(gameTime);
right_ani.Update(gameTime);
position += velocity;
if (Keyboard.GetState().IsKeyDown(key.MoveUp) && prevState.IsKeyUp(key.MoveDown) && prevState.IsKeyUp(key.MoveRight) && prevState.IsKeyUp(key.MoveLeft))
{
foreach (Object2 o in object2List)
{
if (position.Y <= o.position.Y + o.height)
{
velocity.Y = 0;
}
else
{
velocity.Y = -3;
}
}
currentFace = FacePosition.Up;
}
else if (Keyboard.GetState().IsKeyDown(key.MoveDown) && prevState.IsKeyUp(key.MoveUp) && prevState.IsKeyUp(key.MoveRight) && prevState.IsKeyUp(key.MoveLeft))
{
foreach (Object2 o in object2List)
{
if (position.Y + playerWidth >= o.position.Y)
{
velocity.Y = 0;
}
else
{
velocity.Y = 3;
}
}
currentFace = FacePosition.Down;
}
else if (Keyboard.GetState().IsKeyDown(key.MoveRight) && prevState.IsKeyUp(key.MoveDown) && prevState.IsKeyUp(key.MoveUp) && prevState.IsKeyUp(key.MoveLeft))
{
foreach (Object2 o in object2List)
{
if (position.X + playerWidth >= o.position.X)
{
velocity.X = 0;
}
else
{
velocity.X = 3;
}
}
currentFace = FacePosition.Right;
}
else if (Keyboard.GetState().IsKeyDown(key.MoveLeft) && prevState.IsKeyUp(key.MoveDown) && prevState.IsKeyUp(key.MoveRight) && prevState.IsKeyUp(key.MoveUp))
{
foreach (Object2 o in object2List)
{
if (position.X <= o.position.X + o.width)
{
velocity.X = 0;
}
else
{
velocity.X = -3;
}
}
currentFace = FacePosition.Left;
}
else
{
velocity = Vector2.Zero;
}
prevState = Keyboard.GetState();
}
Sorry if this isn't much help, especially the first block of code, that was very much an example of how you could create multiple object2s.

Platform jumping problems with AABB collisions

When my AABB physics engine resolves an intersection, it does so by finding the axis where the penetration is smaller, then "push out" the entity on that axis.
Considering the "jumping moving left" example:
If velocityX is bigger than velocityY, AABB pushes the entity out on the Y axis, effectively stopping the jump (result: the player stops in mid-air).
If velocityX is smaller than velocitY (not shown in diagram), the program works as intended, because AABB pushes the entity out on the X axis.
How can I solve this problem?
Source code:
public void Update()
{
Position += Velocity;
Velocity += World.Gravity;
List<SSSPBody> toCheck = World.SpatialHash.GetNearbyItems(this);
for (int i = 0; i < toCheck.Count; i++)
{
SSSPBody body = toCheck[i];
body.Test.Color = Color.White;
if (body != this && body.Static)
{
float left = (body.CornerMin.X - CornerMax.X);
float right = (body.CornerMax.X - CornerMin.X);
float top = (body.CornerMin.Y - CornerMax.Y);
float bottom = (body.CornerMax.Y - CornerMin.Y);
if (SSSPUtils.AABBIsOverlapping(this, body))
{
body.Test.Color = Color.Yellow;
Vector2 overlapVector = SSSPUtils.AABBGetOverlapVector(left, right, top, bottom);
Position += overlapVector;
}
if (SSSPUtils.AABBIsCollidingTop(this, body))
{
if ((Position.X >= body.CornerMin.X && Position.X <= body.CornerMax.X) &&
(Position.Y + Height/2f == body.Position.Y - body.Height/2f))
{
body.Test.Color = Color.Red;
Velocity = new Vector2(Velocity.X, 0);
}
}
}
}
}
public static bool AABBIsOverlapping(SSSPBody mBody1, SSSPBody mBody2)
{
if(mBody1.CornerMax.X <= mBody2.CornerMin.X || mBody1.CornerMin.X >= mBody2.CornerMax.X)
return false;
if (mBody1.CornerMax.Y <= mBody2.CornerMin.Y || mBody1.CornerMin.Y >= mBody2.CornerMax.Y)
return false;
return true;
}
public static bool AABBIsColliding(SSSPBody mBody1, SSSPBody mBody2)
{
if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
return false;
if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
return false;
return true;
}
public static bool AABBIsCollidingTop(SSSPBody mBody1, SSSPBody mBody2)
{
if (mBody1.CornerMax.X < mBody2.CornerMin.X || mBody1.CornerMin.X > mBody2.CornerMax.X)
return false;
if (mBody1.CornerMax.Y < mBody2.CornerMin.Y || mBody1.CornerMin.Y > mBody2.CornerMax.Y)
return false;
if(mBody1.CornerMax.Y == mBody2.CornerMin.Y)
return true;
return false;
}
public static Vector2 AABBGetOverlapVector(float mLeft, float mRight, float mTop, float mBottom)
{
Vector2 result = new Vector2(0, 0);
if ((mLeft > 0 || mRight < 0) || (mTop > 0 || mBottom < 0))
return result;
if (Math.Abs(mLeft) < mRight)
result.X = mLeft;
else
result.X = mRight;
if (Math.Abs(mTop) < mBottom)
result.Y = mTop;
else
result.Y = mBottom;
if (Math.Abs(result.X) < Math.Abs(result.Y))
result.Y = 0;
else
result.X = 0;
return result;
}
It's hard to read code of other people, but I think this is one possible (purely brainstormed) workaround, although of course I'm not able to test it:
Before the collision detection happens, save the players velocity to some temporary variable.
After you've done your collision response, check if the players X or Y position has been corrected
If X position has been changed, manually reset (as a kind of "safety reset") the players Y velocity to the one that he had before the response.
By the way, what happens with your current code when your players hits the roof while jumping?
I had that same problem. Even the Microsoft platformer starterskit seems to have that bug.
The solution I found so far is to either use multisampling (argh) or to use the movedirection of the object: only move the distance between those 2 objects and no further when a collision is detected (and do that for each axis).
One possible solution I found is sorting the objects before resolving based on the velocity of the player.

Categories

Resources