Rotation damping

Hi – I’m sure I’ve seen the answer to my question in the forums but I can’t figure out how to implement it.
I’m using arrows and GUIbuttons to orbit an object. The arrow buttons work great with a nice speed up/down at the beginning and end and I want the GUI buttons to do the same - slowly start then stop the rotation instead of suddenly start and stop. What do I need to do to this script to make that work? I’ve checked out the smooth follow script but can’t understand what does what I need: Here’s my script:

var target : Transform;
var edgeBorder = 0.1;
var horizontalSpeed = 360.0;
var verticalSpeed = 120.0;
var minVertical = 20.0;
var maxVertical = 85.0;
private var x = 0.0;
private var y = 0.0;
private var distance = 0.0;

function OnGUI () {
// 3D orbit nav array
	if(GUI.RepeatButton(Rect(Screen.width/2 -10 , Screen.height -75, 20, 20), "U")){
	y += verticalSpeed * Time.deltaTime;
	}
	
	if(GUI.RepeatButton(Rect(Screen.width/2 -10 , Screen.height -30, 20, 20), "D")){
	y -= verticalSpeed * Time.deltaTime;
	}
	
	if(GUI.RepeatButton(Rect(Screen.width/2 -40 , Screen.height -50, 20, 20), "L")){
	x += horizontalSpeed * Time.deltaTime;
	}
	
	if(GUI.RepeatButton(Rect(Screen.width/2 +20 , Screen.height -50, 20, 20), "R")){
	x -= horizontalSpeed * Time.deltaTime;
	}
// 3D orbit nav array

function Start()
{
x = transform.eulerAngles.y;
y = transform.eulerAngles.x;
distance = (transform.position - target.position).magnitude;
}

function LateUpdate()
{
	var dt = Time.deltaTime;
	x -= Input.GetAxis("Horizontal") * horizontalSpeed * dt;
	y += Input.GetAxis("Vertical") * verticalSpeed * dt;
	
	y = ClampAngle(y, minVertical, maxVertical);
	 
	var rotation = Quaternion.Euler(y, x, 0);
	var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
	
	transform.rotation = rotation;
	transform.position = position;
}

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

Thanks!

As far as I can tell, I know I need something like this in there somewhere:

var rotation = Quaternion.LookRotation(target.position - transform.position);
			transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * damping);

But every variation I put in there does’t do the job. Anyone?

To get smooth response from the buttons (as you would with Input.GetAxis), you need to gradually add an amount to a variable for each axis. Say, for the horizontal axis, you would start with a variable and the buttons will add a small amount to that variable on each OnGUI. You may want to clamp the axis value between -1 and +1, depending on the effect you are looking for. If no button is pressed, then subtract the small amount, but make sure you stop when you get close to zero. Finally, multiply the axis value by your maximum speed value:-

var horiz: float;
var smallAmount: float = 0.1;   // For example...

function OnGUI() {
    if (GUI.RepeatButton(...) {  // RIght
        horiz += smallAmount * Time.deltaTime;
    } else if (GUI.RepeatButton(...) { // Left
        horiz += smallAmount * Time.deltaTime;
    } else if (....) {
    } else {
        horiz -= Math.Sign(horiz) * smallAmount;
    }

    if (Mathf.Abs(horiz) <= smallAmount) {
        horiz = 0;
    }

    y += horiz * verticalSpeed * Time.deltaTime;

    // ...etc...
}

Thanks a lot – this definately gets me on the right track. I haven’t been able to figure out exactly where to paste each part of your example into my original script – so far all I’ve managed is to get the startup acceleration to work – but I haven’t been able to get it to slow down when the button is released. If you have a chance, should let me know were in the original script everything goes? I’ll keep working on it too. Thanks again!

Hey Andeeee

Sorry to be so dense, but I’ve spent a lot of time with the script you gave me, trying to plug it into that original script I posted, and I just can’t get it to work right. The concept makes sense, and I’ve been able to get it to work halfway (I click the rotate button and it slowly start to rotate.) But I just can’t get it to slow down correctly after mouseup. Could you give me some more tips on how to apply your script to good effect? Thanks for any extra help you can throw my way …

Noob

The key detail is that when there is no button being pressed, you need to subtract from the axis value to get it to die down to zero. You can do this by subtracting the same small amount that you gradually add when the button is pressed in the first place. However, since the value can be either negative or positive depending on direction, you should use Mathf.Sign to determine which it is:-

axis -= Mathf.Sign(axis)... ;

This means “if axis is positive then take some away, but if it’s negative then add some on”. Then, when the axis value is close to zero, just set it to exactly zero - this should stop the axis oscillating up and down around zero endlessly and giving false input.

Thanks for remedial help Andeeee, I’m really close. The code below almost works, except for mouseoff gradual decelleration (your concept makes perfect sense, I’m just using it wrong). I have the Mathf.Sign in there but that snippet is active, I don’t orbit at all – when I comment that part out, I’m so close … but of course I don’t decellerate on mouseoff … what’s the last thing I’m missing? Thanks so much, I think this is my last question on this!

var horiz: float; 
var smallAmount: float = 0.1; 
private var y = 0.0; 
var verticalSpeed = 120.0; 
var target : Transform; 
var edgeBorder = 0.1; 
var horizontalSpeed = 360.0; 
private var x = 0.0; 
private var distance = 0.0; 

function OnGUI() { 
if(GUI.RepeatButton(Rect(Screen.width/2 +20 , Screen.height -50, 20, 20), "R")){ 
        horiz += smallAmount * Time.deltaTime; 
    } 
	
	if (GUI.RepeatButton(Rect(Screen.width/2 -40 , Screen.height -50, 20, 20), "L")){ 
        horiz -= smallAmount * Time.deltaTime; 
    }

// if I disable the 'else' script below I'm very close but I don't decelerate on mouseoff	
    else { 
        horiz -= Mathf.Sign(horiz) * smallAmount; 
		    //~ } 
    if (Mathf.Abs(horiz) <= smallAmount) { 
        horiz = 0; 
	}
}

function Start() 
{ 
x = transform.eulerAngles.y; 
y = transform.eulerAngles.x; 
distance = (transform.position - target.position).magnitude; 
} 

function LateUpdate() 
{ 
   var dt = Time.deltaTime; 
   x -= Input.GetAxis("Horizontal") * horizontalSpeed * dt; 
    
   x += horiz * verticalSpeed * Time.deltaTime; 
    
   var rotation = Quaternion.Euler(y, x, 0); 
   var position = rotation * Vector3(0.0, 0.0, -distance) + target.position; 
    
   transform.rotation = rotation; 
   transform.position = position; 
}

Wait!!! I think I just got it working (left only, but should be able to finish up soon). Thanks a lot for your time Andeeee – I’ll post the final working script here when I get it done so you don’t have to explain all this to someone else :slight_smile:

Well, its still not perfect (some of the GUI buttons disappear when others are pressed, and the object shakes at the top and bottom of the vertical rotation), but the damping effect I wanted works (the camera eases in and out of a rotation around a target). Hopefully anyone who could use this will be able to fix the other problems. Thanks again for all the help Andeeee.

var horiz: float; 
var vert: float; 
var smallAmount: float = .1; 
private var y = 0.0; 
var verticalSpeed = 120.0; 
var target : Transform; 
var edgeBorder = 0.1; 
var horizontalSpeed = 100; 
var minVertical = 20.0; 
var maxVertical = 85.0; 
private var x = 0.0; 
private var distance = 0.0; 

function OnGUI() { 
if(GUI.RepeatButton(Rect(Screen.width/2 +20 , Screen.height -50, 20, 20), "R")){ 
        horiz += smallAmount * Time.deltaTime * horizontalSpeed; 
    } 
	
	else if (GUI.RepeatButton(Rect(Screen.width/2 -20 , Screen.height -50, 20, 20), "L")){ 
        horiz -= smallAmount * Time.deltaTime  * horizontalSpeed; 
    }
	
    else { 
        horiz -= Mathf.Sign(horiz) * smallAmount; 
    if (Mathf.Abs(horiz) <= smallAmount) { 
        horiz = 0; 
	}
	}
	
	if(GUI.RepeatButton(Rect(Screen.width/2, Screen.height -70, 20, 20), "U")){ 
        vert += smallAmount * Time.deltaTime * verticalSpeed; 
    } 
	
	else if (GUI.RepeatButton(Rect(Screen.width/2 , Screen.height -30, 20, 20), "D")){ 
        vert -= smallAmount * Time.deltaTime  * verticalSpeed; 
    }
	
    else { 
        vert -= Mathf.Sign(vert) * smallAmount; 
    if (Mathf.Abs(vert) <= smallAmount) { 
        vert = 0; 
	}
	}
}

function Start() 
{ 
x = transform.eulerAngles.y; 
y = transform.eulerAngles.x; 
distance = (transform.position - target.position).magnitude; 
} 

function LateUpdate() 
{ 
   var dt = Time.deltaTime; 
   x -= Input.GetAxis("Horizontal") * horizontalSpeed * dt; 
   y += Input.GetAxis("Vertical") * verticalSpeed * dt; 
    
   y = ClampAngle(y, minVertical, maxVertical); 
   x += horiz * verticalSpeed * Time.deltaTime; 
	y += vert * verticalSpeed * Time.deltaTime; 
    
   var rotation = Quaternion.Euler(y, x, 0); 
   var position = rotation * Vector3(0.0, 0.0, -distance) + target.position; 
    
   transform.rotation = rotation; 
   transform.position = position; 
} 

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

Nice little script youve made here. really usefull.

Ive snatched it, and I see the “stuttering” problem around minVertical and maxVertical.

While I was unable to find the correcto solutiono (mostly due to my noobiness), isnt it something one could solve by saying:

whenever we are REALLY close to minVertical then lock to minVertical. Same for maxVertical. Wouldnt this stop this stutter behaviour?

Im not sure how you would script this, but heres a simple pseudo:

if ((current - minVertical) < 0.1){
current = minVertical;
}

and then some sort of mechanism that will allow us to “unlock” from minVertical again?

Hi Theformand – I’m glad that script is useful for you - I wish I could say I was more involved with it, but its actually the rotatecamera script from the shadows project with the tweaks Andeeee outlined. Learned a lot though - hopefully Unity will become more intuitive for me someday, but so far I’m struggling with every little step. Thanks for the idea for the stutter problem, seems reasonable I’ll try that out! Happy Unitying to you :slight_smile: