I have steering wheel that is controlled by physical daydream controller(it works similar to wii controller). I use this code to do it:
void Update() {
transform.localRotation = GvrController.Orientation;
transform.localRotation = new Quaternion(0.0f, 0.0f, -transform.localRotation.y, transform.localRotation.w);
}
I need to mess with axis, beacause default position of the controller isn't good for a steering wheel.
But in 3-axis angle between maximum rotation to the left and to the right is 180 degrees. In this range everything is fine, but if I rotate a little bit more this values change to negative and everything is messed up. What can i do to allow the player to rotate only in this range(0 - 180 on z axis of 3-axis rotation)?
EDIT: The main problem is that the values of rotation after crossing 0 or 180 change to negative values, which are the same for both, but in different order. After crossing 0 it s form -1 to -180 and and for 180 its -180 to -1.
Firstly, we need a value that we can actually clamp. We'll get that from the eulerAngles.z field (as a typical onscreen wheel rotates about z - you might need to change that to some other field depending on the controller):
void Update() {
// Get the angle:
float angle = GvrController.Orientation.eulerAngles.z;
// The magic - clamp it:
if(angle < -180f){
angle = -180f;
}
else if(angle > 180f){
angle = 180f;
}
// Apply it as a new rotation:
transform.localRotation = Quaternion.Euler(0f,0f,angle);
}
Try this:
if (transform.eulerAngles.z > 180)
transform.eulerAngles = new Vector3(transform.eulerAngles.y, transform.eulerAngles.y, 180);
else if (transform.eulerAngles.z < 0)
transform.eulerAngles = new Vector3(transform.eulerAngles.y, transform.eulerAngles.y, 0);
If anyone wonders I found a solution, based on a script from Luke's answer. I realized that the values that change to negative are fine, only thing wrong with them is that they are negative. So this is the working script:
transform.localRotation = GvrController.Orientation;
float angle = -transform.localRotation.y;
if (angle < 0.0f) {
angle = Mathf.Abs(angle);
}
transform.localRotation = new Quaternion(0.0f, 0.0f, angle, transform.localRotation.w);
Try this:
If (transform.rotation > 180)
transforn.rotation = 180;
Related
I'd want to rotate the character along the y-axis (green) of another gameobject.
Here's a picture of my system.
I'd want to rotate the character in the direction indicated by the red arrow (see figure, it is not x axis).
I looked at other questions and tried a lot of code,
but I still didn't achieve the desired results.
This is my latest code that created the picture above.
The picture on the right is what I want, but the picture on the left is not.
Any advice is appreciated. Thank you!
IEnumerator RotateToDirection(){
var targetRotation = new Vector3(0, ArrowObject.transform.localEulerAngles.y, 0);
var elapsedTime = 0.0f;
var waitTime = 1f;
while (elapsedTime < waitTime)
{
elapsedTime += Time.deltaTime;
Character.transform.localEulerAngles
= Vector3.Lerp(Character.transform.localEulerAngles, targetDirection, (elapsedTime / waitTime));
yield return null;
}
}
Don't use eulerAngles
When you read the .eulerAngles property, Unity converts the Quaternion's internal representation of the rotation to Euler angles. Because, there is more than one way to represent any given rotation using Euler angles, the values you read back out may be quite different from the values you assigned. This can cause confusion if you are trying to gradually increment the values to produce animation.
From your images it sounds like you want the character's forward axis to align with another objects up axis so you would probably use e.g. Quaternion.LookRotation something like e.g.
var startRotation = Character.transform;
var targetDirection = ArrowObject.transform.up;
var targetRotation = Quaternion.LookRotation(targetDirection);
for(var timePassed = 0f; timePassed< 1f; timePassed += Time.deltaTime)
{
Character.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, timePassed / 1f);
yield return null;
}
Character.transform.rotation = targetRotation;
this is my direction vector
new Vector3(target.transform.position.x - projectile.position.x, 0, target.transform.position.z - projectile.position.z).normalized
I tried multiplying it by Quaternion.AngleAxis(45, Vector3.up) but that simply doesn't work
All other orientations like Vector3.left, right, etc. don't help either
The only thing I could observe is the way that the angle changes when I move the target or projectile
You were close. Use cross product to get the axis you need, use that in AngleAxis, then finally apply that rotation to your starting direction:
Vector3 RotateTowardsUp(Vector3 start, float angle)
{
// if you know start will always be normalized, can skip this step
start.Normalize();
Vector3 axis = Vector3.Cross(start, Vector3.up);
// handle case where start is colinear with up
if (axis == Vector3.zero) axis = Vector3.right;
return Quaternion.AngleAxis(angle, axis) * start;
}
I wanted to a cube do not rotate more than 60 degrees so it dosn't rotate to more
I tried to use this
if(gameObject.GetComponent<Transform>().rotation.x >= 60 || gameObject.GetComponent<Transform>().rotation.x <= -60 || gameObject.GetComponent<Transform>().rotation.z >= 60 || gameObject.GetComponent<Transform>().rotation.z <= -60)
{
gameObject.GetComponent<Transform>().rotation = new Quaternion(0, 0, 0, 0);
}
to check the rotation.
It didn't work so I print what rotation is getting in the x coordinate
and it said cordinates like:
5.98324, 7.39482, -1.983495
and I was just moving the x position not the rotation and It change it.
So how do I get the x rotation that it sais in the component transform?
I think the way you approached is fine but not suitable for the scenario. Euler Angles should be handled in order to control the Transformation.
simple understanding be like:
// declare your cube rotation
float moveSpeed = 5f // speed in which cube rotates
float rotatecube = moveSpeed* Time.deltaTime* 10;
//Your condition be like
if(transform.eulerAngles.z < (.....declare the requirement.....))
transform.Rotate(vector3.forward * rotateCube);
If you still face any issue related to angles console.log() is the better way for self understandings.
Hope it clarifies..
You are interested in the euler angles of the rotation, not the quaternion components of the rotation. You should start by referring to transform.eulerAngles.x instead of transform.rotation.x or transform.eulerAngles.z instead of transform.rotation.z.
By the way, it's best to call GetComponent as few times as you can get away with as it's an expensive operation. You should rather call it once and assign the result to a variable such as this:
Transform cubeTransform = gameObject.GetComponent<Transform>();
if(cubeTransform.eulerAngles.x ...)
{
...
}
Additionally, you don't even need to use GetComponent to access the transform of the gameObject the script is attached to. Instead, you can just use transform, e.g.:
if ( transform.eulerAngles.x >= 60 || transform.eulerAngles.x <= -60
|| transform.eulerAngles.z >= 60 || transform.eulerAngles.z <= -60)
{
transform.rotation = Quaternion.identity;
}
Basicaly, you want to make limit of rotation of any axis - x,y, or z.
if yes, then here is the solution :
Program:
Rotating A cube not more that 60 degree in x and z only.
var rotValue += Time.deltaTime;
Cube.transform.rotaion = Quaternion.Eular(Mathf.Clamp(rotaValue,0,60), 0, Mathf.Clamp(rotaValue,0,60));
you can use Mathf.clamp for Clamping any Float value Between min and max.
hope, problem solved.
Skip all the above comments. I found a way to get the exact rotation values as in INSPECTOR. I am showing for angle (x). The code is as follows:
public Transform GameObject;
void Update()
{
float Rotation;
if(GameObject.eulerAngles.x <= 180f)
{
Rotation = GameObject.eulerAngles.x;
}
else
{
Rotation = GameObject.eulerAngles.x - 360f;
}
}
I'm building a topdown game with my main player rotating towards the mouse pointer but for some reason the player looks at the pointer from his right(his x axis) and i need need him to look from his Y.
I tried multiple ways and still the same as in i tried changing the vector from vector3 to vector2 but it will make things i don't need it to do, and i even tried using Quaternions.
void controlScheme()
{
if (Input.GetKey(KeyCode.W))
{
transform.Translate(Vector3.up * PlayerSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey(KeyCode.S))
{
transform.Translate(Vector3.down * PlayerSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey(KeyCode.A))
{
transform.Translate(Vector3.left * PlayerSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey(KeyCode.D))
{
transform.Translate(Vector3.right * PlayerSpeed * Time.deltaTime,Space.World);
}
transform.up = dir;*/
var dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
the only weird thing that there is no code the tell the engine to make the player rotate towards the mouse from the player's right side.
One solution is to find a vector you want the character to rotate "from" -- the direction of the sprite's "front" -- and where it should rotate "to" -- the direction from the character to the mouse position -- and then use transform.rotation.SetFromToRotation to set any rotation necessary to make that change:
Vector3 desiredDirection = Camera.main.WorldToScreenPoint(transform.position) - Input.mousePosition;
Vector3 startDirection = Vector3.up; // the vector direction of the character's
// "front" before any rotation is applied.
transform.rotation.SetFromToRotation(startDirection, desiredDirection);
Vector2 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - this.transform.position;
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
this.transform.rotation = Quaternion.Euler(0f, 0f, rot_z -90);
i found a way with code though still the character was looking at the mouse pointer from his right, i rotated him -90 degrees so it can look better again, my problem was a bit dumb but still there wasn't a proper way to fix this.
Thank you guys. :D
This has been an issue for a week now. I can't seem to figure it out. I am trying to flip my submarine on its y axis once its goes upside-down. it rotates on my mouse position.
This code rotates my submarine on mouse position which is perfect.
Vector3 RayPos = cam.WorldToScreenPoint(transform.position);
Vector3 dir = Input.mousePosition - RayPos;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation,
rotateSpeed * Time.deltaTime);[sub flipping y][1]
Now this code is my problem. Once my sub goes upside down it flips (y) but
it only does it once and then when I go back the correct way it won't flip
on (y) anymore.
Debug.Log(Mathf.Abs(Vector3.Dot(transform.up, Vector3.up)));
if (Mathf.Abs(Vector3.Dot(transform.up, Vector3.down)) < 0.125f)
{
if (Mathf.Abs(Vector3.Dot(transform.right, Vector3.down)) > 0.825f)
{
SubTrans.localScale = new Vector3(transform.localScale.x, -1,
transform.localScale.z);
}
else
{
SubTrans.localScale = new Vector3(transform.localScale.x, 1,
transform.localScale.z);
}
}
if (Mathf.Abs(Vector3.Dot(transform.up, Vector3.down)) < 0.125f)
I assume this makes your code perform the swap only when the sub is ~90 deg to the ground. This is fine because the absolute value means it occurs on both left & right sides.
if (Mathf.Abs(Vector3.Dot(transform.right, Vector3.down)) > 0.825f)
However this is wrong because of the absolute value. It treats up & down the same (comparatively since you're using transform.right), meaning it always flips you because abs(transform.right) is always >0.8 when the previous condition is valid.
You should be checking whether the sub is pointing up or down by checking the up direction like this
if (Mathf.Abs(Vector3.Dot(transform.up, Vector3.up)) > 0f) //less than 90deg angle with up
//flip sub upwards
else
//flip downwards
You can keep the outer if conditional if you want it to flip at certain times, but this is all that's needed.