Cakey
Full Member   Posts: 127
|
 |
«
on:
2009-04-14 21:14:14 » |
|
Just like in "pong": A ball/Object hits a wall then rotates correctly back in a different direction.
This really is a simple thing. I understand how to do it with a bit of code, but I guess I just want to learn the math behind it all.
I remember in geometry class using a protractor and a ruler to solve how it's done. Though I'm a little wishy washy on the steps.
I need this in 2-D not 3-D(for once haha).
Got any links? or perhaps a brief explanation?
Thanks a bunch.
edit -
Also what is a "synchronised" class/method and what benefits does it have over a regular class/method?
|
|
|
|
Json
Jr. Member   Posts: 80
|
 |
«
Reply #1 on:
2009-04-15 03:12:06 » |
|
When the ball hits the right or left wall, just make sure you invert the velocity.x on the ball and if it hits the top or bottom wall invert the velocity.y factor. See code example below 1 2 3 4 5 6 7 8
| if(ball hits the right or the left wall) { velocity.x *= -1; } else if(ball hits the top or bottom wall) { velocity.y *= -1; } |
This is just from the top of my head but I think it should work alright and then of course you need to update the position of the ball with its velocity etc. // Json
|
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #2 on:
2009-04-15 12:52:48 » |
|
Thanks for the input, I know how to do it that way. I should have been more specific(as always): This is going to be used on polygon's not just for a rectangular bounded area.
the velocity/speed is actually irrelevant for what I'm doing. I'm writing a "lazer" script and when the "lazer" hits a mirror I want it to reflect back.
|
|
|
|
Games published by our own members! Go get 'em!
|
|
Riven
« League of Dukes » JGO Kernel      Posts: 5870 Medals: 255
Hand over your head.
|
 |
«
Reply #3 on:
2009-04-15 12:57:40 » |
|
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings
|
|
|
Orangy Tang
JGO Kernel      Posts: 2960 Medals: 37
Monkey for a head
|
 |
«
Reply #4 on:
2009-04-15 13:05:18 » |
|
The general idea is that you need to take your input velocity and deconstruct it into two separate vectors - the velocity along the collision surface, and the velocity perpendicular to the surface, then negating the velocity perpendicular and adding them back together again.
- Take the collision surface S of points P1 and P2, and find the surface vector Sv by (P2 - P1), then normalise it. - Find the surface normal N by taking the surface vector Sv, swapping the x and y components and negating one. - Now project the incomming velocity V1 onto the Sv by doing a dot product of the two. The result is the length along Sv (call it Vx) - Repeat by projecting V1 onto N with another dot product, call it Vy. - To 'bounce' you want to flip the velocity perpendicular to the surface, so negate Vy. - So the output velocity V2 is (Sv*Vx + N*(-Vy))
If you want to add damping to simulate loss of energy in the collision then multiply Vy by 0.98 (or similar).
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #5 on:
2009-04-15 14:07:54 » |
|
Hmmm I understand Riven's link thanks. I'm gonna play with this a little bit and once I get it to work I'll post the code.  also thanks orangytang I'm gonna try out both and see which one is easiest to work with. Vector maths + me = new aquantences.
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #6 on:
2009-04-15 16:19:22 » |
|
I guess I'm not longer dealing with shapes I'm doing it strictly with segments. Here's what I have so far: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public void handleKeyboardInput(int ki){ if(ki == KeyEvent.VK_SPACE){ Point2D intersectionPoint = lineIntersectionTest(); if(intersectionPoint != null){ System.out.println(intersectionPoint.X + "\n" + intersectionPoint.Y); endPoint.X = intersectionPoint.X; endPoint.Z = intersectionPoint.Y; } } }
public Point2D lineIntersectionTest(){ double intersectionX, intersectionY; Point2D Line1P1 = ballBehavior; Point2D Line1P2 = ballBehavior.movePointForward(10f); Point2D Line2P1 = new Point2D(wall.X - (wall.Width/2), wall.Z - (wall.Depth/2)); Point2D Line2P2 = new Point2D(wall.X + (wall.Width/2), wall.Z - (wall.Depth/2)); double denominator, numeratorA, numeratorB, r, s;
denominator = ( ( Line2P2.Y - Line2P1.Y ) * ( Line1P2.X - Line1P1.X ) ) - ( ( Line2P2.X - Line2P1.X ) * ( Line1P2.Y - Line1P1.Y ) ); numeratorA = ( ( Line2P2.X - Line2P1.X) * (Line1P1.Y - Line2P1.Y ) ) - ( ( Line2P2.Y - Line2P1.Y) * (Line1P1.X - Line2P1.X ) );
numeratorB = ( (Line1P2.X - Line1P1.X ) * ( Line1P1.Y - Line2P1.Y) ) - ( (Line1P2.Y - Line1P1.Y ) * ( Line1P1.X - Line2P1.X) );
r = ( numeratorA / denominator ) ; s = ( numeratorB / denominator ) ;
if(r >= 0.0f && r <= 1.0f && s >= 0.0f && s <= 1.0f){ intersectionX = r * (Line1P2.X - Line1P1.X) + Line1P1.X; intersectionY = r * (Line1P2.Y - Line1P1.Y) + Line1P1.Y; return new Point2D((float) intersectionX, (float) intersectionY); } return new Point2D(); } |
So far I have found the collision point of the segments  . I only posted the code so you guys know I'm actually trying to sort through this... I've been googling for a while and cannot for the life of my find out how to normalise a segment. Anyone got a link or a brief explanation of what I might have to do? Or is that even possible? Is it just the midpoint? Or should I be trying to calculate the angle the two lines make?
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #7 on:
2009-04-15 17:28:31 » |
|
Oh yeah and inertia/momentum/velocity is pretty irrelvant(I think) because I am dealing with "light" verses an actual object bouncing.
Damn.. I really do need to learn vectors...
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #8 on:
2009-04-15 17:57:18 » |
|
Okay so for a vector I need, X and Y coordinates for the Point. (I already have this in my Point2D Class) And a stored angle Value? Then the dot product aka scalar product is just Let A & B be 2-D Vector's dotProduct(Vector A, Vector B) { return A.X * B.X + A.Y * B.Y; }  Maybe I'm just confused how a line get's represented by a vector( a point + magnitude) does my 2D vector class look okay?? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class Point2D { public float X = 0f, Y = 0f; public float angle = 0f; public Point2D(float x, float y){X = x; Y = y;} public Point2D(float x, float y, float angleIn) {X = x; Y = y; angle = angleIn;} public Point2D(){}; public Point2D movePointForward(float distance){ Point2D newPoint = new Point2D(); double tmpAngle = Math.toRadians(angle); newPoint.X = (float)(Math.cos(tmpAngle) * distance) + X; newPoint.Y = (float)(Math.sin(tmpAngle) * distance) + Y; newPoint.angle = angle; return newPoint; } public static float dotProduct(Point2D A, Point2D B) { return A.X * B.X + A.Y * B.Y; }
public float magnitude() { return (float) Math.sqrt(X * X + Y * Y); }
public void normalize() { float M = magnitude(); if (M > 0f || M < 0f) { X /= M; Y /= M; } } public void wrapAngle(){angle = wrapValue(angle, 360.0f);} public float wrapValue(float in, float max){return in % max;} } |
|
|
|
|
Orangy Tang
JGO Kernel      Posts: 2960 Medals: 37
Monkey for a head
|
 |
«
Reply #9 on:
2009-04-16 05:03:28 » |
|
Okay so for a vector I need, X and Y coordinates for the Point. (I already have this in my Point2D Class) And a stored angle Value?
A vector is just an <x, y> pair, you don't need an angle at all. Personally I think your Point2d is ill-named - a point is just a position, what you've really got is a physics Particle with position and direction. I'd also consider changing your 'angle' into a 'velocity' vector, as it's generally easier to work with and lets you have varying speeds as well.
|
|
|
|
Games published by our own members! Go get 'em!
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #11 on:
2009-04-16 12:31:43 » |
|
Everything makes alot more sense then it did last night... Like alot more sense. But there's a problem with my code, anyone wanna help debug? It is calculating new points but I know their wrong because sometimes they are behind the collision line  . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| if(intersectionPoint.X != 0f && intersectionPoint.Y != 0f){ System.out.println("Collision Has Occured!"); Vector2D collisionV1 = new Vector2D(wall.X - (wall.Width/2), wall.Z - (wall.Depth/2)); Vector2D collisionV2 = new Vector2D(wall.X + (wall.Width/2), wall.Z - (wall.Depth/2)); Vector2D surfaceVector = collisionV2.sub(collisionV1); surfaceVector = surfaceVector.normalize(); Vector2D normal = new Vector2D( ( surfaceVector.Y * -1), surfaceVector.X); Vector2D velocityVector1 = ballBehavior.toVector2D(); Vector2D velocityVector2 = ballBehavior.movePointForward(10f).toVector2D(); float vectorX = surfaceVector.dotProduct(surfaceVector, velocityVector1); float vectorY = surfaceVector.dotProduct(surfaceVector, velocityVector2); vectorY = -vectorY; Vector2D mathVector = normal.mul(vectorY); Vector2D bouncedVector = surfaceVector.mul(vectorX).add(mathVector); endPoint.X = bouncedVector.X; endPoint.Z = bouncedVector.Y; } |
and maybe I messed up my Vector2D class... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class Vector2D { public float X = 0.0f, Y = 0.0f; public float velocity = 1.0f; public Vector2D() {} public Vector2D( float x, float y ) { X = x; Y = y; } public Vector2D( Vector2D a ) { X = a.X; Y = a.Y; } public float length() { return (float) Math.sqrt( (X * X) + (Y * Y) ); }
public Vector2D normalize(){ float len = length(); if (len > 0f || len < 0f) { X /= len; Y /= len; } return new Vector2D(X, Y); } public float dotProduct(Vector2D A, Vector2D B) { return (A.X * B.X) + (A.Y * B.Y); }
public Vector2D add( Vector2D a ) { X += a.X; Y += a.Y; return new Vector2D(X, Y); } public Vector2D sub( Vector2D a ) { X -= a.X; Y -= a.Y; return new Vector2D(X, Y); }
public Vector2D mul( Vector2D vec ) { X *= vec.X; Y *= vec.Y; return new Vector2D(X, Y); }
public Vector2D mul( float scalar ) { X *= scalar; Y *= scalar; return new Vector2D(X, Y); } } |
|
|
|
|
Orangy Tang
JGO Kernel      Posts: 2960 Medals: 37
Monkey for a head
|
 |
«
Reply #12 on:
2009-04-16 12:48:07 » |
|
I'd suggest you actually draw the vectors at the point of the collision in varying colours. It should be pretty easy to see then which one(s) are incorrect and narrow down the problem.
I'm not entirely sure what you're doing with velocityVector1/2 is correct. You seem to be doing a dot product between two different ball velocities and the surface, but you need to do (surface . velocity) and (normal . velocity).
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #13 on:
2009-04-16 12:55:05 » |
|
Will do! Hey by negating the variable for the normal you meant multiplying it by -1 right? And not omitting it? But thanks for helping me through this guys haha. Hopefully one I figure this out I'll have a much better understanding of vectors. Here's a picture of what's going on(I already apologize for the size): <img src=" http://i310.photobucket.com/albums/kk420/SmaerdsDreams/angles.gif"> Stupid image won't show up...Here's a link to it... http://i310.photobucket.com/albums/kk420/SmaerdsDreams/angles.gifThe white box is where you are "aiming". The green box is the colliding "wall". The blue box is where the line is "cast" from. The white line is the path of "lazer".
|
|
|
|
h3ckboy
JGO Kernel      Posts: 1645 Medals: 4
|
 |
«
Reply #14 on:
2009-04-16 13:34:35 » |
|
theya re always 45 degrees off (or so it looks to me).
|
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #15 on:
2009-04-16 14:25:40 » |
|
I discovered that
Vector2D normal = new Vector2D( surfaceVector.Y, surfaceVector.X * -1);
produces the opposite effect as
Vector2D normal = new Vector2D( surfaceVector.Y * -1, surfaceVector.X );
So I'm going to assume that is the faulty line. However, I'm not sure how to fix it, or if that is actually the case...
H3ckboy if you look at the picture top right hand side, it's off by over 180 degreees(I think). This is real weird. edit - JSon sorry I didn't see that link you posted before. I'm looking into it now! Edit#2 - Tried to sift through that NeHe Code and honestly... Either it's poorly written for understanding or I'm a poor reader.
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #16 on:
2009-04-16 14:52:30 » |
|
NeHe says R is the new direction vector I is the old direction vector before the collision N is the Normal at the collision point
The new vector R is calculated as follows:
R= 2*(-I dot N)*N + I
The restriction is that the I and N vectors have to be unit vectors. The velocity vector as used in our examples represents speed and direction. Therefore it can not be plugged into the equation in the place of I, without any transformation. The speed has to be extracted. The speed for such a velocity vector is extracted finding the magnitude of the vector. Once the magnitude is found, the vector can be transformed to a unit vector and plugged into the equation giving the reflection vector R. R shows us now the direction, of the reflected ray, but in order to be used as a velocity vector it must also incorporate the speed. Therefore it gets, multiplied with the magnitude of the original ray, thus resulting in the correct velocity vector.
I am currently taking the normal of just the colliding wall... lemme try to play with this.. If this is even right. Edit: ... Now I'm seriously just so confused... Could anyone lend a hand here? I've been given 3 ways to do this, and have found another two, I bet they all work, but honestly I can't get any of them to work. I promise to post the source-code once it's all good and done just so no one ever has to do this again.
|
|
|
|
Json
Jr. Member   Posts: 80
|
 |
«
Reply #17 on:
2009-04-16 15:00:43 » |
|
It sort of feels like the 3 lower images are drawing the normals rather than the "reflection" so to speak.
// Json
|
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #18 on:
2009-04-16 15:03:59 » |
|
I found out that if my degree of "rotation" is less then 90 then it at least bounces back towards the blue box, but if it's greater than 90, then it bounces through the green wall(with the original code I posted) Just saw orangytangs edit, I'm gonna try to figure it out. Still no dice... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| if(intersectionPoint.X != 0f && intersectionPoint.Y != 0f){ Vector2D collisionV1 = new Vector2D(wall.X - (wall.Width/2), wall.Z - (wall.Depth/2)); Vector2D collisionV2 = new Vector2D(wall.X + (wall.Width/2), wall.Z - (wall.Depth/2)); Vector2D surfaceVector = collisionV2.sub(collisionV1); surfaceVector = surfaceVector.normalize(); Vector2D normal = new Vector2D( surfaceVector.Y, -surfaceVector.X); Vector2D velocityVector1 = ballBehavior.toVector2D(); Vector2D velocityVector2 = ballBehavior.movePointForward(10f).toVector2D(); float vectorX = surfaceVector.dotProduct(surfaceVector, velocityVector1); float vectorY = surfaceVector.dotProduct(normal, velocityVector2); vectorY = -vectorY; Vector2D bouncedVector = surfaceVector.mul(vectorX).add(normal.mul(vectorY)); reflect = new Point2D(bouncedVector.X, bouncedVector.Y); } |
is it because my vectors for my "lines" are just the two end points on my line segments? edit: found a good web-site but can't make programming sense of it... http://www-cs-students.stanford.edu/~adityagp/final/node3.htmledit #2: should this be moved to game physics?
|
|
|
|
h3ckboy
JGO Kernel      Posts: 1645 Medals: 4
|
 |
«
Reply #19 on:
2009-04-17 08:03:50 » |
|
H3ckboy if you look at the picture top right hand side, it's off by over 180 degreees(I think). This is real weird. you are talking bout the reflex. If it is over 180 look at the other side. I think that when you come from above it goes 45 degrees clock-wise and formt he bottom 45 degrees anti-clock-wise.
|
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #20 on:
2009-04-17 15:04:15 » |
|
I see what you mean now h3ckboy. If only I could tweak things by their angles verses vectors...But everyone so far has said this is vector math.
hmm... time to try this from a different "angle" har har har...<cheesey>
I think the problem is this.
The "vectors" I made aren't real vectors. And I still cannot find a way to programmaticly(made-up word) turn a LINE (two end-points{X1,Y1}{X2,Y2}) into a "direction vector". Anyone just wanna help me with the understanding of this, or do I actually already have it? Link's, concepts, anything and everything would be appreciated, right now it's looking like 14 hours of wasted time.
|
|
|
|
h3ckboy
JGO Kernel      Posts: 1645 Medals: 4
|
 |
«
Reply #21 on:
2009-04-17 16:00:57 » |
|
make a class called, "vector 2D" here is what it should have 1 2 3 4 5 6 7 8 9 10 11
| public class Vector2D { public float x; public float y;
public Vector2D(float setX, float setY) { x = setX; y = setY; } } |
yes this is what demon pants gave me  .
|
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #22 on:
2009-04-17 16:05:07 » |
|
here's my vector class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class Vector2D { public float X = 0.0f, Y = 0.0f;
public Vector2D() {} public Vector2D( float x, float y ) { X = x; Y = y; } public Vector2D( Vector2D a ) { X = a.X; Y = a.Y; } public float length() { return (float) Math.sqrt( (X * X) + (Y * Y) ); }
public Vector2D normalize(){ float len = length(); if (len > 0f || len < 0f) { X /= len; Y /= len; } return new Vector2D(X, Y); } public float dotProduct( Vector2D A, Vector2D B) { return (A.X * B.X) + (A.Y * B.Y); }
public Vector2D add( Vector2D a ) { X += a.X; Y += a.Y; return new Vector2D(X, Y); } public Vector2D sub( Vector2D a ) { X -= a.X; Y -= a.Y; return new Vector2D(X, Y); }
public Vector2D mul( Vector2D a ) { X *= a.X; Y *= a.Y; return new Vector2D(X, Y); }
public Vector2D mul( float scalar ) { X *= scalar; Y *= scalar; return new Vector2D(X, Y); } } |
But how do you turn a line into a vector if you only know it's two end points? edit: I found this: In order to write down the vector equation of this line, we need to know two things.
* We have to know the position vector of some point which lies on the line, like a on my diagram. * We have to know a vector which gives the direction of the line, like b in my diagram. This is called a direction vector.
Then the position vector r of any general point P on the line is given by the equation r = a + tb but to be honest... I don't really understand how to program the "direction vector" thing? Edit #2: Now I'm REALLLY confused. For a direction vector you need degrees? http://www.analyzemath.com/vector_calculators/magnitude_direction.htmlso do I need a direction vector, or just a vector, or the vector equation of a line(consisting of both)? edit # 3: Wait so a vectors direction is derived from the line it makes from the origin 0,0?
|
|
|
|
Cakey
Full Member   Posts: 127
|
 |
«
Reply #23 on:
2009-04-17 21:07:24 » |
|
wow... FINALLLY SOLVED. I only tested it on one wall so I'm not 100%, but I think this is it  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| Vector2D collisionV1 = new Vector2D(wall.X - (wall.Width/2), wall.Z - (wall.Depth/2)); Vector2D collisionV2 = new Vector2D(wall.X + (wall.Width/2), wall.Z - (wall.Depth/2)); Vector2D surfaceVector = collisionV2.sub(collisionV1); Vector2D velocityVector1 = ballBehavior.toVector2D(); Vector2D velocityVector2 = ballBehavior.movePointForward(10f).toVector2D(); Vector2D velocityVector = velocityVector2.sub(velocityVector1); surfaceVector = surfaceVector.normalize(); Vector2D normal = new Vector2D( surfaceVector.Y, surfaceVector.X); float vectorX = surfaceVector.dotProduct(surfaceVector, velocityVector); float vectorY = surfaceVector.dotProduct(normal, velocityVector); vectorY = -vectorY; Vector2D mathVector = normal.mul(vectorY);Vector2D bouncedVector = surfaceVector.mul(vectorX).add(mathVector); reflect = new Point2D(bouncedVector.X, bouncedVector.Y); |
|
|
|
|
|