I just want to use MoveRotation to rotate it in the direction the camera is facing but I can’t match the rotation of the rigidbody with the position of the raycast that I created, or with another method useful for the purpose.
I don’t understand the mistake and have been stuck for a long time.
Vector3 direction;
Vector3 rayDir = new Vector3(Screen.width/2,Screen.height/2);
void Update()
Ray ray = Camera.main.ScreenPointToRay(rayDir);
Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow);
RaycastHit hit = new RaycastHit ();
direction = hit.point - transform.position;
private void FixedUpdate ()
Quaternion rotation = Quaternion.LookRotation(direction);
rig.MoveRotation(rig.rotation * rotation);
Try to interpolate the current rotation towards the new look rotation with Quaternion.Slerp:
float speed = 0.3f;
var currentRotation = rig.rotation;
var targetRotation = Quaternion.LookRotation(direction);
var newRotation = Quaternion.Slerp(
currentRotation, // mix where the rig points now
targetRotation, // with where it should point
speed * Time.fixedDeltaTime); // with this ratio
rig.MoveRotation(newRotation);
You can obviously shorten the code, I just added the variables for clarity. I hope it works, didn’t test it
Thanks for the reply. Without rig.rotation in “MoveRotation” even so the object trembles strongly.
I don’t necessarily need to use the raycast, even without, you have suggestions to rotate the object in the direction the camera is pointing…?
I can’t find a solution useful for the purpose!! xd
Now, I am trying to use the direction of the raycast as a reference point. I would like to create a rotation vector taking into account the X axis of the direction of the raycast, with the X axis of the rotation of the object, in order to create a value where the more the object rotates towards the X axis direction of the raycast more the value decreases going, to stop the rotation of the object when it reaches zero.
Being new to unity, however, I cannot find the definition to indicate the two X axes well because in the script that I made the object continues to rotate; is it possible to relate the two X axes?? or have a similar solution?
Vector3 direction; // raycast vector
//point of origin of the raycast
Vector3 rayDir = new Vector3(Screen.width/2,Screen.height/2);
void Update()
//The raycast starts from the camera.main
Ray ray = Camera.main.ScreenPointToRay(rayDir);
Debug.DrawRay(ray.origin, ray.direction * 10, Color.yellow);
// the direction of rotation is the same as that of the raycast
direction = ray.direction;
direction.y = 0;
private void FixedUpdate ()
//Create a rotation value equal to the position on the X axis of the raycast - the X axis of rotation of the object
Quaternion rotation = Quaternion.Euler(0, direction.x - transform.rotation.x, 0);
rig.MoveRotation(rig.rotation * rotation);
Just to get it right: Do you want to align the rigidbody with the direction of the camera OR with the point where the raycast hit? Don’t worry, we’ll figure this out
Okay, I’m more confident ^ ^.
I put the raycast on the camera because, I thought it would be easier to indicate the position where the camera is pointed and in the future it would also be useful for other purposes. However, it is more complicated because if the camera is pointed in an area where it does not hit anything, then I should give the raycast a maximum length beyond which it gives me a point of impact for the rotation of the object, and I not know good, how to do it.
It would also be enough for me to align the direction of the rigidbody with the direction of the camera if it is too complicated with the raycast.
I tried this script and in fact initially the object rotates towards the camera and then stops when it is in the axis, but only up to a certain point; if I rotate the camera more around the object, the object no longer rotates and does not align.
I’m still confused, because you’re only taking a part of the Euler angles of the rotation.
Do you want to completely make the rig point into the same direction as the cameras “forward” direction? Or should it just point into the same direction but keep the horizontal rotation? Either way, in my opinion, you’re better off sticking to strict vector math.
Here is a full example of how to let the rigidbody point its local forward axis (that’s the blue) into whatever direction you’re giving it
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AlignRotation : MonoBehaviour
{
public Vector3 direction = Vector3.right;
public float speed = 0.3f;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
var currentRotation = rb.rotation;
var targetRotation = Quaternion.LookRotation(direction);
var newRotation = Quaternion.Slerp(
currentRotation, // mix where the rig points now
targetRotation, // with where it should point
speed * Time.fixedDeltaTime); // with this ratio
rb.MoveRotation(newRotation);
}
}
Add this behaviour to the object containing the rigidbody. You can play with “speed” and the direction vector.
If you only want to rotate within the horizontal plane, you’ll just have to project the direction vector onto a horizontal plane using this handy function: Unity - Scripting API: Vector3.ProjectOnPlane
If that is your goal, change the FixedUpdate function of the code above as follows:
void FixedUpdate()
{
var currentRotation = rb.rotation;
var horizontalDirection = Vector3.ProjectOnPlane(direction, Vector3.up);
var targetRotation = Quaternion.LookRotation(horizontalDirection);
var newRotation = Quaternion.Slerp(
currentRotation, // mix where the rig points now
targetRotation, // with where it should point
speed * Time.fixedDeltaTime); // with this ratio
rb.MoveRotation(newRotation);
}
edit: you can obviously set “direction” to Camera.main.transform.forward in the update function
My goal is to have the rigidbody rotate in the direction the camera is pointing. I wanted to simulate and understand the movement mechanism used in third-person games.
I tried your first script (changing in update, direction with Camera.main.transform.forward) and it works, the body rotates until it stops in the forward direction of the camera.
I don’t know if this is the right solution for the purpose but it works and I thank you very very very very very much !!
You can extend that script to only turn the rigidbody if it has some velocity to have the effect that the camera can go around the player without him turing and only when the player is moving, let him turn. You can do so using rb.velocity.magnitude and apply some curve to it (check AnimationCurve).
But I really think to make this look and feel really good, some developer at this studio put a lot of work and trial and error in this.
Yes, I still have to do it but I had already thought of using rb.velocity.magnitude to understand when the object is stopped and allow the rotation of the camera around him.
What I noticed, however, is that when I rotate the camera, regardless of the speed of rotation, the object does not rotate at the same time as I rotate the camera but a fraction of a second later (as if the input starts late).
Do you think it may be because I use transform.position to move the camera?
cam.transform.position = target.transform.position + rotation quaternion //is a example of my script
From what i understand move directly with transform.position respawn the position, does not move it from point A to point B in a fluid way but teleports it, and maybe the input to rotate the object is given only when the camera stops. This is just my guess but I don’t know.
If you change the camera position in an Update() function, that’s as fast and smooth as it gets. If you’re using Input.GetAxis to rotate or move the camera, you might have to change the Player Settings for the axis because it doesn’t just jump to a value when a button is pressed but gradually goes there.
Without knowing more about your setup, I can’t tell where the delay comes from. The fraction of a second you’re talking about it probably not from setting the camera position itself, because that probably happens 60 times per second or more often, which is fast enough for not being noticeable
I use Input.GetAxis MouseX and MouseY to rotate the camera, they are updated and I have no problems with MovePosition (the object moves towards the camera immediately even when I rotate this) but with MoveRotation it moves late.
This is my camera:
public class CameraController : MonoBehaviour
{
public GameObject player;
private Camera cam;
private Transform playerTransform;
public float distanza = 3.0f;
public float sX = 4.0f;
public float sY = 1.0f;
public float currentX = 0f;
public float currentY = 0f;
void Update()
{
currentX += Input.GetAxis("Mouse X") * sX;
currentY += Input.GetAxis("Mouse Y") * sY;
}
void LateUpdate()
{
Vector3 dir = new Vector3(0, 0, -distanza); //introduce la posizione della camera
Quaternion rotation = Quaternion.Euler(currentY, currentX, 0);
cam.transform.position = player.transform.position + rotation * dir;
cam.transform.LookAt(player.transform.position);
}
}
I started a new scene by adding the rotation script to an “Ethan” to have no doubt that something was interfering.
As you can see from the video when I move the camera very slowly then Ethan rotates in sync, but as soon as I move it faster, he rotates late even if I move the camera slightly, as if the input arrives late. I can increase the rotation speed out of all proportion, the speed with which it rotates changes but the rotation will always start with that second of delay, going out of sync.
With the commands on MovePosition I have no problems, even if I quickly rotate the camera the object immediately moves in the direction of the camera, the problem is only for rotation. (video in in quote).
I also thought about changing by moving the object with AddForce and AddTorque but I think it is less suitable for third person movements, I think this method should be better for the purpose, or am I wrong?
Ah, I see
That’s simply the smoothing behaviour that’s in the code that I posted
void FixedUpdate()
{
var currentRotation = rb.rotation;
var horizontalDirection = Vector3.ProjectOnPlane(direction, Vector3.up);
var targetRotation = Quaternion.LookRotation(horizontalDirection);
var newRotation = Quaternion.Slerp(
currentRotation, // mix where the rig points now
targetRotation, // with where it should point
speed * Time.fixedDeltaTime); // with this ratio
rb.MoveRotation(newRotation);
}
If you replace “speed * Time.fixedDeltaTime” by 1, the character follows the camera direction exactly. Then, you can also simplify the code to
var horizontalDirection = Vector3.ProjectOnPlane(direction, Vector3.up);
var targetRotation = Quaternion.LookRotation(horizontalDirection);
rb.MoveRotation(targetRotation);
There’s more to this whole topic though, which goes towards system dynamics and feedback control. If you don’t really want to get into this whole stuff but you’d rather have a camera that “just works”, get your feet wet with Cinemachine. It’s available in the package manager and gives a whole world of possibilities.
Thanks very much for the advice, before learning to use cinemachine I wanted to create a good script for movement.
Unfortunately I have tried both of your scripts but the problem remains the same. Incidentally, if I replace “speed * Time.fixedDeltaTime” to 1, the speed drops dramatically and will spin even more slowly (from what I understand by putting it at 1 it should always be facing the final direction but it is not so for me).
This is all my motion script, I would like you to try it on a camera object to understand if you have the same problems.
I know this is a strange problem. Thanks for your time
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movimento : MonoBehaviour
{
[SerializeField] float walk = 1;
[SerializeField] float run = 2;
Vector3 movement = Vector3.zero;
private Rigidbody rb;
Vector3 direction;
public float speed = 15;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift)) walk = (walk + run);
if (Input.GetKeyUp(KeyCode.LeftShift)) walk = (walk - run);
float Horizontal = Input.GetAxis("Horizontal"); // i valori che avrà lo spostamento.
float Vertical = Input.GetAxis("Vertical");
movement = Camera.main.transform.forward * Vertical + Camera.main.transform.right * Horizontal;
float origMagnitude = movement.magnitude;
movement.y = 0f;
movement = movement.normalized * origMagnitude;
direction = Camera.main.transform.forward;
direction.y = 0;
}
private void FixedUpdate ()
{
rb.MovePosition(rb.position + movement * walk * Time.fixedDeltaTime);
//if (movement != Vector3.zero)
{
var currentRotation = rb.rotation;
var horizontalDirection = Vector3.ProjectOnPlane(direction, Vector3.up);
var targetRotation = Quaternion.LookRotation(horizontalDirection);
var newRotation = Quaternion.Slerp(currentRotation, targetRotation, speed * Time.fixedDeltaTime);
rb.MoveRotation(newRotation);
}
}
}