Implementing simple bounce physics

Hi,

I am working on a 2D top-down shooter and I am not using physics in my game because of the way my player ship moves does not work well with the laws of physics. But when the player collides with asteroids (and possible other things) I want some physics to occur and make the player bounce off the asteroid (the asteroid is in a fixed position and does not move or bounce). I have to do this math and apply it manually to the player ship because mixing the physics engine and my manual movement code does not work, but I do not know how to make this work and all my attempts have failed miserably.

I move my player ship by creating a movement Vector2 from input and forces (acceleration and mass) with this code (I can provide the whole code if needed):

transform.Translate(movement);

and I simply set the rotation of the player ship with this code:

transform.Rotate (rotationVector);

Now when the ship collides with something, I would like the ship to bounce off that something in a somewhat realistic way so that its course and rotation gets altered, something like this image (not showing rotation, but I think you know what I mean):

The left example is player ships course if not affected by collision and bounce, and the right is a example of effect of collision/bounce. A simple drawing that might not add anything to the understanding but what I wanted to illustrate is that the bounce effect is something that must be added to the ships current momentum and work against/with the force of the engine (player input), and this bounce force of course has be something that is affecting the ship over time.

My idea was to have a OnTriggerEnter2D that calculate the angle between the asteroid/something and the ship, convert this angle to a Vector2 with a given/calculated magnitude and each frame/Update add this bounce vector to the movement vector and also decrese the magnitude of the bounce vector each frame. But this produces strange results, and also rotation is of course not affected by this.

Here is how I create the rotation and movement vector (inputX and inputY are taken from Input.GetAxis(“Horizontal”) and Input.GetAxis(“Vertical”)):

void MakeMovement(float inputX, float inputY) {
	float fps = 1.0f / Time.deltaTime;
	float speedStepDivider = fps / acceleration * 2;
	float shipSpeed = speed;

	// Rotation
	float correctedRotateSpeed = 0;
	if (inputX > minValX) {
		float maxPlayerRotation = agility * inputX;
		if(currentPlayerRotation < maxPlayerRotation) {
			currentPlayerRotation = currentPlayerRotation + (maxPlayerRotation / speedStepDivider);
			if(currentPlayerRotation > maxPlayerRotation) {
				currentPlayerRotation = maxPlayerRotation;
			}
		}
	} else if (inputX < (minValX * -1)) {
		float maxPlayerRotation = agility * inputX;
		if(currentPlayerRotation > maxPlayerRotation) {
			currentPlayerRotation = currentPlayerRotation + (maxPlayerRotation / speedStepDivider);
			if(currentPlayerRotation < maxPlayerRotation) {
				currentPlayerRotation = maxPlayerRotation;
			}
		}
	} else {
		float maxPlayerRotation = agility;
		if(currentPlayerRotation > 0.0f) {
			currentPlayerRotation = currentPlayerRotation - (maxPlayerRotation / speedStepDivider);
			if(currentPlayerRotation < 0.0f) {
				currentPlayerRotation = 0.0f;
			}
		} else if(currentPlayerRotation < 0.0f) {
			currentPlayerRotation = currentPlayerRotation + (maxPlayerRotation / speedStepDivider);
			if(currentPlayerRotation > 0.0f) {
				currentPlayerRotation = 0.0f;
			}
		}
	}
	correctedRotateSpeed = currentPlayerRotation * -1;
	Vector3 rotationVector = new Vector3 (0, 0, correctedRotateSpeed);
	rotationVector *= Time.deltaTime;
	transform.Rotate (rotationVector);

	// Movement
	if (inputY > minValY) {
		float maxPlayerSpeed = shipSpeed * inputY;
		if(currentPlayerSpeed < maxPlayerSpeed) {
			currentPlayerSpeed = currentPlayerSpeed + (maxPlayerSpeed / speedStepDivider);
			if(currentPlayerSpeed > maxPlayerSpeed) {
				currentPlayerSpeed = maxPlayerSpeed;
			}
		}
	} else if (inputY < (minValY * -1) && currentPlayerSpeed <= 0) {
		float maxPlayerSpeed = ((shipSpeed * inputY) / 2);
		if(currentPlayerSpeed > maxPlayerSpeed) {
			currentPlayerSpeed = currentPlayerSpeed + (maxPlayerSpeed / speedStepDivider);
			if(currentPlayerSpeed < maxPlayerSpeed) {
				currentPlayerSpeed = maxPlayerSpeed;
			}
		}
	} else {
		float maxPlayerSpeed = shipSpeed;
		if(currentPlayerSpeed > 0.0f) {
			currentPlayerSpeed = currentPlayerSpeed - (maxPlayerSpeed / speedStepDivider);
			if(currentPlayerSpeed < 0.0f) {
				currentPlayerSpeed = 0.0f;
			}
		} else if(currentPlayerSpeed < 0.0f) {
			currentPlayerSpeed = currentPlayerSpeed + (maxPlayerSpeed / speedStepDivider);
			if(currentPlayerSpeed > 0.0f) {
				currentPlayerSpeed = 0.0f;
			}
		}
	}

	Vector2 movement = new Vector2(0, currentPlayerSpeed);
	movement *= Time.deltaTime;

	transform.Translate(movement);
}

I successfully detect collision with the following code, but this is where my ideas run out:

void OnTriggerEnter2D(Collider2D otherCollider) {
	// Is this a asteroid?
	Asteroid asteroid = otherCollider.gameObject.GetComponent<Asteroid>();
	if (asteroid != null) {
		bounceAngle = Mathf.Deg2Rad * Vector2.Angle(otherCollider.transform.position, transform.position);
		bounceMagnitude = 1;//fix me
	}
}

Am I on the right track here, or how can I make this work?

Thank you
Søren

I’m kind of confused, are you doing this in 2D or 3D ?


Alright, this might be a long process…

The solution i’m thinking of requires that the movement (and rotation) script change quite “drastically” (fault of a better term).

But before I get to this, I might have figured a way to get something relatively close to what you want:

Is your “angle” code doing what you want ?, does your ship end up facing exactly where you want it to ?
If it does, i believe your movement code actually makes your ship go forward only, right ?

Here’s what i have in mind : (assuming rotation wasn’t working)

	void OnTriggerEnter2D(Collider2D otherCollider) {
		// Is this a asteroid?
		Asteroid asteroid = otherCollider.gameObject.GetComponent<Asteroid>();
		if (asteroid != null) {
			Vector3 direction = (otherCollider.transform.position - transform.position).normalized;
			Quaternion lookRotation = Quaternion.LookRotation(direction);
			transform.rotation = lookRotation;
			currentPlayerSpeed = currentPlayerSpeed/2; //technically you can put anything that feels real here.
		}
	}

Now technically, what this should do is turn your player to face the opposite direction from the collision, and half his forward speed.

I don’t really believe this will work out ok, (or work at all to be honest) but if you’re satisfied with that, I won’t go any further.

If you aren’t, I’ll develop on the other solution I have.