Banking an object in relation to its turn

Hi,

I have a script (mouse look) that I have altered to achieve the movement in the game I am developing but I cannot get the object to bank when I turn. Ideally I would like the object to tilt up to say 15 degrees and when the controller returns to central have then character follow suit. The code I have rotates the character through 360 degrees with a camera that follows behind. The problem I have is that by using the turn angle I cannot return to up right until I am facing the original direction again as the tilt is out of kilter...

Code below:

    var keyboardControls : boolean = true;
    var sensitivityX : float = 15;
    var sensitivityY : float = 15;

    var minimumX : float = -360;
    var maximumX : float = 360;

    var minimumY : float = -30;
    var maximumY : float = 30;

    var rotationZ : float = 0;
    var rotationY : float = 0;
    var rotationAY : float = 0;

    private var originalRotation : Quaternion;

    function Update () {
    if (keyboardControls) {
    rotationZ += -Input.GetAxis("Mouse X");
    rotationY = ClampAngleY (rotationZ, minimumY, maximumY);
    rotationAY += Input.GetAxis("Mouse X") * maximumY;
                    }
    else {
    rotationZ += -Input.acceleration.y * sensitivityX;
    rotationZ = ClampAngle (rotationZ, minimumX, maximumX);
    rotationAY += Input.acceleration.y * maximumY;
    }

    var target = Quaternion.Euler( 0, rotationAY, rotationY);
    transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * sensitivityY);

    var xQuaternion = Quaternion.AngleAxis (rotationZ, Vector3.up);
    var yQuaternion = Quaternion.AngleAxis (rotationY, Vector3.forward);

transform.localRotation = originalRotation * xQuaternion * yQuaternion;
    }

    function Start () {
    if (rigidbody)
    rigidbody.freezeRotation = true;
    originalRotation = transform.localRotation;
    }

    static function ClampAngle (angle : float, min : float, max : float) : float {
    if (angle < -360.0)
    angle += 360.0;
    if (angle > 360.0)
    angle -= 360.0;
    return Mathf.Clamp (angle, min, max);
    }

    static function ClampAngleY (angle : float, min : float, max : float) : float {
    if (angle < -30.0)
    angle += 30.0;
    if (angle > 30.0)
    angle -= 30.0;
    return Mathf.Clamp (angle, min, max);
    }

Should I look to implement a better way to control the movement - its supposed to be a free roaming game so I thought using the mouse look to determine direction was a good way to go...

Ideas or fixes greatly welcomed...

Regards

The simple answer is to get how much you are turning by and then bank by some amount relative to that, returning to your original bank rotation when you are not turning any longer.

EDIT 12/02/2010: I spent some time and tested some settings. If you want to add easing in, feel free, but something like this works fairly nicely:

var keyboardControls : boolean = true;
var mouseControls : boolean = false;

//The max variables are to make the rotation framerate independent.
//You could alternatively do the work in FixedUpdate,
//but the controls might be less responsive there.

//Tilt
var maxTilt : float = 180.0f; //Degrees/second
var tiltScale : float = 60.0f; //Degrees/unitInput*second
var tiltRange : float = 30.0f; //Degrees
private var rotX : float = 0.0f; //Degrees

//Turn
var maxTurn : float = 360.0f; //Degrees/second
var turnScale : float = 120.0f; //Degrees/unitInput*second
var turnRange : float = 360.0f; //Degrees
private var rotY : float = 0.0f; //Degrees

//Bank
var maxBank : float = 90.0f; //Degrees/second
var bankScale : float = 60.0f; //Degrees/unitInput*second
var returnSpeed : float = 40.0f;//Degrees/second
var bankRange : float = 20.0f; //Degrees
private var rotZ : float = 0.0f; //Degrees

//Input
private var mouseScale : float = 1.0f; //Gs of acceleration/pixel
private var deltaX : float = 0.0f; //Units of input
private var deltaY : float = 0.0f; //Units of input

//Start information
private var originalRot : Quaternion = Quaternion.identity;

function Update () {
    if(keyboardControls) {
       deltaX = Input.GetAxis("Horizontal");
       deltaY = Input.GetAxis("Vertical");
    } else if(mouseControls) {
       deltaX = Input.GetAxis("Mouse X")*mouseScale;
       deltaY = Input.GetAxis("Mouse Y")*mouseScale;
    } else {
       deltaX = Input.acceleration.x;
       deltaY = Input.acceleration.y;
    }

    //Bank
    if(!Mathf.Approximately(deltaX, 0.0f))
        rotZ = ClampAngle(rotZ-
                  ClampAngle(deltaX*bankScale,-maxBank,maxBank)*Time.deltaTime,
                  -bankRange, bankRange);
    else if(rotZ > 0.0f)
        rotZ = ClampAngle(rotZ-Time.deltaTime*returnSpeed,0.0f,bankRange);
    else rotZ = ClampAngle(rotZ+Time.deltaTime*returnSpeed,-bankRange,0.0f);

    //Turn
    rotY = ClampAngle(rotY+
              ClampAngle(deltaX*turnScale,-maxTurn,maxTurn)*Time.deltaTime,
              -turnRange,turnRange);

    //Tilt
    rotX = ClampAngle(rotX-
              ClampAngle(deltaY*tiltScale,-maxTilt,maxTilt)*Time.deltaTime,
              -tiltRange,tiltRange);

    transform.localRotation = Quaternion.Euler(rotX,rotY,rotZ)*originalRot;
}

function Start () {
    if (rigidbody) rigidbody.freezeRotation = true;
    originalRot = transform.localRotation;
}

//Modified to work when you get angles outside of -/+720 
static function ClampAngle (angle : float, min : float, max : float) : float {
    while (angle < -360.0) angle += 360.0;
    while (angle > 360.0) angle -= 360.0;
    return Mathf.Clamp(angle, min, max);
}