- Home /
Rotate object with mouse cursor that slows down on release
Hi,
I am grabbing an object with the mouse cursor and rotating it, but when I release the mouse button I want it to continue to rotate a little then slow down to a stop.
I am doing the rotation in the OnMouseDrag function:
function OnMouseDrag () { RotationSpeed = 2; transform.Rotate (0, -RotationSpeed*Input.GetAxis ("Mouse X"), RotationSpeed*Input.GetAxis ("Mouse Y"), 0);
}
I have added a rigidbody component but that doesn't help. Do I need to calculate and apply a torque?
THANK YOU!
I like this question, seems like quite an interesting feature that can return in many forms!
Answer by duck · Nov 17, 2010 at 08:10 AM
Try this.
it's untested (I don't have Unity in front of me right now)
Ok, now implemented and tested, and turns out it was a little more complex to implement - mainly because at a high framerate, you get many frames where the mouse axis input is zero during a drag - so if you don't keep track of speed over a number of frames and you release the button during one of these 'zero value' frames, it appears as though the mouse wasn't moving!
First, the rotation is done in Update rather than MouseDrag, so that it can continue after the mouse is released. I'm using OnMouseDown to detect that this object was originally clicked on, and subsequently using Input.GetMouseButton to determine that the mouse is still held down.
Basically, while dragging, it keeps a separate "average speed" value (avgSpeed), which contains the current speed of rotation averaged over the last half-second or so (Using Lerp). It then uses this value when the mouse is released as the speed to continue rotating, and gradually Lerps this value down to zero to slow the rotation.
I have also used a different method of rotating the objects so that the rotation direction is always in accordance with the direction that you're dragging the mouse in screen-space.
Hope this fits what you're looking for!
var rotationSpeed = 10.0; var lerpSpeed = 1.0;
private var speed = new Vector3(); private var avgSpeed = new Vector3(); private var dragging = false; private var targetSpeedX = new Vector3();
function OnMouseDown() { dragging = true; }
function Update () {
if (Input.GetMouseButton(0) && dragging) {
speed = new Vector3(-Input.GetAxis ("Mouse X"), Input.GetAxis("Mouse Y"), 0);
avgSpeed = Vector3.Lerp(avgSpeed,speed,Time.deltaTime * 5);
} else {
if (dragging) {
speed = avgSpeed;
dragging = false;
}
var i = Time.deltaTime * lerpSpeed;
speed = Vector3.Lerp( speed, Vector3.zero, i);
}
transform.Rotate( Camera.main.transform.up * speed.x * rotationSpeed, Space.World );
transform.Rotate( Camera.main.transform.right * speed.y * rotationSpeed, Space.World );
}
Without trying it out, I don't think this will work as the op asked for a solution that will continue to rotate when he releases the mouse. So doing stuff in On$$anonymous$$ouseDrag won't work.
Oh yes, that should be changed to Update, good point :) (Fixed)
Completely reworked the example due to other unexpected problems when I came to test it! (described in answer)
@ Duck- Great code, was wondering how I could lock the rotation axis? I've tried a few things but can't get it to work. I'm going for a garage scene where you can rotate a car to see from different angles, same as in "Asphalt 5". Thanks in advance!
Answer by c6y · Jan 30, 2014 at 07:57 AM
Thanks @duck, this saved me a lot of time. For the record here's a translation to C#, hope it's correct.
using UnityEngine;
using System.Collections;
public class DragRotateSlowDown : MonoBehaviour {
private float rotationSpeed = 10.0F;
private float lerpSpeed = 1.0F;
private Vector3 theSpeed;
private Vector3 avgSpeed;
private bool isDragging = false;
private Vector3 targetSpeedX;
void OnMouseDown() {
isDragging = true;
}
void Update() {
if (Input.GetMouseButton(0) && isDragging) {
theSpeed = new Vector3(-Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"), 0.0F);
avgSpeed = Vector3.Lerp(avgSpeed, theSpeed, Time.deltaTime * 5);
} else {
if (isDragging) {
theSpeed = avgSpeed;
isDragging = false;
}
float i = Time.deltaTime * lerpSpeed;
theSpeed = Vector3.Lerp(theSpeed, Vector3.zero, i);
}
transform.Rotate(Camera.main.transform.up * theSpeed.x * rotationSpeed, Space.World);
transform.Rotate(Camera.main.transform.right * theSpeed.y * rotationSpeed, Space.World);
}
}
Answer by StarHunter32 · Aug 04, 2014 at 08:37 PM
Hello, seems like a great script, but I can't understand how to make it work. Should I attach it to the object I want to rotate? If yes, it doesn't seem to work with me.
Thank you in advance!
Answer by tmalhassan · Sep 16, 2017 at 03:38 AM
Following @stek very simple and very helpful example (on a different thread). I took his code and modified it so the can spin on both sides while accepting touch controls so it can work on mobile devices. Simply, attach the script to the spinning object. Bare with me, i am a beginner. The script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinWheelScript : MonoBehaviour {
float pointerY;
float f_lastX = 0.0f;
float f_difX = 0.5f;
float f_steps = 0.0f;
int i_direction = 1;
void Start()
{
pointerY = Input.GetAxis("Mouse Y");
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
f_difX = 0.0f;
}
else if (Input.touchCount > 0)
{
pointerY = Input.touches[0].deltaPosition.y;
f_difX = Mathf.Abs(f_lastX - pointerY);
var touch = Input.GetTouch(0);
if (touch.position.x > Screen.width / 2)
{
// Right
if (f_lastX < Input.GetAxis("Mouse Y"))
{
i_direction = 1;
transform.Rotate(Vector3.forward, f_difX * Time.deltaTime);
}
if (f_lastX > Input.GetAxis("Mouse Y"))
{
i_direction = -1;
transform.Rotate(Vector3.forward, -f_difX * Time.deltaTime);
}
}
else if (touch.position.x < Screen.width / 2)
{
// Left
if (f_lastX < Input.GetAxis("Mouse Y"))
{
i_direction = -1;
transform.Rotate(Vector3.forward, -f_difX * Time.deltaTime);
}
if (f_lastX > Input.GetAxis("Mouse Y"))
{
i_direction = 1;
transform.Rotate(Vector3.forward, f_difX * Time.deltaTime);
}
}
f_lastX = -pointerY;
f_difX = 500f;
Debug.Log(f_difX);
}
else
{
if (f_difX > 0.5f) f_difX -= 1f;
if (f_difX < 0.5f) f_difX += 1f;
transform.Rotate(Vector3.forward, f_difX * i_direction * Time.smoothDeltaTime);
}
}
}
Currently, the object will spin based on a swipe along the Y axis, you can simple change it by replacing the Y's with X's. Also, i've modified the speeds to fit my liking. Hope this helps.
Cheers!
Your answer
![](https://koobas.hobune.stream/wayback/20220613083354im_/https://answers.unity.com/themes/thub/images/avi.jpg)