Ball gets stuck when colliding with Rectangle - c#

A new problem i have at the moment is sometimes when the ball is bouncing around the screen, it may all of a sudden get stuck colliding with a rectangle, so it may hit a spot between the rectangle and the side of the screen. This sometimes results in either: a) the ball looks like it's shaking or something, which i am assuming as it's still colliding with the rectangle, it's velocity (as i have defined it) is constantly inversing... but it's still stuck... (that's what i cant solve... lol :( ), or b) when the ball collides with the rectangle, it starts to move along the edge of the rectangle and goes back and forth but it continues to do this... (so it's basically stuck moving just along the edge).
I have uploaded a video to youtube showing this in action (btw... the ball gets stuck and goes up and down the right side of the screen and then starts going along the top edge of the white rectangle and then eventually bounces off into oblivion... well basically frees itself, which is kind of ok but then if you wait 5 more seconds, it repeats this process)
http://www.youtube.com/watch?v=3qfpgtoWbIU&feature=youtu.be
the code i am using for collision detection with the rectangle is:
if (theBall.GetRectangle.Bottom >= cornerSquare.GetRectangle.Top && theBall.GetRectangle.Bottom <= cornerSquare.GetRectangle.Bottom)
{
theBall.pVelocity.Y = -theBall.pVelocity.Y;
}
thats for detection if the ball hit's the top of the rectangle.
detection with the right side of the screen is:
if (pPosition.X + pTexture.Width >= screenWidth)
{
pVelocity.X = -pVelocity.X;
}
I hope someone has a simple and effective solution to this as i just want to 'be done' with all this collision detection nonsense lol... as it's taking up most of my time whilst i could be alot more productive doing other parts of the game.
Thanks for reading, taking the time to read, taking the time to help.... ETC.... :D

Try to check for collision first using a calculated test-rectangle.
For example the ball moves for Vector2(1, 1) per Update. Find out where the Rectangle for collision WOULD be at the next step BEFORE moving.
int nextPosX = currRect.X + (int)movementVector.X;
int nextPosY = currRect.Y + (int)movementVector.Y;
// find out where the rectangle would be after this update:
Rectangle nextStepsCollisionRect = new Rectangle(nextPosX, nextPosY, width, height);
// check if the test rectangle would collide:
if( collisionTest(nextStepsCollisionRect, sideWall) )
{
// do not move the intended way!
// invert X and recalc with pre-calculated rectangle again...
} else {
// no collision. now move the caculated way:
ball.CollisionRectangle = nextStepsCollisionRect;
}
This is a quite simple way. Use "ray tracing" if the ball is a very fast bullet (just to be mentioned).

If your ball is stuck along the edge you can simply bring the ball position to its previuos position before the collision (the one it had in the previous frame), in this way you change its velocity and ensure that the ball is not colliding anymore, this should do the trick.
You can achieve this by subtracting ball speed to ball position.

Related

Getting a Model to Clamp to the Camera in 3D

I'm trying to get a 3D model that I've implemented into Monogame (Xna 4.0) code to constantly be in the bottom right of the screen, it's a gun - basic pistol model, there's nothing fancy - doesn't even have textures! But I can't figure it out, I've tried some maths to get it to stay there, but the problem is that the X and Z offset I set is hard-coded so when the player rotates the camera, while the pistol rotates to face the new LookAt, the actual model doesn't move position so it goes out of sight very quickly.
It's been a long road for a pretty pointless 3D game for an A-Level (Highschool equivalent I suppose) course in computer science which I'm making in Monogame Xna to rake in those complexity marks, but I've got to the last stretch, I need to get my fbx model to sit like the player is holding it in the bottom right of the screen. Right now, if it sits in the centre of the screen, there's not much notice - however, if I increase my X or Z offset to position it where I want, when you begin to rotate your camera it falls behind the camera or goes in a massive circle around the camera which breaks immersion (despite how silly it sounds it really bugs me).
After the simple way didn't work, I tried attaching it to the BoundingBox that the current camera is using: Still left a gap, tried a BoundingSphere to see if I could get it to move around the sphere's edge and follow the player that way: No luck. Yet.
tl;dr I've tried attaching gun to BoundingBox, BoundingSphere and regular Vector Positioning to no success.
if (pausedGame == false)
{
camera.UpdateCamera(gameTime);
if (carryingWeapon)
{
weapons[weaponToCarry].SetRotationMatrix(Matrix.CreateRotationX(camera.GetCameraRotation().X), Matrix.CreateRotationY(camera.GetCameraRotation().Y));
weapons[weaponToCarry].SetPosition(camera.weaponSlot.Center + camera.GetLookAtOffSet());
//Debug.WriteLine(weapons[weaponToCarry].Position);
//Debug.WriteLine(camera.Position);
}
CheckCollision();
AIMovement();
UpdateVisitedNodes(updatedNodes);
}
that was my update for it, simple setting position and rotation of model. The 'weaponslot.Centre' is due to the fact that right now I left on using BoundingSphere so that piece of code is still in there.
else if (_state == ItemState.Dynamic)
{
foreach (var mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
effect.World = Matrix.CreateScale(SCALE, SCALE, SCALE) * rotationMatrix *
Matrix.CreateTranslation(position);
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
this is my draw for the actual item, it's nothing fancy.
Like you can imagine, I want it to be locked in the bottom right of the frustum and moves it's position according to where the player is looking themselves. Right now the positioning of the item is really messed up - any conceptual help is welcome! Thanks.
What I would do is parenting the gun to the camera (it's done that way in engines like unity as well).
You would need to do that by yourself in mono (I think) - the basic principle is to first transform the gun relative to the cam and multiply with the cameras World-Matrix afterwards - this also means to have the guns position relative to the camera
gun.worldmatrix = Matrix.CreateTranslation(gun.position) * camera.world;
You now just move and rotate the camera and the gun keeps in relative position to the camera. Remember: The guns position/(rotation) has to be relative to the camera in that case.
The important thing is just the order in which you multiply the matrices (haven't tried it, hopefully I got it right above)

Physics Engine (Collision Detection C#, GDI+)

I'm currently working on a 2D Game Engine in C# using GDI+ and have gotten to the point where I want to add simple collision detection.
So far, I can check whether or not my player has intersected with another game object using the code below:
public static bool IntersectGameObject(GameObject a, GameObject b)
{
Rectangle rect1 = new Rectangle((int)a.Position.X, (int)a.Position.Y, a.Sprite.Bitmap.Width, a.Sprite.Bitmap.Height);
Rectangle rect2 = new Rectangle((int)b.Position.X, (int)b.Position.Y, b.Sprite.Bitmap.Width, b.Sprite.Bitmap.Height);
return rect1.IntersectsWith(rect2);
}
That's fantastic and I'm happy that I've gotten this far, however I wish to find out whether or not my player has intersected with the top, bottom, left or right side of a game object so that I can stop my player from moving in that direction if say... he collides with a wall. How would I go about doing this? Can some one please help me :)
By the way, game objects have Bitmaps, that are all 32 * 32 pixels, so i don't need per pixel collision
Thank you in advance :)
Computing whether two rectangles intersect is just a matter of a few comparisons (I know you're already using IntersectsWith):
if (Left > other.Right) return false;
if (Right < other.Left) return false;
if (Top > other.Bottom) return false;
if (Bottom < other.Top) return false;
return true;
To determine the direction of the collision, you'll have to take into account the possibility that:
one rectangle completely contains the other (collides in no direction)
it might create a "plus" figure (collides in all directions)
one corner of the rectangle could intersect with a corner of other corner (collides in two directions)
Anyway, to determine whether it has collided on the left side:
if (Right > other.Left && Right < other.Right && Left < other.Left)
{
// the right side of "this" rectangle is INSIDE the other
// and the left side of "this" rectangle is to the left of it
}
Last but not least, if you're computing this frame by frame, there's the possibility that an object might "jump over" the other. For more realistic physics you'd have to keep track of time and compute when it would intersect with (each edge of) the rectangle.
If you're processing frame by frame, a good choice could be storing the previous position P0x,P0y and the current position P1x,P1y.
Then, you can calculate a vector Vx,Vy and you can calculate the intersection point Ix,Iy. So you can get a more precise information about the collision.
If you need collision detection you need a rigidbody, you normally move rigidbodies with physics. As far as I saw, it's possible to live problem with above code snippet. If your moving them with transform move you should mark as is kinematic. That means it will not be moved by physics but by transform.
A kinematic rigidbody which you want to move should be done during FixedUpdate to apply collisions properly.
if you would like to know which side you hit you may raycast to the object
This code snippet gives an example that shows a raycast you could perform on collision. Ultimately, which game engine have you been using?
//this ray will generate a vector which points from the center of
//the falling object TO object hit. You subtract where you want to go from where you are
Ray MyRay = ObjectHit.position - ObjectFalling.position;
//this will declare a variable which will store information about the object hit
raycasthit MyRayHit;
//this is the actual raycast
raycast(MyRay, out MyRayHit);
//this will get the normal of the point hit, if you dont understand what a normal is
//wikipedia is your friend, its a simple idea, its a line which is tangent to a plane
vector3 MyNormal = MyRayHit.normal;
//this will convert that normal from being relative to global axis to relative to an
//objects local axis
MyNormal = MyRayHit.transform.transformdirection(MyNormal);
//this next line will compare the normal hit to the normals of each plane to find the
//side hit
if(MyNormal == MyRayHit.transform.up)
{
you hit the top plane, act accordingly
}
//important note the use of the '-' sign this inverts the direction, -up == down. Down doesn't exist as a stored direction, you invert up to get it.
if(MyNormal == -MyRayHit.transform.up)
{
you hit the bottom plane act accordingly
}
if(MyNormal == MyRayHit.transform.right)
{
hit right
}
//note the '-' sign converting right to left
if(MyNormal == -MyRayHit.transform.right)
{
hit left
}
Wouldn't it be an option to have 4 different objects each one on 1 side on your player object so depending on which side intersects with game object you could know which movement direction to prevent ?

Match an object's rotation to that of another object's relative rotation

I tried posting this in the unity forums, but it's been stuck awaiting moderation, so I'm posting it here in hopes of getting some more immediate feedback.
I have 4 objects, two planes and two arrows. One arrow points at one of the planes, and I want the second arrow to match the first arrow, but relative to the second plane. What I mean by this, is if the first arrow is moved 1 unit to the right relative to the first plane, the second arrow should move 1 unit to the right relative to the second plane. I have gotten the positions to work out correctly, but I can't figure out how to match the rotations. Some axes of rotations work correctly some of the time, but once one of the planes are rotated, the second arrow's rotation gets more out of sync with the first.
Here's the code that I'm using to test this, with the best I could figure out:
[ExecuteInEditMode]
public class RotationTest : MonoBehaviour
{
public GameObject target;
public GameObject camera;
public GameObject arrow;
void OnWillRenderObject()
{
if (!target || !camera || !arrow) return;
arrow.transform.position = target.transform.TransformPoint(transform.InverseTransformPoint(camera.transform.position));
//arrow.transform.rotation = Quaternion.Inverse(camera.transform.rotation) * transform.rotation * Quaternion.Inverse(target.transform.rotation);
//arrow.transform.eulerAngles = new Vector3(arrow.transform.eulerAngles.x, -arrow.transform.eulerAngles.y, arrow.transform.eulerAngles.z);
arrow.transform.eulerAngles = (target.transform.eulerAngles - transform.eulerAngles) + camera.transform.eulerAngles;
}
}
I put this script on the first plane, the first arrow is 'camera', the second plane is 'target', the second arrow is 'arrow'. When both planes are aligned exactly, the second arrow should be exactly the same position and rotation as the first. The commented out lines are the first thing I tried, the uncommented line is the next closest thing I got to work, but it only works correctly when the planes are rotated about the Y axis, and mess up when any other axis on the plane is rotated.
When both planes are facing the same direction, simply setting the rotation of the second arrow to the first arrow's rotation works correctly, but once the first plane is rotated this method falls apart.
I've been at this for quite a while, trying different combinations of Quaternion multiplications and differences of eulerAngles, but I can't seem to figure it out. Any help at this point is much appreciated.
Edit: Here are a few images depicting what I'd like to happen, and what is actually happening with the current script: http://imgur.com/a/MVI8x
The first three pictures show what is occurring when both planes have the same rotation (the arrow positions and rotations work correctly in this case, as I stated earlier). The 4th picture shows what happens (and should happen) when the plane is rotated about the Y axis. The blue arrow moves and rotates to look at the same point on the blue plane that the green arrow is now looking at the green plane. The last two pictures show what the blue arrow should do, but as can be seen, is rotating in odd directions. I'm testing this purely in the editor, so when I move or rotate any object, the blue arrow will respond immediately.
You can always just set the arrow's rotations equal to each other, and as long as neither is parented to anything else, they will always be exactly equal, so long as the models themselves have been authored with the same axis point and initial rotation.
public GameObject arrow1;
public GameObject arrow2;
void Update(){
arrow2.transform.rotation = arrow1.transform.rotation;
}
EDIT:
If that's not working, how are you rotating the first arrow? Is it using transform.LookAt?
When I run into rotation issues it's usually a local vs. global issue. Maybe try:
void Update(){
arrow2.transform.localRotation = arrow1.transform.localRotation;
}
Or maybe I don't understand what you're actually trying to achieve and a diagram could help clarify.

Different method for collision detection using faces of a rectangle

I have been working on and off of a certain game I'm making (trying to get it finished!) and a problem that has been unsolved for a while in it is the collision detection between a ball and a square.
Basically what I want to happen eventually is depending on the angle/way the rectangle is facing, I want the ball to bounce of it accordingly (I know I could just inverse the ball direction before/as it hit the square).
At the moment though, my current problem is trying to inverse the correct X and Y components depending on the side/face that the ball collides with the square, e.g. if the ball hits the right side of the square, then I need to inverse the ball's X component.
This doesn't seem to work and I was wondering if I could somehow label each side of the rectangle, in terms of for the top of it label that 'face 1' or something, then for the right side of it 'face 2' or 'side 2', etc...
I have provided some code below (this is the code I'm using now):
//(collision with right side of square)
if (theBall.GetRectangle.Left <= thePaddle.GetRectangle.Right)
{
theBall.pVelocity.X = -theBall.pVelocity.X;
}
//(collision with bottom of square)
if (theBall.GetRectangle.Top <= thePaddle.GetRectangle.Bottom)
{
theBall.pVelocity.Y = -theBall.pVelocity.Y;
}
I have written the code for the other 2 sides of the rectangle but they are just the opposite of the two above, i.e. for collision with top of rectangle = opposite of bottom, etc.
EDIT: the object I am checking against if the ball has collided with DOES NOT move, I mean it only rotates... so I don't know if this is important (it probably is, therefore I apologise for missing this info out at the start).
EDIT # 23:36: ok, I have tried something.... and it hasn't worked... :(
public Vector2 DistBetweenBallAndBlock(Paddle thePaddle, Ball theBall)
{
Vector2 centreOfBall = new Vector2(theBall.Texture.Width / 2, theBall.Texture.Height / 2);
float distX = thePaddle.Position.X - centreOfBall.X;
float distY = thePaddle.Position.Y - centreOfBall.Y;
if (distX < 0)
{
distX = -distX;
}
if (distY < 0)
{
distY = -distY;
}
return new Vector2(distX, distY);
}
I have then tried to just print the result just to get an idea of what's going on and what sort of values are being output:
Vector2 a = ball.DistBetweenBallAndBlock(paddle1, ball);
angleOfPaddle = Math.Atan2(a.Y, a.X);
I then just print this value to screen, however I am getting the same result of 0.63...
To detect a collision between Rectangles you could use Rectangle.Intersect method, instead of checking the objects' sides.
And to detect which side of the rectangle is hit, you can compute the Vector2 between the ball center and the rectangle center. Getting its angle with Math.Atan2 you can easily know which face of the rectangle has been hit.
Looked up some Vector stuff, based on my comment.
Collision Style
The optimal way of colliding with a circular object is to collide using a vector between it and the nearest point of the object you're checking against. If the distance is less than or equal to the radius of the circle, there is a collision. The advantages of this method are that you don't have to keep track of a rectangle, you get circular collision, and you get the angle of the collision from the vector.
How You Do It
I'll assume you have some strategy to keep from considering every object every frame, and keep to the basic problem. Your paddle has 4 vertices, one for each corner. Because your ball is essentially a vertex with a picture drawn over it, you can easily check the distance between the ball and each corner of your paddle. Two will be nearest. From there, it's just a matter of finding out if that edge collides. I found a solution to that here, which includes a nice formula.
Does that help?

Collision response 2d

Problem:
Problem http://img684.imageshack.us/img684/5486/prob1b.png
Problem http://img810.imageshack.us/img810/3157/prob3.png
Green block is the player and the gray block is the static brick
When jumping up against a tile the player is pushed to the left/right when it stands near the edge of the colliding tile. This probably happens because the jump velocity up is bigger than the x-movement (which may even be 0) and thus the player is corrected over the x-axis...
The pseudo-code goes like this:
1: get colliding tiles around player
2: foreach colliding tile:
{
2a: get intersection depth
2b: correct player location with the smallest correction-axis
(example: if (Math.Abs(X) > Math.Abs(Y) Then correct Y value. Else
correct X value)
// Below is some other pseudo-code which should not be part of the problem:
2c: if collision is with the top side of the player: cancel any jumps
2d: if collision is with the bottom side of the player:
IsStandingOnGround = true;
}
Some Code:
foreach (Stone stone in collidingStones)
{
#region Collision Response
if (DrawRect.Intersects(stone.CollisionRect)) // DrawRect is the players collision rectangle
{
//warning bug is in this if-statement. causes the player to be adjusted and go trough neighboar tiles and such
Vector2 correction = Collision.CalculateMinimumTranslationDistance(DrawRect, stone.CollisionRect);
if (Math.Abs(correction.X) > Math.Abs(correction.Y))
{
Location += new Vector2(correction.X, 0);
}
else
{
Location += new Vector2(0, correction.Y);
}
Interesting question, I was developing a game in Delphi some years ago and I ran into the same problems. Couple of points:
You should correct both X and Y on collision. Correcting only X or Y will look unnatural with high velocities (more than ~3px/update).
The kind of collision detection that you are doing would work with rectangularly-filled tiles, but if you had irregular tiles (like a triangle for a slope-section) then it would be impossible to calculate the correction values for collision.
In the end I made an engine in which each tile had the bitmap (the actual visible graphics) and something I called a freemap, which was a black&white bitmap which represented map of free space within a tile. Then I wrote collision functions that operated first in the tile-space (to determine the tiles that collide with the player) then in the bitmap of the tile.
When moving the player you calculate the next point based on the player velocity, and then you test each point along the line between the current position and the calculated next position. If on that line you run into an obstacle then you stop the player at that point.

Categories