[solved I think?]Bouncing objects off "walls"

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?

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


if(ball hits the right or the left wall)
{
    velocity.x *= -1; // this will invert the velocity making the ball go the other way on the x axis
}
else if(ball hits the top or bottom wall)
{
    velocity.y *= -1; // this will invert the velocity making the ball go the other way on the y axis
}

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

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.

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 (SvVx + N(-Vy))

If you want to add damping to simulate loss of energy in the collision then multiply Vy by 0.98 (or similar).

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. :smiley:

also thanks orangytang I’m gonna try out both and see which one is easiest to work with. Vector maths + me = new aquantences.

I guess I’m not longer dealing with shapes I’m doing it strictly with segments.

Here’s what I have so far:


	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;
				//Now I have the points of collision on the line
			}
			
		}
	}

	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 ) );
	
		//if(denominator != 0){ //check for parrellel lines
		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 :D.

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?

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…

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??



public class Point2D {
	public float X = 0f, Y = 0f;//Point Locations
	public float angle = 0f;//Point Rotations
		
	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;}
}

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.

I found something which might interest you.

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=30

On that page, scroll down to point 2 “Physically Based Modeling”, where you will see a section called “Collision Response”.

// Json

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 :(.


if(intersectionPoint.X != 0f && intersectionPoint.Y != 0f){//If Lines Intersect
	System.out.println("Collision Has Occured!");
	//Start point of Wall line
	Vector2D collisionV1 = new Vector2D(wall.X - (wall.Width/2), wall.Z - (wall.Depth/2));
	//End point of Wall line
	Vector2D collisionV2 = new Vector2D(wall.X + (wall.Width/2), wall.Z - (wall.Depth/2));
	//Subtract the two wall vectors
	Vector2D surfaceVector = collisionV2.sub(collisionV1);
	//Normalize the two wall vectors
	surfaceVector = surfaceVector.normalize();
				
	//Get the Normal
	Vector2D normal = new Vector2D( ( surfaceVector.Y * -1), surfaceVector.X);
				
	//Start point of intersecting line
	Vector2D velocityVector1 = ballBehavior.toVector2D();
	//End Point of the intersecting line
	Vector2D velocityVector2 = ballBehavior.movePointForward(10f).toVector2D();
	float vectorX = surfaceVector.dotProduct(surfaceVector, velocityVector1);
	float vectorY = surfaceVector.dotProduct(surfaceVector, velocityVector2);
	//Make the VectorY negative as to "flip" the collision
	vectorY = -vectorY;
				
	Vector2D mathVector = normal.mul(vectorY);//To simplify the final operation
	Vector2D bouncedVector = surfaceVector.mul(vectorX).add(mathVector);
				
	//Place on Object on the Point of the reflection
	endPoint.X = bouncedVector.X;
	endPoint.Z = bouncedVector.Y;
}

and maybe I messed up my Vector2D class…


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);
    }
    
}

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).

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):

Stupid image won’t show up…Here’s a link to it…

The 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”.

theya re always 45 degrees off (or so it looks to me).

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.

NeHe says

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.

It sort of feels like the 3 lower images are drawing the normals rather than the “reflection” so to speak.

// Json

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…


if(intersectionPoint.X != 0f && intersectionPoint.Y != 0f){//If Lines Intersect
		//Start point of Wall line
		Vector2D collisionV1 = new Vector2D(wall.X - (wall.Width/2), wall.Z - (wall.Depth/2));
		//End point of Wall line
		Vector2D collisionV2 = new Vector2D(wall.X + (wall.Width/2), wall.Z - (wall.Depth/2));
		//Subtract the two wall vectors
		Vector2D surfaceVector = collisionV2.sub(collisionV1);
		//Normalize the two wall vectors
		surfaceVector = surfaceVector.normalize();
				
		//Get the Normal 
		Vector2D normal = new Vector2D( surfaceVector.Y, -surfaceVector.X);
				
		//Start point of intersecting line
		Vector2D velocityVector1 = ballBehavior.toVector2D();
		//End Point of the intersecting line
		Vector2D velocityVector2 = ballBehavior.movePointForward(10f).toVector2D();
				
		float vectorX = surfaceVector.dotProduct(surfaceVector, velocityVector1);
		float vectorY = surfaceVector.dotProduct(normal, velocityVector2);
		//Make the VectorY negative as to "flip" the collision
		vectorY =  -vectorY;
				
		Vector2D bouncedVector = surfaceVector.mul(vectorX).add(normal.mul(vectorY));
				
		//Place on Object on the Point of the reflection
		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.html

edit #2: should this be moved to game physics?

[quote]H3ckboy if you look at the picture top right hand side, it’s off by over 180 degreees(I think). This is real weird.
[/quote]
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.