Slowly rotate an object in the z-axis - c#

How to slowly rotate an object in the z-axis?
I have an object at an angle z=0 and I want it to move to z=100.
How do I do it so it slowly rotates in like 5 seconds?
public Vector3 rotationDirection;
public float durationTime;
private float smooth;
void Update()
{
smooth = Time.deltaTime * durationTime;
transform.Rotate(rotationDirection * smooth);
}
rotationDirection should be from (0,0,0) to (0,0,20) however the rotation does not stop after reaching the angle. How do I stop it when it reaches (0,0,20)?

Using Quaternion.RotateTowards did the work.
void Update()
{
Vector3 direction = new Vector3(0, 0, 20);
Quaternion targetRotation = Quaternion.Euler(direction);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * 20f);
}

Related

How to limit the movement to only move the z axis

How to limit my ai movement to move only on the z axis. Ive already tried freezing the rotation and position on it's rigidbody but instead when i jump my ai also goes up with me on it's position and slightly rotates towards me.
private void Update()
{
StopFollowing();
Vector3 relativePos = target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos);
Quaternion current = transform.localRotation;
transform.localRotation = Quaternion.Slerp(current, rotation, Time.deltaTime
* LookSpeed);
}
// Update is called once per frame
void followPlayer()
{
Vector3 pos = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
rig.MovePosition(pos);
;
}
Freezing the rigidbody will only affect physics (using AddForce or rb.velocity)
You are using MoveTowards (basically teleporting it ignoring physics)
But you can limit it to Z-Axis manually:
void followPlayer()
{
Vector3 targetPos = target.position; // copy target Position
targetPos.x = transform.position.x; // keep x
targetPos.y = transform.position.y; // keep y
Vector3 pos = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime); // now only considers z-difference
rig.MovePosition(pos);
}
You basically modify the target Position to be equal on the x and y axis, so that the MoveTowards only uses Z effectively.

How to add relative movement to multiple virtual cameras?

I am using a Cinemachine state driver to transition between my 8 directional cameras orbiting my player. Right now my player script is set to a basic isometric character controller:
Player.cs
public float speed = 5f;
Vector3 forward;
Vector3 right;
// Start is called before the first frame update
void Start()
{
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
// Update is called once per frame
void Update()
{
if (Input.anyKey)
{
Move();
}
}
void Move ()
{
Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Vector3 rightMovement = right * speed * Time.deltaTime * Input.GetAxis("Horizontal");
Vector3 upMovement = forward * speed * Time.deltaTime * Input.GetAxis("Vertical");
Vector3 heading = Vector3.Normalize(rightMovement + upMovement);
transform.forward += heading;
transform.position += rightMovement;
transform.position += upMovement;
}
I want the players move direction to reflect the direction of the camera. For example, using W (from WASD) will always move the player up. Could I edit the script to pick up the direction of each of my virtual cameras and add that to my player controller or is there a better way?
To solve this problem you have to change the movement of the keys according to the angle of the camera. This is done as follows with transform.TransformDirection. When the movement is synchronized with the direction of the camera, it causes the W key to press the character towards the ground, because the angle in front of the camera is inside the ground. To solve the problem, we set y to zero and then normalize the axis.
public float speed = 10f;
void Update()
{
var moveInput = new Vector3(Input.GetAxis("Horizontal"), 0f , Input.GetAxis("Vertical"));
moveInput = Camera.main.transform.TransformDirection(moveInput);
moveInput.y = 0;
moveInput = moveInput.normalized;
transform.position += moveInput * Time.deltaTime * speed;
}

Rotate 2D object linearly

My 2D object is looking up (transform.up = (0,1)).
When I click somewhere in the screen, I want the object to look to where I clicked. I also want it to rotate linearly: it should rotate d degrees per second, implying that it takes twice the time to rotate twice the angle.
Here is my code:
void Update() {
if (Input.GetMouseButtonDown(0)) {
Vector2 wPos = cameraRef.ScreenToWorldPoint(Input.mousePosition);
StartCoroutine(LookAt(mouseScreenPosition));
}
}
public IEnumerator LookAt(Vector2 position) {
Vector2 direction = (position - (Vector2) transform.position).normalized;
float angle = Vector2.SignedAngle(direction, transform.up);
float startAngle = transform.eulerAngles.z;
for(float t = 0; t <= 1; t += Time.deltaTime * (180 / Mathf.Max(1, Mathf.Abs(angle)))) {
transform.eulerAngles = new Vector3(0, 0, Mathf.Lerp(startAngle, startAngle - angle, t));
yield return null;
}
}
The factor I multiply Time.deltaTime is 180 / Mathf.Max(1, Mathf.Abs(angle)), which says that the bigger the angle, the bigger the time it takes to rotate, but I don't know if I'm doing it right (it works) or if this is the better way to do it.
Define some rotationSpeed field:
public float rotationSpeed = 90f;
Use Quaternion.LookRotation to get the Quaternion you want to rotate towards. You want the local forward to point in the global forward direction and local up to point towards the target position, so use Quaternion.LookRotation(Vector3.forward,targetDirection):
public IEnumerator LookAt(Vector2 position) {
// casting to Vector2 and normalizing is redundant
Vector3 targetDirection = position - transform.position;
Quaternion targetRotation = Quaternion.LookRotation(Vector3.forward, targetDirection);
Then use Quaternion.RotateTowards with the max amount of degrees you want to rotate in that frame until you are done rotating toward the goal rotation:
while (Quaternion.Angle(targetRotation, transform.rotation) > 0.01)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation,
time.deltaTime * rotationSpeed);
}
Altogether:
public float rotationSpeed = 90f;
public IEnumerator LookAt(Vector2 position) {
// casting to Vector2 and normalizing is redundant
Vector3 targetDirection = position - transform.position;
Quaternion targetRotation = Quaternion.LookRotation(Vector3.forward, targetDirection);
while (Quaternion.Angle(targetRotation, transform.rotation) > 0.01)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation,
time.deltaTime * rotationSpeed);
}
}

Unity 3d, point object towards mouse (3d space)

I searched around for a while but I couldn't figure out how to solve this nasty bug. I am using a top down view (pointing towards -z), basically 2d with 3d objects and camera in perspective mode.
I need to orient an object towards the mouse , ignoring the z aspect, as everything moves on the same plane.
I am using the following code:
Vector3 mouseToWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition + new Vector3(0, 0, 1f));
mouseToWorld.z = 0f;
Vector3 difference = mouseToWorld - transform.position;
difference.Normalize();
float angle = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, angle - 90);
Unfortunately it only works when the object is still, and breaks as soon as the velocity is > 0;
Any hint would be appreciated :)
p.s. I am adding 1 to the z and then resetting it, because otherwise the mouseToWorld is constantly 0 wherever I move the pointer.
Perhaps it breaks because the velocity vector and the mouse direction aren't the same.
the following script will make an arrow follow the mouse, It's basically the same as yours except it updates the position as well:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowMouse : MonoBehaviour {
public float moveSpeed = 0.01f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.position = Vector2.Lerp(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition), moveSpeed);
Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
difference.Normalize();
float rotation_z = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotation_z);
}
}
Thanks for the answer! I figured out you need to subtract the distance between the player and the camera to the initial mouse position:
Vector3 mouseToWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition - new Vector3(0, 0, Camera.main.transform.position.z));
Here the working script:
Vector3 mouseToWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition - new Vector3(0, 0, Camera.main.transform.position.z));
//Debug.DrawLine(transform.position, mouseToWorld);
mouseToWorld.z = 0f;
Vector3 difference = mouseToWorld - transform.position;
difference.Normalize();
float angle = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, angle - 90);

Unity 3D how to rotate an object so that its oriented correctly based on the ground plane?

I'm using an asset called Dreamteck Splines to create a path, what I'm trying to do is make it so when I rotate the spline the game object the pink cube in this case, also rotates so it's oriented correctly on the path whether its upside down or sideways like a roller coaster. For some reason, I can only rotate the path to about 90 degrees before the cube stops rotating to align itself to the path.
GIFF
if (Input.GetKey(KeyCode.W))
{
vehicle.transform.Translate(0, 0, speed * Time.deltaTime);
}
if (Physics.Raycast(vehicle.transform.position, Vector3.down, out hit, 100))
{
Vector3 surfaceNormal = hit.normal; // Assign the normal of the surface to surfaceNormal
Vector3 forwardRelativeToSurfaceNormal = Vector3.Cross(vehicle.transform.InverseTransformDirection(vehicle.transform.right), surfaceNormal);
Quaternion targetRotation = Quaternion.LookRotation(forwardRelativeToSurfaceNormal, surfaceNormal); //check For target Rotation.
vehicle.transform.rotation = Quaternion.Lerp(vehicle.transform.rotation, targetRotation, Time.deltaTime * 20); //Rotate Character accordingly.
}
I found this which does what I was trying to achieve:
void Update()
{
/*Here we get user input to calculate the speed the ship will get*/
if (Input.GetKey(KeyCode.W))
{
/*Increase our current speed only if it is not greater than fwd_max_speed*/
current_speed += (current_speed >= fwd_max_speed) ? 0f : fwd_accel * Time.deltaTime;
}
else
{
if (current_speed > 0)
{
/*The ship will slow down by itself if we dont accelerate*/
current_speed -= brake_speed * Time.deltaTime;
}
else
{
current_speed = 0f;
}
}
/*We get the user input and modifiy the direction the ship will face towards*/
yaw += turn_speed * Time.deltaTime * Input.GetAxis("Horizontal");
/*We want to save our current transform.up vector so we can smoothly change it later*/
prev_up = transform.up;
/*Now we set all angles to zero except for the Y which corresponds to the Yaw*/
transform.rotation = Quaternion.Euler(0, yaw, 0);
RaycastHit hit;
if (Physics.Raycast(transform.position, -prev_up, out hit))
{
Debug.DrawLine(transform.position, hit.point);
/*Here are the meat and potatoes: first we calculate the new up vector for the ship using lerp so that it is smoothed*/
Vector3 desired_up = Vector3.Lerp(prev_up, hit.normal, Time.deltaTime * pitch_smooth);
/*Then we get the angle that we have to rotate in quaternion format*/
Quaternion tilt = Quaternion.FromToRotation(transform.up, desired_up);
/*Now we apply it to the ship with the quaternion product property*/
transform.rotation = tilt * transform.rotation;
/*Smoothly adjust our height*/
smooth_y = Mathf.Lerp(smooth_y, hover_height - hit.distance, Time.deltaTime * height_smooth);
transform.localPosition += prev_up * smooth_y;
}
/*Finally we move the ship forward according to the speed we calculated before*/
transform.position += transform.forward * (current_speed * Time.deltaTime);
}

Categories