Rotate rigidbody with moverotation in the direction of the camera - c#

I want to use moverotation to rotate the object in the direction of the Main Camera, like a common third person shooter, but I don't know how to set the quaternion values or otherwise
`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 rig;
// Start is called before the first frame update
void Start()
{
rig = 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");.
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;
}
private void FixedUpdate ()
{
rig.MovePosition(rig.position + movement * walk * Time.fixedDeltaTime);
Quaternion rotation = Quaternion.Euler(???);
rig.MoveRotation(rig.rotation * rotation);
}
}`

i use a coroutine to do smooth rotation. I use Quaternion.LookRotation for the job.
so you indicate the position of object to look at and the duration of animation. Here you want to rotate face to the main camera
StartCoroutine(SmoothRotation(Camera.main.transform, 3f));
:
:
IEnumerator SmoothRotation(Transform target, float duration)
{
float currentDelta = 0;
var startrotation = transform.rotation;//use your rigisbody if you want here i use the gameobject
var LookPos = target.position - transform.position;
var finalrot = Quaternion.LookRotation(LookPos);
while (currentDelta <= 1f)
{
currentDelta += Time.deltaTime / duration;
transform.rotation = Quaternion.Lerp(startrotation, finalrot, currentDelta);//
yield return null;
}
transform.rotation = finalrot;
}
if you want to see (in scene when running) where your camera points just add this line of code in update():
Debug.DrawRay(Camera.main.transform.position, Camera.main.transform.TransformDirection(Vector3.forward) * 10f, Color.black);
if you want to point in same direction tha nthe Camera just change the line of finalrot in SmoothRotation Method:
var finalrot = Camera.main.transform.rotation;
you dont need to calculate the LookPos
for your problem of crazy rotation, i suggest you to reset rotation x and z
direction = hit.transform.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(direction);
rotation.x = 0f;
rotation.z = 0f;
a tips to detect object what you want with the raycast inside spere : Physics.OverlapSphere: you could select what you want to cast when using the optional parameter layermask
private void DetectEnemy(Vector3 center, float radius)
{
var hitColliders = Physics.OverlapSphere(center, radius );
for (var i = 0; i < hitColliders.Length; i++)
{
print(hitColliders[i].name + "," + hitColliders[i].transform.position);
// collect information on the hits here
}
}

I created a raycast from the camera, and I would like to rotate the rigidbody to where the raycast is pointing but if i launch unity, it rotated wildly. What is the error?
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);

Add a character controller component, this is what is for. See:
https://docs.unity3d.com/Manual/class-CharacterController.html

Related

How to make my character look in the direction of the camera in Unity 3d?

My character has a chinemachine camera attached to it and it is moving perfectly fine. But when I move my mouse to change the camera direction it is not looking in that direction. And I can't figure out how to make it look in that direction.
I have a reference to the original camera at the top of the script by the name cam.
The script has different functions for movement, rotation, animation, etc.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//so that unity recognises the callbacks ctx passed to the movementinput
using UnityEngine.InputSystem;
public class AnimationAndMovController : MonoBehaviour
{
public Transform cam;
public float speed;
//here we are creadting three vars for the animation
//vector2 currentMovementInput stores the input axis of the player
//vector3 store the current position of the player
PlayerInput playerInput;
CharacterController characterController;
Animator animator;
Vector2 currentMovementInput;
Vector3 currentMovement;
Vector3 currentRunMovement;
Vector3 moveDir;
bool isMovementPressed;
bool isRunPressed;
float rotationFactor = 15.0f;
// float turnSmoothtime = 0.1f;
// float turnSmoothVelocity ;
float runMultiplier = 4.0f;
int walkHash ;
int runHash ;
//runs before start function
void Awake(){
playerInput = new PlayerInput();
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
// walkHash = Animator.StringToHash("Walking");
// runHash = Animator.StringToHash("run");
//now instead of writing the logic three times we pass the callback ctx to the movementInput() function
playerInput.CharacterControls.Move.started += movementInput;
playerInput.CharacterControls.Move.canceled += movementInput;
playerInput.CharacterControls.Move.performed += movementInput;
playerInput.CharacterControls.Run.started += handleRun;
playerInput.CharacterControls.Run.canceled += handleRun;
}
void handleRun(InputAction.CallbackContext ctx){
isRunPressed = ctx.ReadValueAsButton();
}
//we are going to handle rotations with quaternions
void handleRotation(){
Vector3 positionToLookAt;
positionToLookAt.x = currentMovement.x;
positionToLookAt.y = 0.0f ;
positionToLookAt.z = currentMovement.z;
Vector3 direction = new Vector3(positionToLookAt.x, 0.0f, positionToLookAt.z).normalized;
Quaternion currentRotation = transform.rotation;
//we take the current rotation and the target rotation and slerp them *FYI : Im still not sure how slerp works
if(isMovementPressed){
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactor * Time.deltaTime);
}
}
//we are passing the callback ctx to this function so that we dont have to call the function everytime we start, cancel or perform the movement
void movementInput(InputAction.CallbackContext ctx){
//we are setting the movement input to the axis of the player
currentMovementInput = ctx.ReadValue<Vector2>();
currentMovement.x = currentMovementInput.x;
//we are setting the z axis to the y axis of the player because we move y axis on keyboard or joystick but in game we move in z axis
currentMovement.z = currentMovementInput.y;
//now we are setting the run movement to the current movement
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
void handleAnimation(){
bool walk = animator.GetBool("walking");
bool run = animator.GetBool("run");
if(isMovementPressed && !walk){
animator.SetBool("walking", true);
}
else if(!isMovementPressed && walk){
animator.SetBool("walking", false);
}
if((isMovementPressed && isRunPressed) && !run){
animator.SetBool("run", true);
}
else if((!isMovementPressed || !isRunPressed)&& run){
animator.SetBool("run", false);
}
}
void handleGravity(){
//we are setting the gravity to -9.8f because we are moving in y axis
if(characterController.isGrounded){
float groundGravity = -0.05f;
currentMovement.y = groundGravity;
currentRunMovement.y = groundGravity;
}
else{
float gravity = -9.8f;
currentMovement.y += gravity * Time.deltaTime;
currentRunMovement.y += gravity * Time.deltaTime;
}
}
// Update is called once per frame
void Update()
{
handleAnimation();
handleRotation();
handleGravity();
if(isRunPressed){
characterController.Move(currentRunMovement * Time.deltaTime);
}
else{
characterController.Move(currentMovement * Time.deltaTime);
}
}
//we are checking if the player script gets enabled or disabled and accordingly we are enabling or disabling the player input
void OnEnable(){
playerInput.CharacterControls.Enable();
}
void OnDisable(){
playerInput.CharacterControls.Disable();
}
}
That quite a lot of code to dive into.
I'd try:
Quaternion cameraRot = Camera.Main.transform.rotation;
transform.rotation = cameraRot;
Or if you have a target Quaternion.LookRotation:
Vector3 relativePos = target.position - transform.position;
// the second argument, upwards, defaults to Vector3.up
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
Hope that helps
Use Transform.LookAt, which points a Game Object's rotation towards a target's position.
In your case, this would be
transform.LookAt(cam);
here is the code that I use..
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCamera : MonoBehaviour
{
public float sensitivity = 1000f;
public float xRotation = 0f;
public Transform playerBody;
public Quaternion localRotate;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float MX = Input.GetAxis("Mouse X")*sensitivity*Time.deltaTime;
float MY = Input.GetAxis("Mouse Y")*sensitivity*Time.deltaTime;
xRotation -= MY;
xRotation = Mathf.Clamp(xRotation,-90f,90f);
transform.localRotation = Quaternion.Euler(xRotation,0f,0f);
localRotate = transform.localRotation;
playerBody.Rotate(Vector3.up * MX);
}
}
the player body you see is the player object to you character...
note that the camera is use is not In. cinema chine and is inside of the player...

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

Adding a clamp to the rotation of a 2D object in Unity2D

I have been working for a long time trying to get a clamp implemented on my 2D object in Unity2D. I have struggled with this issue for weeks now. I have a rocketship that moves upwards on it's own, and I'm trying to make it where you can't go further than 40 degrees rotating. Some details to note is that the ship rotates(x-axis of course) and moves toward the mouse(x-axis, doesn't go further up more then the current velocity) as a way to avoid obstacles which are coming soon. Here's my code for the ship:
public class MiniGameRocketShipController : MonoBehaviour
{
public Vector2 velocity = new Vector2(0f, 1500f);
private Vector2 directionX;
private Vector2 directionY;
public Rigidbody2D rb;
public new Camera camera;
public float moveSpeed = 100f;
public float rotation;
private void Start()
{
rotation = rb.rotation;
}
private void Update()
{
rb.AddForce(velocity * Time.deltaTime);
rb.velocity = new Vector2(directionX.x * moveSpeed, directionY.y * moveSpeed);
FaceMouse();
}
void FaceMouse()
{
if (rotation > 180)
{
rotation = 360;
}
rotation = Mathf.Clamp(rotation, -40f, 40f);
rb.rotation = rotation;
Vector3 mousePosition = Input.mousePosition;
mousePosition = camera.ScreenToWorldPoint(mousePosition);
directionX = (mousePosition - transform.position).normalized;
directionY = transform.position.normalized;
transform.up = directionX;
}
}
You can use Vector2.SignedAngle and Mathf.Clamp to do this. Explanation in comments:
// world direction to clamp to as the origin
Vector2 clampOriginDirection = Vector2.up;
// what local direction should we compare to the clamp origin
Vector2 clampLocalDirection = Vector2.up;
// how far can the local direction stray from the origin
float maxAbsoluteDeltaDegrees = 40f;
void ClampDirection2D()
{
// world direction of the clamped local
// could be `... = transform.up;` if you are ok hardcoding comparing local up
Vector2 currentWorldDirection = transform.TransformDirection(clampLocalDirection);
// how far is it from the origin?
float curSignedAngle = Vector2.SignedAngle(clampOriginDirection, currentWorldDirection);
// clamp that angular distance
float targetSignedAngle = Mathf.Clamp(curSignedAngle, -maxAbsoluteDeltaDegrees,
maxAbsoluteDeltaDegrees);
// How far is that from the current signed angle?
float targetDelta = targetSignedAngle - curSignedAngle;
// apply that delta to the rigidbody's rotation:
rb.rotation += targetDelta;
}

Camera always behind player in Unity3d

I'm struggling with this for quit some time now. I have GameObject, being a sphere, which is my player on a 3d Terrain. I have a Camera which is always on a fixed distance from the player, follows it where it goes with below script:
public GameObject player;
private Vector3 offset;
// Use this for initialization
void Start () {
offset = transform.position - player.transform.position;
}
void LateUpdate () {
transform.position = player.transform.position + offset;
}
So far so good. However what I actually want is that the camera rotates with the player, so it always looks into the direction where the sphere is moving, but always stays behind the player at the same fixed distance, so that the player is always visible in the camera view.
There are a lot of scripts available, but the problem with the onces I've seen so far is that the camera indeed rotate with the player, but because the player actually is a rolling sphere the camera view is rolling and turning as well.
The best script I found so far is below, but this one has the same problem as the other onces, the camera rolls with the player.
public Transform target;
public float distance = 3.0f;
public float height = 3.0f;
public float damping = 5.0f;
public bool smoothRotation = true;
public bool followBehind = true;
public float rotationDamping = 10.0f;
void Update () {
Vector3 wantedPosition;
if(followBehind)
wantedPosition = target.TransformPoint(0, height, -distance);
else
wantedPosition = target.TransformPoint(0, height, distance);
transform.position = Vector3.Lerp (transform.position, wantedPosition, Time.deltaTime * damping);
if (smoothRotation) {
Quaternion wantedRotation = Quaternion.LookRotation(target.position - transform.position, target.up);
//Quaternion ownRotation = Quaternion.RotateTowards;
transform.rotation = Quaternion.Slerp (transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
}
else transform.LookAt (target, target.up);
}
Can anyone help me with this please?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public GameObject player;
public float cameraDistance = 10.0f;
// Use this for initialization
void Start () {
}
void LateUpdate ()
{
transform.position = player.transform.position - player.transform.forward * cameraDistance;
transform.LookAt (player.transform.position);
transform.position = new Vector3 (transform.position.x, transform.position.y + 5, transform.position.z);
}
}
My solution (based on #brennon-provencher answer) with smoothness and auto offset:
public class CameraFollow : MonoBehaviour
{
public GameObject target;
public float speed = 5;
Vector3 offset;
void Start()
{
offset = target.transform.position - transform.position;
}
void LateUpdate()
{
// Look
var newRotation = Quaternion.LookRotation(target.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, speed * Time.deltaTime);
// Move
Vector3 newPosition = target.transform.position - target.transform.forward * offset.z - target.transform.up * offset.y;
transform.position = Vector3.Slerp(transform.position, newPosition, Time.deltaTime * speed);
}
}
You need to move your camera position based on sphere movement direction -
public GameObject player;
private Vector3 offset;
float distance;
Vector3 playerPrevPos, playerMoveDir;
// Use this for initialization
void Start () {
offset = transform.position - player.transform.position;
distance = offset.magnitude;
playerPrevPos = player.transform.position;
}
void LateUpdate () {
playerMoveDir = player.transform.position - playerPrevPos;
playerMoveDir.normalize();
transform.position = player.transform.position - playerMoveDir * distance;
transform.LookAt(player.transform.position);
playerPrevPos = player.transform.position;
}
Edit 2: To fix flickering camera, try this -
void LateUpdate () {
playerMoveDir = player.transform.position - playerPrevPos;
if (playerMoveDir != Vector3.zero)
{
playerMoveDir.normalize();
transform.position = player.transform.position - playerMoveDir * distance;
transform.position.y += 5f; // required height
transform.LookAt(player.transform.position);
playerPrevPos = player.transform.position;
}
}

How to stop rotation by LerpAngle after -90°

I have colliders where i can turn to the sides and i want camera to rotate as a player turn to the side. I'm using Mathf.LerpAngle for that, but when I press the key for turn to side, camera is rotating in loop. How can I make rotation stop?
The problem is that everytime I turn player should go -90 degrees to the left +90 to the right and there will be more turns so i can't use functions for setting rotation.
I was already trying to make it stop by that if statement with (lAngle > 90f)
float lAngle = Mathf.LerpAngle(minAngle, lMaxAngle, Time.deltaTime);
float rAngle = Mathf.LerpAngle(minAngle, rMaxAngle, Time.deltaTime);
Quaternion leftRotation = Quaternion.Euler(new Vector3 (0, lAngle, 0));
Quaternion rightRotation = Quaternion.Euler(new Vector3 (0, rAngle, 0));
transform.position = player.transform.position + offSet;
transform.LookAt (player.transform);
if (Input.GetKeyDown (KeyCode.LeftArrow) && GameObject.Find("Player").GetComponent<PlayerMovement>().turn) {
turnLeft = true;
} else if (Input.GetKeyDown (KeyCode.RightArrow) && GameObject.Find("Player").GetComponent<PlayerMovement>().turn) {
turnRight = true;
}
if(turnLeft) {
offSet = leftRotation * offSet;
transform.position = player.transform.position + offSet;
transform.LookAt (player.transform);
if (lAngle > 90f)
turnLeft = false;
}
if(turnRight) {
offSet = rightRotation * offSet;
transform.position = player.transform.position + offSet;
transform.LookAt (player.transform);
if (rAngle < -90f)
turnRight = false;
}
An alternative would be to use Quaternion.RotateTowards, as this allows rotations to negative values without the GameObject infinitely rotating (as it can't approach a negative value). Below you can see I'm storing the initial value of the GameObject's rotation, as a Vector3, before modifying this value whenever A or D keys are pressed. The rotation of the transform is then set to the result of Quaternion.RotateTowards.
public class FixedRotate : MonoBehaviour
{
[SerializeField]
private float m_rotationAngle;
[SerializeField]
private float m_rotationSpeed;
private Vector3 m_targetRotation;
public void Start()
{
m_targetRotation = transform.eulerAngles;
}
public void Update()
{
//Left
if(Input.GetKeyDown(KeyCode.A))
m_targetRotation.y -= m_rotationAngle;
//Right
if (Input.GetKeyDown(KeyCode.D))
m_targetRotation.y += m_rotationAngle;
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.Euler(m_targetRotation), m_rotationSpeed);
}
}
The unfortunate thing about this approach is that you can't specify the amount of time a rotation takes, only the incremental value of which the object will rotate by. An alternative approach would be to use Mathf.Clamp to add Time.deltaTime / rotationTime to the existing y rotation of the GameObject and stop once it's reached +/- 90. Hope this helps.

Categories