Rotate 2D object linearly - c#

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);
}
}

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.

Get WASD keys to follow camera rotation in Unity

I understand there are many answers to this online but I was unable to apply them correctly to my code.
I have tried using pre-made player assets but could not get that to work.
Vector3 pos = transform.position;
public float X;
public float Y;
public float Z;
// Used to tilt camera up and down
float tilt = 0;
if (Input.GetMouseButton(1))
{
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.rotation.eulerAngles.x;
Y = transform.rotation.eulerAngles.y;
Z = transform.rotation.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
//Spaceship does not go in direction it is facing once panned
if (Input.GetKey("w"))
{
//transform.rotation = Quaternion.Euler(0, Y, tilt);
pos.z += speed * Time.deltaTime;
}
if (Input.GetKey("s"))
{
pos.z -= speed * Time.deltaTime;
}
if (Input.GetKey("d"))
{
pos.x += speed * Time.deltaTime;
// DEBUG Does not work properly while mouse held down
//transform.Rotate(-1, 0, 0);
}
if (Input.GetKey("a"))
{
pos.x -= speed * Time.deltaTime;
}
transform.position = pos;
Assuming here the "Camera" equals transform you can simply use its local axis transform.forward
Returns a normalized vector representing the blue axis of the transform in world space.
and transform.right
Returns a normalized vector representing the red axis of the transform in world space.
like e.g.
private void Update()
{
if (Input.GetMouseButton(1))
{
// NOTE: I DON'T UNDERSTAND THIS CODE BLOCK YET
// YOU KNOW E.G. THAT IF YOU "transform.eulerAngles.x" ALREADY IS "45°"
// THE "tilt" WOULD JUMP EVERY FRAME IN HUGER STEPS (45 -> 90 -> 180 - 360 ....)
// ALSO WHY ROTATE IN X AXIS IF AFTERWARDS YOU RESET THE X ROTATION
// AND RATHER APPLY IT TO Z?
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.eulerAngles.x;
Y = transform.eulerAngles.y;
Z = transform.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
Vector3 movement = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
movement += transform.forward;
}
if (Input.GetKey(KeyCode.S))
{
movement -= transform.forward;
}
if (Input.GetKey(KeyCode.D))
{
movement += transform.right;
}
if (Input.GetKey(KeyCode.A))
{
movement -= transform.right;
}
// I would do it like this to make sure that diagonal movement
// does not move faster
transform.position = movement.normalized * speed * Time.deltaTime;
}

Slowly rotate an object in the z-axis

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);
}

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);
}

Unity3D Move Camera with mouse on HORIZONTAL axis [duplicate]

I have a main camera in Unity3D that I want to rotate depending on mouse input, so it works as a first person video-game where you move the mouse depending on where do you want to look at.
The starting values of the camera (Transform tab in Inspector tab in Unity) are:
Position: X = -1, Y = 1, Z = -11.
Rotation: X = 0, Y = 0, Z = 0.
Scale: X = 1, Y = 1, Z = 1.
I added a Script component for the Main Camera. And it is the following class:
using UnityEngine;
using System.Collections;
public class CameraMove : MonoBehaviour {
float deltaRotation = 50f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.GetAxis("Mouse X") < 0){
//Code for action on mouse moving left
transform.Rotate (new Vector3 (0f, -deltaRotation, 0f) * Time.deltaTime);
}
else if(Input.GetAxis("Mouse X") > 0){
//Code for action on mouse moving right
transform.Rotate (new Vector3 (0f, deltaRotation, 0f) * Time.deltaTime);
}
if(Input.GetAxis("Mouse Y") < 0){
//Code for action on mouse moving left
transform.Rotate (new Vector3 (deltaRotation, 0f, 0f) * Time.deltaTime);
}
else if(Input.GetAxis("Mouse Y") > 0){
//Code for action on mouse moving right
transform.Rotate (new Vector3 (-deltaRotation, 0f, 0f) * Time.deltaTime);
}
}
}
However, when I play the scene the camera doesn't rotate like it should. The values of the rotation change in x-axis, y-axis and even for z-axis.
What am I doing wrong?
That's a problem with how Quaternion is calculated. This happens when multiple axis are being modified. If you comment all the x rotation or the y rotation, and only rotate in one axis at a time, you will realize that this problem will go away.
To properly rotate your camera with the mouse input, use the eulerAngles or localEulerAngles variables. The option between these two depends on what you are doing.
public float xMoveThreshold = 1000.0f;
public float yMoveThreshold = 1000.0f;
public float yMaxLimit = 45.0f;
public float yMinLimit = -45.0f;
float yRotCounter = 0.0f;
float xRotCounter = 0.0f;
// Update is called once per frame
void Update()
{
xRotCounter += Input.GetAxis("Mouse X") * xMoveThreshold * Time.deltaTime;
yRotCounter += Input.GetAxis("Mouse Y") * yMoveThreshold * Time.deltaTime;
yRotCounter = Mathf.Clamp(yRotCounter, yMinLimit, yMaxLimit);
transform.localEulerAngles = new Vector3(-yRotCounter, xRotCounter, 0);
}

Categories