Rotate GameObject on Z axis while moving forward - c#

Currently I have the following code, and it works 100% for a 3D game, but I can't get it to work for a 2D game.
What it is supposed to do, is once the object gets to the waypoint, it is supposed to rotate towards the new waypoint. What is actually happening is that it is rotating around the x and y axis, and not the z axis. What can I do to make it only rotate on the z axis? The object is supposed to turn as it moves forward based on the turn speed. It shouldn't be an instant turn, unless the turnspeed is a high number. But anyways, again I ask how do I get this code to only roate on the z axis?
void Update () {
if(toWaypoint > -1){
Vector3 targetDir = wayPoints[toWaypoint].position - transform.position;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, turnSpeed * Time.deltaTime, 0.0f);
transform.rotation = Quaternion.LookRotation(newDir);
}
if(!usePhysics && toWaypoint != -1){
transform.Translate(Vector3.forward * Time.deltaTime * speed);
next();
}
}

Look rotation is not dependable for 2D games as the forward axis is different. One workaround is to parent the sprite to an empty GameObject with the z axis (blue arrow) pointed in the direction that the sprite will be rotating.

Looks like you're using Unity3D, which leaves me wondering why you're messing around with the Z-axis in the first place if you're making a game in 2D editing mode. The Z-axis does literally nothing in that mode, unless you set your two axes to include it somehow. My suggestion to you is to switch to 2D editing if you haven't already, then use Vector2s instead of Vector3s.
Also, try using one of the other axes as your axis of rotation (transform.right or .up instead of .forward).

I found what I was looking for:
void Update () {
if(toWaypoint > -1){
Vector3 vectorToTarget = wayPoints[toWaypoint].position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * turnSpeed);
}
if(!usePhysics && toWaypoint != -1){
transform.Translate(Vector3.right * Time.deltaTime * speed);
next();
}
}

Related

Unity: How to limit the rotation of the z axis using Wheel Joint 2D?

I am creating a Jump and run game but you are driving with a car. I use the the Wheel Joint 2D collider and I am also able to jump. Here is my code for the movement:
void Update()
{
movement = Input.GetAxis("Horizontal");
if (Input.GetButtonDown("Jump") && IsGrounded())
{
carRb.velocity = new Vector2(carRb.velocity.x, jumpForce);
}
if (Input.GetButtonUp("Jump") && carRb.velocity.y > 0f)
{
carRb.velocity = new Vector2(carRb.velocity.x, carRb.velocity.y * 0.5f);
}
}
private void FixedUpdate()
{
backTire.AddTorque(-movement * speed * Time.fixedDeltaTime);
frontTire.AddTorque(-movement * speed * Time.fixedDeltaTime);
carRb.AddTorque(-movement * carTorque * Time.fixedDeltaTime);
}
It works just fine but when I am fast and jump I rotate completely around my own axis and I land on my head and can't move anymore. Therefore I want to limit the rotation of the z-axis to a certain degree so that it won't happen anymore. I looked up how to do it but it doesn't fit for my car-context. Do you have any idea?
I would be very grateful
You have multiple options to solve this:
Freeze the rotation axis on the rigibody (very limiting option)
Detect the faulty position as "upside-down + grounded" and respawn the vehicle after 2s
Forcefully rotate the vehicle back to normal rotation when it's grounded (not in air anymore, so you still allow flips in the air)
Limit the angle via script.
Last thing could be done like this:
Vector3 eulerRot = rb.rotation.eulerAngles; // read current rotation
eulerRot.z = Mathf.Clamp(eulerRot .y, minRotation, maxRotation); // clamp it only on z axis.
rb.rotation = Quaternion.Euler(eulerRot); // set clamped rotation

Player unwanted rotation on the Y axis

Any Quaternion genius could tell me what is wrong with my code ? I have this PlayerRotation script that does two things:
Rotate the player's Y axis localy
Align the player to the surface's normals
The PlayerMovement is only making the player go forward on the transform.forward axis. The problem is that when i start playing and going on some upside down surfaces after a while my player's Y axis gets offset with the joystick randomly, like tilting the joystick straight forward makes the player rotate slightly to the right
input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
Vector2 inputDir = input.normalized;
//Angle part
if (inputDir != Vector2.zero)
{
targetAngle = Mathf.Atan2(input.x, input.y) * Mathf.Rad2Deg + cam.eulerAngles.y;
Quaternion localRotation = Quaternion.Euler(0f, targetAngle - lastTargetAngle, 0f);
transform.rotation = transform.rotation * localRotation;
lastTargetAngle = targetAngle;
}
//Raycast part
if (Physics.Raycast(transform.position - transform.up * start, -transform.up, out hit, end))
{
Quaternion targetRotation = Quaternion.FromToRotation(transform.up, hit.normal);
transform.rotation = targetRotation * transform.rotation;
}
After many ajustement a concluded that the problem seems to be coming from the raycast part but i dont understand why
My experience with Quaternions is pretty much limited to using FromToRotation and LookRotation and trial and error until I get it working, so I'm not the most knowledgeable about Quaternions but here is what I think is happening:
You are detecting the rotation between the surface normal and the up vector, and than adding that to your current rotation. The problem with this is that even when your current rotation is already aligned with the surface normal you still add that rotation, causing it to over-rotate.
What you should do is either calculate the rotation from your current upwards direction to the surface normal or do something like I did below, which is fairly easy to understand:
Use your current rotation to determine the direction you want to be looking in
lookDirection = transform.rotation * Vector3.forward
And use your targetRotation, to determine the direction you want to be up
upDirection = targetRotation * Vector3.up
And calculate your final rotation using Quaternion.LookRotation
LookRotation(Vector3 forward, Vector3 upwards)
Resulting in your raycast block looking like this:
Quaternion targetRotation = Quaternion.FromToRotation(transform.up, hit.normal);
transform.rotation = Quaternion.LookRotation(transform.rotation * Vector3.forward, targetRotation * Vector3.up);
EDIT: I am at Uni using my craptop so I haven't actually tested this yet.
I know it's an old post and I can't comment on answers yet but Rishaan's answer worked for me I just had to change:
transform.rotation = Quaternion.LookRotation(transform.rotation * Vector3.forward, targetRotation * Vector3.up);
To:
transform.rotation = Quaternion.LookRotation(targetRotation * Vector3.forward, transform.rotation * Vector3.up);

How to rotate an object along all 3 axes with finger swipe?

I'm working on a simple AR Vuforia application. How can I implement the rotation of an object along all three axes with one finger swipe?
The code I'm currently using has one bug: the rotation of the object depends on its local axes. For example, if I look at the object from the front, everything works as it should, but if I look at the object from the back side, the finger swipe upwards makes it rotate downwards and vice versa.
Here is this script:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X")*rotSpeed*Mathf.Deg2Rad;
float rotY = Input.GetAxis("Mouse Y")*rotSpeed*Mathf.Deg2Rad;
transform.Rotate(Vector3.up, -rotX);
transform.Rotate(Vector3.right, -rotY);
}
This is not what I need, how can I rotate the object according to the finger swipe direction regardless of the angle from which I look at it?
Update
A simple non-AR example, which may help you understand what I need is an iOS game "Space Frontier 2". After a successful launch of the rocket, it lands on the planet and you can rotate the planet with your finger swipe.
Here is the video demo: https://youtu.be/OiNPP1WNIAI
This works nice regardless of your object's rotation, and regardless of your camera position relative to the object:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed;
Camera camera = Camera.main;
Vector3 right = Vector3.Cross(camera.transform.up, transform.position - camera.transform.position);
Vector3 up = Vector3.Cross(transform.position - camera.transform.position, right);
transform.rotation = Quaternion.AngleAxis(-rotX, up) * transform.rotation;
transform.rotation = Quaternion.AngleAxis(rotY, right) * transform.rotation;
}
Make sure your camera has the "MainCamera" tag, or assign the camera externally if necessary.
I do not have the exact code with me right now.
But if you did not update your point of view coordinates, this should be the expected result.
Consider a real ball with 2 colors, blue and red, separated vertically.
When you are in front of it, seeing only the blue side, stroking it up will make the blue side go up and the red side appear from the bottom.
Now move behind it, seeing only the red side, and stroke it up again.
The blue face will go down and appear from the bottom.
Unity applies physics to virtual objects the same way we interact with real objects.
So you need to consider your camera position with the object orientation when you apply movements to it.
You need to apply a transformation matrix to your movement based on your camera location related to the object origin orientation.
I hope this is clear enough to put you on tracks to fix it.
I think you have to somehow clamp the rotation to have the desired behaviour. I wrote a script recently to do just that. I did a little modification though.
public float rotSpeed = 30f;
float ClampAngle(float _angle, float _min, float _max)
{
if (_angle < 0f) _angle = 360 + _angle;
if (_angle > 180f) Mathf.Max(_angle, 360 + _min);
return Mathf.Min(_angle, _max);
}
USAGE:
void RotateGameObject()
{
float h = Input.GetTouch(0).deltaPosition.x * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
float v = Input.GetTouch(0).deltaPosition.y * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
Vector3 rot = transform.rotation.eulerAngles + new Vector3(-v, h, 0f);
//Change the y & z values to match your expected behaviour.
rot.x = ClampAngle(rot.x, -5f, 20f);
//Clamp rotation on the y-axis
rot.y = ClampAngle(rot.y, -20f, 20f);
transform.eulerAngles = rot;
}
See if that works and of course, try to play with the values.

Unity2D Enemy Patrol, weird sprite rotation

Needed help here, I've been following this tutorial about Enemy Patrolling, https://www.youtube.com/watch?v=KKU3ejp0Alg
The tutorial tell us to set 2 Empty Game Objects and the coordinates so the sprite will walk from one direction to another, the walking does working, however the rotation of the sprite became really weird, the 'Worm' sprite is suppose to move left and right now it change into facing upward
Please look at this image,
When moving from left to right
When moving from right to left
public Transform[] patrolPoints;
public float speed;
Transform currentPatrolPoint;
int currentPatrolIndex;
// Use this for initialization
void Start()
{
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * speed);
if (Vector3.Distance(transform.position, currentPatrolPoint.position) < .1f) {
if (currentPatrolIndex + 1 < patrolPoints.Length)
currentPatrolIndex++;
else
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
Vector3 patrolPointDir = currentPatrolPoint.position - transform.position;
float angle = Mathf.Atan2(patrolPointDir.y, patrolPointDir.x) * Mathf.Rad2Deg - 90f;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 180f);
}
This is the code
Thank you
You can pass the optional parameter Space.World to your translation to move your object relative to world space instead of object space. That should prevent your object from rotating.
transform.Translate(Vector3.up * Time.deltaTime * speed, Space.World);
You can read more about it in the documentation.
You probably rotated the enemy sprite by 90 degrees. Try placing all your scripts into empty game object with no rotation, than place the enemy sprite as child of the empty game object and rotate as you need. This way your logic won't collide with your graphics.

Unity - Sprite Rotation + Get Angle

Im trying to get a sprite rotation by key input (arrow down or up).
The point is lifting the arrow (sprite) to choose the angle. Its like a system of a golf game, actually.
So far i tried:
void Update () {
if (Input.GetKey(KeyCode.UpArrow)){
transform.Rotate (Vector3.forward * -2); }
if (Input.GetKey(KeyCode.DownArrow)){
transform.Rotate (Vector3.forward * +2); }
}
I will need the angle, since it will be related to a "shot" part i will be doing next. My point is setting the right angle with the keys up and down.
I can move the "arrow" sprite with my code, but i cannot set the max angle (90), minimum (0) and get the angle to use in the shot ^^
Hard question to answer without just simply giving you the code. This code works by assuming your character's forward vector is actually it's right vector (common in 2d sprite games) in order to shoot in the other direction, rotate your objects y axis 180.
float minRotation = 0f;
float maxRotation = 90f;
float rotationSpeed = 40f; //degrees per second
//get current rotation, seeing as you're making a sprite game
// i'm assuming camera facing forward along positive z axis
Vector3 currentEuler = transform.rotation.eulerAngles;
float rotation = currentEuler.z;
//increment rotation via inputs
if (Input.GetKey(KeyCode.UpArrow)){
rotation += rotationSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.DownArrow)){
rotation -= rotationSpeed * Time.deltaTime;
}
//clamp rotation to your min/max
rotation = Mathf.Clamp(rotation, minRotation, maxRotation );
//set rotation back onto transform
transform.rotation = Quaternion.Euler( new Vector3(currentEuler.x, currentEuler.y, rotation));
If you were making a golf game, you'd set the ball's velocity to be transform.right * shotPower

Categories

Resources