Controlling Position and Rotation, but Collision Detection

I’m working on a rail shooter. Instead of translating and rotating the object every frame, I zero out my ship’s position vector and rotation quaternion, then use Translate and Rotate on my ship’s transform to reset it. That way, I can bound how far the ship deviates from the spline, rotations, etc. The problem is, my collision response doesn’t seem to work. I added a rigid body, and when I apply translate/rotate incrementally, it works fine, however, I can’t bound my position anymore.

Here’s what I have for a script:

#pragma strict

var flip : boolean = false;
var wobble : float = 0.0f;
var lift : float = 0.0f;
var turn : float = 0.0f;
var maxWobble : float = 2.0f;
var maxLift : float = 30.0f;
var maxTurn : float = 30.0f;
var speed : float = 250.0f;
var position : Vector3 = new Vector3(0.0f, 10.0f, 0.0f);
var force : Vector3 = new Vector3(0.0f, 0.0f, 0.0f);
var maxOffset = new Vector2(25.0f, 25.0f);


function Update ()
{
	// choose how to tilt the ship
	if(flip)
	{
		wobble += Time.deltaTime * 1.5707;
		if(wobble >= maxWobble)
		{
			wobble = maxWobble;
			flip = false;
		}
	} else {
		wobble -= Time.deltaTime * 6.26f;
		if(wobble <= -maxWobble)
		{
			wobble = -maxWobble;
			flip = true;
		}
	}
	
	// allow the ship to descend
	if(Input.GetButton("forward_button"))
	{
		lift += Time.deltaTime * 45.0f;
		if(lift >= maxLift) lift = maxLift;
	} else {
		if(lift > 0.0f)
		{
			lift -= lift * Time.deltaTime * 3.14f;
			if(lift < 0.0f) lift = 0.0f;
		}
	}
	
	// allow the ship to ascend
	if(Input.GetButton("back_button"))
	{
		lift -= Time.deltaTime * 45.0f;
		if(lift <= -maxLift) lift = -maxLift;
	} else {
		if(lift < 0.0f)
		{
			lift -= lift * Time.deltaTime * 3.14f;
			if(lift > 0.0f) lift = 0.0f;
		}
	}
	
	// turn the ship left
	if(Input.GetButton("left_button"))
	{
		turn -= Time.deltaTime * 45.0f;
		if(turn <= -maxTurn) turn = -maxTurn;
	} else {
		if(turn < 0.0f)
		{
			turn -= turn * Time.deltaTime * 3.14f;
			if(turn > 0.0f) turn = 0.0f;
		}
	}
	
	// turn the ship right
	if(Input.GetButton("right_button"))
	{
		turn += Time.deltaTime * 45.0f;
		if(turn >= maxTurn) turn = maxTurn;
	} else {
		if(turn > 0.0f)
		{
			turn -= turn * Time.deltaTime * 3.14f;
			if(turn < 0.0f) turn = 0.0f;
		}
	}
	
	// update the position
	position.x += Mathf.Sin(turn / 180.0f) * speed * Time.deltaTime;
	position.y -= Mathf.Sin(lift / 180.0f) * speed * Time.deltaTime;
	//position.z += speed * Time.deltaTime;
	
	// bound the position
	if(position.x < -maxOffset.x) position.x = -maxOffset.x;
	if(position.x >  maxOffset.x) position.x =  maxOffset.x;
	if(position.y < -maxOffset.y) position.y = -maxOffset.y;
	if(position.y >  maxOffset.y) position.y =  maxOffset.y;
	
	// reset rotation
	transform.position = Vector3.zero;
	transform.rotation = Quaternion.identity;
	
	// apply position and rotation
	transform.Translate(position);
	transform.Rotate(Vector3(0.0f, 1.0f, 0.0f), turn);
	transform.Rotate(Vector3(1.0f, 0.0f, 0.0f), lift);
	transform.Rotate(Vector3(0.0f, 0.0f, 1.0f), wobble - turn);
}

The code moves and rotates my ship exactly as I want, and bounds the position and rotation correctly. Two problems, however: collision response doesn’t work, and I’m not sure if this is efficient (just started Unity3D last night). I believe writing JavaScript code should be like writing shaders: keep them as lean as possible!

My goal is to have my ship slide along the bottom of the ground if it’s smooth, but if it collides into an object such as a wall, the ship will respond to the collision by processing a shaking animation (based on manipulating transform values, and not modeled animation), and taking damage, and then continue going through the wall.

I’ll do most of the collision response actions by checking the collider collision callbacks in the script, but getting the object to slide along certain objects such as terrain is where I’m stuck.

I have some bad news for you…

you are probably gonna have to re-write this script… i say probably because you dont necessarily need to use forces to do movement if there is only going to be one ship.

The problem is, using Transform.Translate/Rotate is expensive and the wrong way to move rigidbodies. Of course using forces is a lot harder to get right.

You should be using functions such as AddForce to do the movement.

If you stick with Translate, you are going to end up with jittery movement on collisions, and you may even push through colliders

I was wondering if I’d have to rewrite my script. Add forces makes sense since net force + collision detection would result in the correct response.

What I’ll try is modifying the force, and if I want to bound the position, I’ll bound it accordingly, and see if that causes any issues.