So basically, I am doing my first xna game and it's an arkanoid game. My ball right now is a square that rotate.
Unfortunately, it's impossible to correctly detect the collision of a rotated rectangle in xna.
I found thing about scalars but I am only in computer science in college so I don't know about these big maths...
Can anyone direct me in the right way to detect these kind of collision ? or at least to be able to obtain a new rectangle in the right way so that I can detect the collision on this one?
EDIT
I just thought about making my rotating square in a still square and test the collision with the outer square would that be viable ?
If you want to detect a collision of the square ball with the outer rectangle, you need to know the coordinates of the four corners of the ball. Then simply compare these points with the outer rectangle.
If s is the length of the sides of the rectangle. The corners can be calculated like this:
double h = 0.707106781 * s; // Half diagonal
double angle = rotation_angle + 0.25 * Math.PI; // 0.25 * Math.PI = 45 degrees
// inclination of the diagonal.
double x = h * Math.Cos(angle);
double y = h * Math.Sin(angle);
// The four points are
p1x = +x + squareCenterX;
p1y = +y + squareCenterY;
p2x = -y + squareCenterX;
p2y = +x + squareCenterY;
p3x = -x + squareCenterX;
p3y = -y + squareCenterY;
p4x = +y + squareCenterX;
p4y = -x + squareCenterY;
Do you really want your ball to be a square?
Or a simple circle could do?
You could use a collision circle instead, the logic behind the collision is much more simple than rotated squares... (If you really want a square and a pixel-perfect collision, disregard this answer and see Terrance's comment)
if(circle.Center.X - circle.Radius < ScreenBounds.XMin ||
circle.Center.X + circle.Radius > ScreenBounds.XMax ||
circle.Center.Y - circle.Radius < ScreenBounds.YMin ||
circle.Center.Y + circle.Radius > ScreenBounds.YMax)
{
//Ball is partly or entirely outside of the screen
}
This is not really a direct answer to your question, but more of an alternative
Edit: This code assumes that the position of your ball is relative to its center.
Also, you can approximate your rotated square's collision with a collision circle (or a non-rotated square as a matter of fact). The collision won't be pixel perfect, but I think that'll be hardly noticeable. It will also be easier to implement (considering this is your first game).
Related
My issue is that I've been trying to check if a rectangle that is rotated by a certain amount of degrees contain a point, but I wasn't able to calculate that after many attempts with the help of some code samples and examples that I've found online.
What I got is the rectangle (X, Y, Width, Height, Rotation) and the point (X, Y) and I've been trying to create a simple function that lets me instantly calculate that, which would be something something like this:
public bool Contains(Rect Rectangle, float RectangleRotation, Point PointToCheck);
But as I mentioned, I wasn't able to do so, those mathematical calculations that include some formulas I found online are way too much for me to understand.
Could someone help me with calculating this? If you could provide the calculation in C# code form (not formulas) then that would be great! Thanks.
PS: Using the 2D Physics Engine that is available in Unity3D is not a option, my rectangle is not associated with a gameobject that I could attach a 2D collision component to, I need to do this mathematically without the involvement of gameobjects or components.
Edit: I forgot to mention, the rectangle is being rotated by the middle of the rectangle (center/origin).
Rather than checking if the point is in a rotated rectangle, just apply the opposite of the rotation to the point and check if the point is in a normal rectangle. In other words, change your perspective by rotating everything by -RectangleRotation, so that the rectangle does not appear rotated at all.
public bool Contains(Rect rect, float rectAngle, Point point)
{
// rotate around rectangle center by -rectAngle
var s = Math.Sin(-rectAngle);
var c = Math.Cos(-rectAngle);
// set origin to rect center
var newPoint = point - rect.center;
// rotate
newPoint = new Point(newPoint.x * c - newPoint.y * s, newPoint.x * s + newPoint.y * c);
// put origin back
newPoint = newPoint + rect.center;
// check if our transformed point is in the rectangle, which is no longer
// rotated relative to the point
return newPoint.x >= rect.xMin && newPoint.x <= rect.xMax && newPoint.y >= rect.yMin && newPoint.y <= rect.yMax;
}
I have successfully implemented the floor clip plane to measure the distance of left foot to the floor, which is fairly accurate. The problem I have is that as I move away from the camera (i.e. left foot Z axis is increased), the foot distance to the floor changes (increases).
Note: The floor itself is not tilted nor the Kinect stand.
I tested it with Kinect 1 and had the same result. The subject's head height (Y axis) also changes value as I move away or get closer to the camera. It does not matter of the camera is tilted or line of sight. the D value in the FloorClipPlane equation shows a constant number during the test.
A = bodyFrame.FloorClipPlane.X;
B = bodyFrame.FloorClipPlane.Y;
C = bodyFrame.FloorClipPlane.Z;
D = bodyFrame.FloorClipPlane.W;
distanceLeftFoot = A * leftFootPosX + B * leftFootPosY + C * leftFootPosZ + D;
Just to let you know, I have coordinate mapping between depth and colour. Not sure if that has anything to do with the issue.
The FloorClipPlane is expressed in hessian normal form - as explained in the docs. Specifically, your A, B, and C values compromise the unit vector from camera origin (center of the Kinect) to floor plane such that it produces a perpendicular intersection with the floor plane. D is the magnitude of that vector (distance from camera origin to floor plane).
Even if you think the floor is flat and the Kinect is parallel to the ground, you have a perspective warping problem which means the body location (measured in depth space) is going to change as you come closer and further.
To fix this you need to provide as input both your 3D coordinate values and the floor plane, which will then give you back what you want, a measured distance from floor plane to joint:
// j is your joint - left foot or any other joint
float x = j.Position.X;
float y = j.Position.Y;
float z = j.Position.Z;
float distance = (Math.Abs((x * floorPlane.X) + (y * floorPlane.Y) + (z * floorPlane.Z) + floorPlane.W))/((float)Math.Sqrt((Math.Pow(floorPlane.X,2)) + (Math.Pow(floorPlane.Y, 2)) + (Math.Pow(floorPlane.Z, 2))));
I hope this helps you. Can't elaborate further what influence your mapping from depth to color might be doing here without seeing what you are specifically doing
I'm making a 2D platformer that features a dynamic camera. The camera must track 4 players at once so that they're all on the screen. In addition the camera must not move beyond a predefined rectangle boundary. I've tried implementing it but I just can't seem to get the process of zooming the camera so that it's always close as possible to the four objects.
The general algorithm I have so far is
1. Define the viewing space by calculating a 2D axis aligned bounding box using the 4 object positions being tracked and use its center as a camera postion (or averaging)
2. Calculate an orthographic size by using the largest x OR y value using a vector from the camera's position to each object being tracked.
If the camera is beyond the camera's boundary calculate the excess amount and displace in the opposite direction.
This seems simple enough on paper but I can't seem to get a correct working implementation.
Why dont you just take the Average of the 4 players Position and use it as Camera Position, also check if the players are out of boundary and when they are, zoom out.
float x = 0;
float y = 0;
GameObject[] players = new GameObjects[5];
foreach(GameObject _ply in players)
{
x += _ply.transform.position.x;
y += _ply.transform.position.y;
}
x = x/players.Length;
y = y/players.Length;
foreach(GameObject _ply in players)
{
if(_ply.transform.position.x > (x + (Screen.Width / 2)))
//zoom out
if(_ply.transform.position.y > (y + (Screen.Height / 2)))
//zoom out
}
But you have to fix Zoomin.
I have a rectangle.
Its height (RH) is 400.
Its width (RW) is 500.
I have circle.
Its height (CH) is 10.
Its width (CW) is 10.
Its starting location (CX1, CY1) is 20, 20.
The circle has moved.
Its new location (CX2, CY2) is 30, 35.
Assuming my circle continues to move in a straight line.
What is the circle's location when its edge reaches the boundary?
Hopefully you can provide a reusable formula.
Perhaps some C# method with a signature like this?
point GetDest(size itemSize, point itemPos1, point itemPos2, size boundarySize)
I need to calculate what that location WILL be once it arrives - knowing that it is not there yet.
Thank you.
PS: I need this because my application is watching the accelerometer on my Windows Phone. I am calculating the target necessary to animate the motion of the circle inside the rectangle as the user is tilting their device.
It is 1 radius away from the boundar(y/ies).
The answer is X=270 Y=395
first define the slope V as dy/dx =(y2-y1)/(x2-x1). In your example: (35-20)/(30-20)=1.5
the line equation is
y = V * (x-x1) + y1. You are interested in the horizontal locations x at:
y= CH/2 OR y= H-CH/2
so (not code, just math)
if (y2-y1)<0:
x=(CH/2 -y1)/V +x1 10 for your example. OR
if (y2-y1)>0:
x=(H-CH/2 -y1)/V +x1 270 for your example
else (that is: y2==y1)
the upper or lower lines were not hit.
if CH/2 <= x <= W-CH/2 the circle did hit the that upper or lower side: since V>0, we use x=270 and that is within CH/2 and W-CH/2.
So the answer to your question is y=H-CH/2 = 395 , X=270
For the side lines it's similar:
(if (x2-x1)<0)
y=(CH/2 -x1)*V +y1
(if (x2-x1)>0)
y=(W-CH/2 -x1)*V +y1
else (that is: x2==x1)
the side lines were not hit.
if CH/2 <= y <= H-CH/2 the circle did hit that side at that y.
be careful with the trivial cases of completely horizontal or vertical movement so that you don't divide by zero. when calculating V or 1/V. Also deal with the case where the circle did not move at all.
Since you now asked, here's metacode which you should easily be able to convert to a real method. It deals with the special cases too. The input is all the variables you listed in your example. I here use just one symbol for the circle size, since it's a circle not an ellipse.
method returning a pair of doubles getzy(x1,y1,W,H,CH){
if (y2!=y1){ // test for hitting upper or lower edges
Vinverse=(x2-x1)/(y2-y1)
if ((y2-y1)<0){
xout=(CH/2 -y1)*Vinverse +x1
if (CH/2 <= y <= H-CH/2) {
yout=CH/2
return xout,yout
}
}
if ((y2-y1)>0){
xout=(H-CH/2 -y1)*Vinverse +x1
if (CH/2 <= y <= H-CH/2) {
yout=H-CH/2
return xout,yout
}
}
}
// reaching here means upper or lower lines were not hit.
if (x2!=x1){ // test for hitting upper or lower edges
V=(y2-y1)/(x2-x1)
if ((x2-x1)<0){
yout=(CH/2 -x1)*V +y1
if (CH/2 <= x <= W-CH/2) {
xout=CH/2
return xout,yout
}
}
if ((x2-x1)>0){
yout=(H-CH/2 -x1)*V +y1
if (CH/2 <= x <= W-CH/2) {
xout=H-CH/2
return xout,yout
}
}
}
// if you reach here that means the circle does not move...
deal with using exceptions or some other way.
}
It's easy; no calculus required.
Your circle has radius R = CW/2 = CH/2, since the diameter of the circle D = CW = CH.
In order to have the circle touch the vertical edge of the rectangle at a tangent point, you have to move the circle to the right by a distance (W - (CX1 + CW/2))
Likewise, the circle will touch the bottom edge of the rectangle at a tangent point when you move it down by a distance (H - (CY1 + CH/2)).
If you do this in two separate translations (e.g., first to the right by the amount given, then down by the amount given or visa versa), you'll see that the circle will touch both the right hand vertical and the bottom horizontal edges at tangent points.
When the moving circle arrives at a wall (boundary) then it will be tangent at one of four points on the circle, call them N, S, E, and W. You know their initial coordinates.
The points travel in a line with a slope known to you: m=(y2-y1)/(x2-x1); where in your example (x1, y1) - (20,20) and (x2, y2)= (30, 35).
Your problem is to find the trajectory of the first point N, S, E, or W which reaches any wall. The trajectory will be a line with slope m.
You can do this by adding (or subtracting) the direction vector for the line to the point N, S, E, or W, scaled by some t.
For example, N is (20, 15). The direction vector is (x2-x1,y2-y1) = (10, 15). Then (20, 15) + t * (10, 15) will hit the boundary lines at different t's. You can solve for these; for example 20 + t*10 = 0, and 20 + t*10 = 400, etc.
The t that is smallest in magnitude, over all four trajectories, gives you your tangent point.
Not sure its calculus..wouldn't it just be the following:
if y >= 390 then it reached the top edge of the rectangle
if x >= 490 then it reached the right edge of the rectangle
if y <= 0 then it reached the bottom edge of the rectangle
if x <= 0 then it reached the left edge of the rectangle
ok i am trying to get a pool game going in c#/java.
start = back of pool cue(x,y)
end = front of pool cue(x,y)
circles = list of balls (x,y,r)
So every time you move your mouse I update start, end and then I loop through `circles check if it intersects. Then this is my problem I need to figure out what will happen with ball if I hit it at the intersection point( will it go right up down).
How will I do this. I looked at some examples on google but could only find example where they did it with vector and that way over my head....
my first thought was get the angle of the pool cue and from the circle mid point draw a line the same angle but for some reason that is wrong. It might be my GetEnd function
public Point GetEnd(Point start, double angle, int len)
{
double y = start.Y + (len * Math.Sin(angle));
double x = start.X + (len * Math.Cos(angle));
return new Point((int)x, (int)y);
}
I think the angle between the direction where the cue points and the ball moves is:
Math.ASin(a/r)
with a the minimal distance between the ray representing the cue and the center of the ball, and r the radius of the ball.
You obtain a by minimizing a^2 = (Cue.Position+Cue.Direction*Lamda-Ball.Position)^2 for lamda and then calculating the squareroot of that expression.
But I'm too lazy to reformulate that expressions without vectors.