- Home /
Rotate GameObject With GUI Slider
For context, I am trying to move the flap on an airplane wing using a GUI Slider in Unity 2017.3.0f3. Ideally I'm going to have the slider start in the middle, and you can drag the dot left for "down" a certain amount of degrees, and right for "up" a certain amount of degrees. So far I have hit walls in all of my attempts of just proof of concept for scripting this. My setup I have in the scene is:
- a slider named "LeftFlap_Slider",
- a C# script titled "MoveFlaps.cs",
- GameObject titled "LeftWingFlap_Pivot" that the C# script is attached to.
I first found a post from 2015 posing a very similar question, and the solution given(variables changed to my context):
public GameObject LeftFlap;
public void RotateFlap()
{
float sliderValue = GetComponent<Slider>().value;
LeftFlap.transform.rotation = Quaternion.Euler(sliderValue * 360, 0, 90);
}
While this doesn't show any errors in the editor, when I move the slider in Unity I get the error ArgumentException: GetComponent requires that the requested component 'Slider' derives from MonoBehaviour or Component or is an interface.
And further down it directly calls out the line that float sliderValue = GetComponent<Slider>().value;
is on. So I'm assuming that it's something to do with <Slider>
?
I have also gone down the route of Transforms and Vector3 eulerAngles. Specifically:
public void LeftFlapSlider(float newValue)
{
Vector3 pos = LeftFlap.transform.eulerAngles;
pos.y = newValue;
LeftFlap.transform.position = pos;
}
When I connect it to the slider (and select the Dynamic float version of LeftFlapSlider), the LeftWingFlap_Pivot GameObject teleports to a different location the moment the slider begins to update. A note on its teleport location, this is not world center or GameObject center, as those are both located in front of the airplane, and this is teleporting somewhere above and behind the airplane. The slider does move the GameObject pos and neg when I go left and right, but it's on an axis, and I want to rotate it on an axis. So this was my final attempt:
public float speed;
public void AdjustSpeed(float newSpeed)
{
transform.Rotate(speed, 0, 0);
speed = newSpeed;
}
This has the GameObject spin, only while the slider is moving, and it spins faster or slower depending on where I am currently moving the slider. But it's rotating it, which is better than a linear movement on an axis.
So that's where I am at now and am at a loss. It would seem that my first example would be the best bet, as that thread stated that it worked just great for what they were using it for, and that's near identical to what I'm doing, but of course it doesn't work.
Come on guys. 484 people following this and not even a comment? I'm seriously still working on this and have gotten zero progress.
Answer by TreyH · Mar 12, 2018 at 04:09 PM
When using Unity's UI elements, there's usually an event listener you can use instead of manually checking for changed values or assigning rotations each frame regardless of change. This script assumes that your slider goes from 0 to 1 and that you want to extend that to 0 to 360, as you had in your question.
using UnityEngine;
using UnityEngine.UI;
public class RotateWithSlider : MonoBehaviour
{
// Assign in the inspector
public GameObject objectToRotate;
public Slider slider;
// Preserve the original and current orientation
private float previousValue;
void Awake ()
{
// Assign a callback for when this slider changes
this.slider.onValueChanged.AddListener (this.OnSliderChanged);
// And current value
this.previousValue = this.slider.value;
}
void OnSliderChanged (float value)
{
// How much we've changed
float delta = value - this.previousValue;
this.objectToRotate.transform.Rotate (Vector3.right * delta * 360);
// Set our previous value for the next change
this.previousValue = value;
}
}
Which will look like:
Alright, this does work fantastically and does exactly what I have been looking for. But a new problem has presented itself within this solution. When the slider updates, the wing flap that moves, will teleport 90degrees counter-clockwise, and then work as intended. Even when I move the slider back to its original position, the wing flap stays in the off 90degree rotated position like so: But it does rotate exactly how you would expect an airplane flat to move, except that it's off the vehicle by 90degrees. Its original rotational position is: 0, -14.597, 0. But when I set that back to 0, 0, 0, it's nothing like what's in the screenshot's right image. Looking at the inspector of the GameObject while in play mode, the rotation Y-value gets set to -90degrees.
The original response was just taking your (X,0,0) vector and applying it as the object's euler angles. I just updated the answer to only rotate around the given axis without assigning other euler components.
Also, which axis is that wing flap supposed to rotate around? I assumed X, but the script will need to be adjusted depending on how your objects are set up.
Alright, those changes fix the sudden -90degree change. Final (I hope) problem that's presented itself in this. And to be honest I don't know if it should be in this thread or another new one. But when I rotate an object using the rotate tool, click off that object than back onto it, my rotation sphere (visual showing the x,y,z axis) has reset itself back to the default position. Even though the values in the inspector are not back to 0, 0, 0. And if I type in rotational values in the inspector, the sphere does not change. I've restarted Unity but this problem persists. edit: And even more odd, when I add a child to a parent object, the parent object's positional center changes to that of the child. And when I remove the child, the parent's positional center returns to what it originally was. I've been doing this for the entire project and this has never happened before.
Answer by SimRuJ · Feb 01 at 11:04 AM
It's a bit easier in Unity 2021.1:
Create the slider(s) in the editor and assign the following function to its OnValueChanged
:
public Slider xSlider, ySlider, zSlider; //set in editor
public GameObject objectToRotate; //set in editor
private readonly float rotationLimit = 180f;
public void RotateObject() {
objectToRotate.transform.localEulerAngles = new Vector3(
xSlider.value * rotationLimit,
ySlider.value * rotationLimit,
zSlider.value * rotationLimit //y-up, switch ySlider & zSlider for z-up
);
}
I also set the sliders' min value to -1 and max value to 1, so the handle starts in the middle and you can rotate left and right (for a full rotation combined). To only go right change the values to 0 and 1 and set the limit to 360. If you only want to rotate the object in a single direction with a single slider, use e.g.:
objectToRotate.transform.localEulerAngles = Vector3.right * xSlider.value * rotationLimit;
Your answer
Follow this Question
Related Questions
Rotate an Instantiated GameObject a set amount from another instantiated GameObject? 1 Answer
Distribute terrain in zones 3 Answers
Multiple Cars not working 1 Answer
What is the best way to instatiate an array of connected GameObjects? 0 Answers
Object reference not set to an instance of an object 2 Answers