Local Euler Angles not displaying right values [duplicate] - c#

In the inspector for a gameObject I'm using the starting rotation is "-90", but when I run print(transform.eulerAngles.x) I get 270 (ditto for transform.localEulerAngles.x).
If I tilt the gameObject downward, the inspector X value gets bigger (say, to -85) as it should. The printed transform.eulerAngles.x also gets bigger, say to 274.
Here's where things get weird:
If I tilt the gameObject upward the inspector x coordinate gets smaller (ex, to -95), as it should, BUT the printed eulerAngle.x value gets BIGGER (here to 274). So if I rotate the object up or down from the eulerAngle.x being 270, the x value increases regardless.
I'm definitely doing something wrong here, but after a lot of troubleshooting I still can't figure out what. Any thoughts?

eulerAngles are a convoluted process in Unity3D. You should never increment/decrement or set the values in your inspector or via code. Should only use absolute values to read and set it.
Don't increment or decrement the values, as it will fail when the angle exceeds 360 degrees. Transform.Rotate is what you use instead.
Here is the sample code in the Unity3D documentation example:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
public float yRotation = 5.0F;
void Update() {
yRotation += Input.GetAxis("Horizontal");
transform.eulerAngles = new Vector3(10, yRotation, 0);
}
void Example() {
print(transform.eulerAngles.x);
print(transform.eulerAngles.y);
print(transform.eulerAngles.z);
}
}
This is taken directly from the documentation:
https://docs.unity3d.com/ScriptReference/Transform-eulerAngles.html
Also Transform.Rotate documentation:
https://docs.unity3d.com/ScriptReference/Transform.Rotate.html
The inspector will almost always give you a funky value vs when you log it. The only consistency you will get is print(transform.rotation). This should retain similar values across inspector and code.

For each value in transform.eulerAngles or transform.localEulerAngles if it has a parent:
if (value > 270)
value -= 360;

Related

Is there a way to create a curve when launching a gameobject to the player?

This is what I have tried so far:
I create a raycast and if it hits an object on layer 8 (the layer in which objects need to be launched to the player), I call the SlerpToHand() function.
private void Update()
{
if(Physics.Raycast(transform.position, transform.forward * raycastLength, out hit))
{
if(hit.collider.gameObject.layer == 8)
{
// Launch object to player
SlerpToHand(hit.collider.transform);
}
}
}
Inside of SlerpToHand(), I set the object's position to Vector3.Slerp(), that vector being created from values in the hit object.
private void SlerpToHand(Transform hitObj)
{
Vector3 hitObjVector = new Vector3(hitObj.transform.position.x, hitObj.transform.position.y, hitObj.transform.position.z);
hitObj.position = Vector3.Slerp(hitObjVector, transform.position, speed);
}
But the result of this is all wrong, the object just gets teleported to the player's hands. Is Vector3.Slerp() not a good way to curve an object to the player? For context I am trying to recreate Half-Life: Alyx's grabbity gloves. There is still some work to do with the hand gestures but I am just trying to get the object curve down. Help is much appreciated, let me know if more info is needed.
See unity docs:
public static Vector3 Slerp(Vector3 a, Vector3 b, float t);
Here, t is a normalized position between two input values. It means, if t = 0, result will be exactly first value. If t = 1, result will be exactly second value. If t = 0.5, result will be the middle between two values.
So, usually, you need to call Slerp every Update, step by step increasing t from 0 to 1. For this, usually Time.deltaTime used (which equals the time between updates). For speed control, multiply your speed by Time.deltaTime.
Update()
{
if (t < 1)
{
t += Time.deltaTime * speed;
hitObj.position = Vector3.Slerp(startPosition, endPosition, t);
}
}
...and in this case, for start moving, you just need to set t = 0. Probably, you have to implement your own logic here, but this should show the idea.
In addition:
Slerp used to interpolate between vector directions, for positions use Lerp.
Consider use DOTween plugin - its free and powerful for such cases.

Setting Quaternion through inspector window

I was looking for a way to set the Quaternions (x, y, z, w) through the inspector window. We get all these variables when we click on "Debug" mode in Unity. Through Unity docs, I got to know that these values are between 0-1. So how do we set for angles such as 90,-90,180,-180,270,.... MAIN THING here is that I want to set the target rotations in the script of this game object so that the gameObject moves from initial rotation to target rotation.
For example in "Normal" window, if I set the target rotation of x as 180 (shown as -5.008956e-06 in the inspector window), the gameObject moves from 0 to -180, instead of +180. That is the reason I moved to "Debug" window thinking it helps here to set it. But the values here range between 0-1, so does anyone have an idea of how to calculate this?
Moreover, for rotation I am using this one line:
transform.localRotation = Quaternion.Slerp(transform.localRotation, targetRotation, Time.deltaTime * RotationSpeed);
It sounds like you want to be able to adjust it via a Vector3 just how Unity does it in the Transform Inspector. You could do something like
public Vector3 targetRotationV3;
private Quaternion targetRotation;
private void Start()
{
targetRotation = Quaternion.Euler(targetRotationV3);
}
or if you need to be more flexible
private void Update()
{
targetRotation = Quaternion.Euler(targetRotationV3);
...
}
Then for my comment what I mean is that Slerp interpolates a value between the first and the second argument using the factor between 0 and 1.
Since you every frame use a new value as start point, namely the current rotation, this will get slower and slower to the end and depending on your given speed never reach the target rotation.
It makes little sense to use Time.deltaTime here which just divides your speed by about 60 (for 60 FPS). Usually you rather want a constant interpolation factor between 0 and 1. If the frame-rate goes up it might even rotate back since in this case the Time.deltaTime would get smaller!
So you either rather want a constant interpolation factor
[Range(0f,1f)] private float slerpFactor = 0.5f;
private void Update()
{
targetRotation = Quaternion.Euler(targetRotationV3);
transform.localRotation = Quaternion.Slerp(transform.localRotation, targetRotation, slerpFactor);
}
or if you want to rotate with a constant speed instead use Quaternion.RotateTowards
private void Update()
{
targetRotation = Quaternion.Euler(targetRotationV3);
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, Time.deltaTime * RotationSpeed);
}
where your RotationSpeed is now in ° / second
As I said in my comment, don't set Quaternion directly ever, unless you are really confident in your understanding of them, as pointed out in the unity docs (emphasis mine).
They are based on complex numbers and are not easy to understand intuitively. You almost never access or modify individual Quaternion components (x,y,z,w); most often you would just take existing rotations (e.g. from the Transform) and use them to construct new rotations (e.g. to smoothly interpolate between two rotations). The Quaternion functions that you use 99% of the time are: Quaternion.LookRotation, Quaternion.Angle, Quaternion.Euler, Quaternion.Slerp, Quaternion.FromToRotation, and Quaternion.identity. (The other functions are only for exotic uses.)
Rather what you want to do is set the initial and target rotations as Vector3 (Eulerangles) from the inspector and use the build in Quaternion.Euler(); method to let Unity figure out the transformation from Eulerangles to Quaternions.
This would look something like this (Note that I am doing this in an update for the example, and using a float time that I update from the inspector to change the rotation, this is just done for ease of example and not the best way to do implement the t parameter of Quaternion.Slerp):
public Vector3 initialrotation;
public Vector3 targetRotation;
public float time;
void Update()
{
// Let Unity figure out what the appropriate Quaternions are for the given Eulerangles
// Note that this can better be done in Start if initialRotation and targetRotation never change. Just put it here for simplicity
var initialQuaternion = Quaternion.Euler(initialrotation);
var targetQuaternion = Quaternion.Euler(targetRotation);
var slerp = Quaternion.Slerp(initialQuaternion, targetQuaternion, time);
transform.rotation = slerp;
}

Projectile motion with user specified angle and speed using RigidBody2D

Edited:
I've got a slider from 0-90 for the user to select an angle, and a text field for them to enter a speed. All vids I've seen either have people using their own physics or are retrieving an angle directly from the angle of the "gun" or the mouse position, but that's not what I need. I've got it to where gravity affects it now, but it just drops after it spawns, even if I set the speed to 50. I want the speed to determine the dx and dy values at the time the ball is spawned, but it seems that's not happening.
I believe I can get the slider value with GameObject.Find("AngleSlider").GetComponent().angleSlider.value
and should be able to do something similar with the text box value for the speed if I can cast it to a float(?) so I think I'm fine there unless anyone notices a problem with that.
Any help is appreciated for this beginner. Thanks!
Edit: By request I've added the code I have atm for this part. This is the ball spawner that I've attached to the cannon. The CannonBall mentioned is another script attached to the cannonball prefab. I have public uninitialized dx, dy, and speed floats in the CannonBall script.
public GameObject cannonBallPrefab;
public Transform shotPoint;
void Start () {
}
void Update () {
if(Input.GetKeyDown("space"))
{
GameObject ball = Instantiate(cannonBallPrefab, shotPoint.position, Quaternion.identity);
CannonBall ballMovement = ball.GetComponent<CannonBall>();
ballMovement.dy = Mathf.Sin(GameObject.Find("AngleSlider").GetComponent<SliderHandler>().angleSlider.value * Mathf.Deg2Rad) * ballMovement.speed;
ballMovement.dx = Mathf.Cos(GameObject.Find("AngleSlider").GetComponent<SliderHandler>().angleSlider.value * Mathf.Deg2Rad) * ballMovement.speed;
Debug.Log("ball is spawned");
}
}

How to slow down rotation?

So I wrote some code to make an object rotate if I swiped left or right
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotater : MonoBehaviour {
public Transform player;
void Update()
{
if (Input.touchCount == 1)
{
// GET TOUCH 0
Touch touch0 = Input.GetTouch(0);
// APPLY ROTATION
if (touch0.phase == TouchPhase.Moved)
{
player.transform.Rotate(0f, 0f, touch0.deltaPosition.x);
}
}
}
}
and the problem is when I swipe fast the rotation will be uncontrollable. So I want the input to be less sensitive.
my goal is for the rotation to be like rolly vortex
my setup:
I made an empty object and put it in the center
made the empty object a parent of my player
and finally, I put my code in the empty object
this setup made the player rotate in sort of an orbit which like I told you is similar to rolly vortex.
First you want to be able to scale the sensitivity. This means making it so that for every unit of change in touch position, you will get some multiple of a unit of change in the rotation. For this, make a configurable (public) member variable, public float touchSensitivityScale, and multiply the rotation by that value. Example:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotater : MonoBehaviour {
public Transform player;
public float touchSensitivityScale;
void Update()
{
if (Input.touchCount == 1)
{
// GET TOUCH 0
Touch touch0 = Input.GetTouch(0);
// APPLY ROTATION
if (touch0.phase == TouchPhase.Moved)
{
player.transform.Rotate(0f, 0f, touch0.deltaPosition.x * touchSensitivityScale);
}
}
}
}
Now you can edit the touch sensitivity in the inspector. With touchSensitivityScale set to 1, the behavior will be identical to what it is currently. If you make the number 0.5, the rotation will be half as sensitive.
If this doesn't fully solve the problem and you also want some smoothing or acceleration, that might warrant an edit to the question.
I hope it helps!
Rather than rotating by touch0.deltaPosition.x you could always have some sort of negative exponential function. In this case it’d probably be something along the lines of e^(-x-a) where x is your touch0.deltaPosition.x, and a would be a variable you’d have to determine based on how fast you want the initial speed of rotation. If you’re not familiar with exponential functions try using a graphing software like Desmos to plot y=e^(-x-a) and vary the value of a. Once you’ve visualised that it should be pretty self explanatory.

Why the script is not rotating my sphere object?

Well, I am new to unity 3d and C sharp. I was trying a script to rotate my spehere object . But it's not working.
I was following a youtube video. This code worked for him. But in my case it is not working.
I added the transform object.
using UnityEngine;
using System.Collections;
public class cubescript : MonoBehaviour {
public Transform sphereTransform;
// Use this for initialization
void Start () {
sphereTransform.parent = transform;
}
// Update is called once per frame
void Update () {
transform.eulerAngles = new Vector3 (0, 180*Time.deltaTime, 0);
}
}
It's kind of working but stuck at 2.981877-3 Y rotation .. And not rotating around the cube..
The problem is that you are trying to rotate, but eulerAngles only sets to ABSOLUTE angles (if you want to add angles to the current frame angle, you will use Rotate).
So, if you use transform.eulerAngles you will be all the frames setting the angle change to what 180 * Time.deltaTime returns, that will depend on how many FPS you are running, thats why you get constant number.
If you use transform.Rotate it will add the new angle change to the current angle frame. Say that you want to increment by 10 degress, so frame 1 = (0,0,0), frame 2 = (0,10,0), frame 3 = (0,20,0).
In eulerAngles you will get all the time (0,10,0), because it sets ABSOLUTE angle, Rotate adds to the current angle what you want.
Change this
transform.eulerAngles = new Vector3 (0, 180*Time.deltaTime, 0);
To this
transform.Rotate(new Vector3 (0, 180*Time.deltaTime, 0));
This is the official Unity Documentation for eulerAngle and Rotate
As said in another answer, when you set transform.eulerAngles, you are setting an absolute rotation. You can use transform.Rotate() but you can also use Time.time to ensure that you get linear rotation: transform.eulerAngles = new Vector3(0, 180*Time.time, 0);

Categories