Simulating bounce along contactPoint.normal producing unwanted results

Hey guys,

I’ve been puzzled over this one for a little while and have yet been unable to find a solution to the problem.

Ultimately, I am building a simple arcade style racing game and due to the unrealistic nature of it, I am hardcoding most of the physical properties of the objects. I have come to a problem however with tring to simulate a (purposely unrealistic) bounce, when the car hits an object tagged specifically to cause a bounce when the car hits it.

Here is my code attempting to do so:

	//collision effects
	void OnCollisionEnter(Collision collision)
	{
		//find any collisions with BncObj and Player tagged objects
		foreach(ContactPoint contact in collision.contacts)
		{
			if(contact.otherCollider.tag == "BncObj")
			{
				//bounce the player in the normal direction and break from loop
				isBouncing = true;

				//cast a ray from the contact point along the normal
				Ray contactRay = new Ray(contact.point, contact.normal);
				//get the point, collisionBounceAmount along the ray
				Vector3 target = contactRay.GetPoint(collisionBounceAmount);
				//get the forward direction
				Vector3 dir = target - transform.position;
				
				//build the hashTable
				Hashtable ht = new Hashtable();
				
				ht.Add("amount",dir);
				ht.Add("time",collisionBounceForce);
				ht.Add("oncomplete","setBounceOff");
				ht.Add("easetype","easeOutQuad");
				
				//add the direction of dir over time
				iTween.MoveAdd(gameObject,ht);
				
				break;
			}
		}
	}

Firstly I know using a Ray here is kind of pointless, considering I can simply do dir*collisionBountAmount after normalising the transform.position - contact.normal, however both that method and this method produce the same problem, which is that the point that it moves the object to, is not correct. It’s a bit tricky to explain but here it goes.

Basically, I am testing this by driving the car into a cube tagged as BncObj. Here is what is happening:

When driving into the left side of the cube the car bounces North.

When driving into the North side of the cube the car tries to bounce South (into the cube)

When driving into the right side, the car bounces south.

When driving into the South side of the cube, the car bounces South! (the intended result)

Here is a crude paint image to describe the results further, as if looking directly down onto the cube from a birds-eye view.

What I am ideally trying to do is send the car backwards from the direction that it was going when it collided with the cube.

I have also tried using Vector3.Project, to project a point along the normal of the collision, which also produced identical results.

Any help would be greatly appreciated.

Your calculations seem off to me. If I’ve walked through you code correctly you are doing something like this:

11436-vector.png

Let’s assume the dark blue line is the normal to the surface at the contact point scaled by collisionBounceAmount, and that collisionBounceAmount is small. When you do:

Vector3 target = contactRay.GetPoint(collisionBounceAmount);

You get a point in 3D space (black dot). And when you do this:

Vector3 dir = target - transform.position;

You get the green arrow, which I don’t believe is what you want. If collisionBounceAmount is large, the geometry gets better. But I’m not sure what is going to happen when you do an iTween.MoveAdd() multiple times (once for each contact point). I’m unsure how you’ve defined your unrealistic physics, so I’m not sure what to suggest to fix this. As a starting point, you could just pass contact.normal to the iTweenMoveAdd().

With thanks to @robertbu and a little bit more fiddling I have managed to work out where I was going wrong.

I started drawing debug rays just to physically see what was being considered the normal and ultimately the generated target point. Immediately I realised that a contactPoint.normal is actually the normal of the contactPoint, and not the normal of the face on the mesh where the contact point was located. I realise now I am pretty silly for thinking that this was the case! ha

With this in mind, the actual point at which I want the object to land on once finished “bouncing” away from the contact point is simply just collisionBounceAmount along the contactPoint.normal.

My use of iTween here was also incorrect. MoveAdd attempts to move the object, treating the given Vector3 as the forward direction. Changing this to MoveTo has fixed it because it is now treating the given Vextor3 (which is collisionBounceAmount along the collionPoint.normal) as the destination.

To answer your question robertbu, you’ll notice a break; in the for loop inside of the if statement, so ultimately it will only consider the first contact with an object tagged BncObj and then ignore any other contact points.

For anyone interested, here’s the working code:

	//collision effects
	void OnCollisionEnter(Collision collision)
	{
		//find any collisions with BncObj and Player tagged objects
		foreach(ContactPoint contact in collision.contacts)
		{
			if(contact.otherCollider.tag == "BncObj")
			{
				//bounce the player in the normal direction, at the y height of the player and break from loop
				isBouncing = true;

				Vector3 target = contact.normal;
				//set the target to be collisionBounceAmount along it's direction
				target *= collisionBounceAmount;
				//set the y position to be the same as the player's y position
				target.y = transform.position.y;
				
				//create the hashtable
				Hashtable ht = new Hashtable();
				
				ht.Add("position",target);
				ht.Add("time",collisionBounceForce);
				ht.Add("oncomplete","setBounceOff");
				ht.Add("easetype","easeOutQuad");
				
				//add the direction of dir over time
				iTween.MoveTo(gameObject,ht);
				//iTween.MoveTo(gameObject,contact.normal*collisionBounceAmount,collisionBounceForce);
				break;
			}
		}
	}

Thanks again for the help.