简体   繁体   中英

Unity3d - Camera rotation smoothing 'bug'

I made a simple racing game. The camera follows the car (player) and its position and rotation is based on car's Y rotation. I want to smooth the camera rotation, but when it crosses 0 degree point, it rotates 360 degrees. Here's the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Camera : MonoBehaviour {
    public Transform camera, player;


    void Update() {
        Vector3 cameraPosition = camera.transform.position;
        float cameraRotation = camera.eulerAngles.y;
        float playerRotation = player.eulerAngles.y;
        Vector3 playerPosition = player.transform.position;
        cameraPosition.x = (Mathf.Sin((playerRotation / 180) * Mathf.PI) * -6 + player.position.x);
        cameraPosition.y = playerPosition.y + 2.5f;
        cameraPosition.z = (Mathf.Cos((playerRotation / 180) * Mathf.PI) * -6 + player.position.z);
        camera.transform.position = cameraPosition;
        cameraRotation = cameraRotation + (playerRotation-cameraRotation)/2;
        camera.localRotation = Quaternion.Euler(20f, cameraRotation, 0f);
    }
}

I figured out that this rotation is caused by smoothing script:

 cameraRotation = cameraRotation + (playerRotation-cameraRotation)/2;

How to prevent this unwanted rotation?

This is how I would do it:

public int smoothSpeed = 1f; // Change accordingly to increase/decrease smooth speed.

Then in update:

Vector3 directionToCar = player.position - camera.position;
Quaternion desiredRotation = Quaternion.LookRotation(directionToCar);
camera.rotation = Quaternion.Slerp(camera.rotation, desiredRotation, Time.deltaTime * smoothSpeed);

On a side node, if this camera script is attached to the camera, you don't have to make a field referencing the camera's transform. You can simply do transform.position instead of camera.transform.position .

A simpler solution to using the Slerp is to use Mathf.SmoothDamp, which has a variant called Mathf.SmoothDampAngle which handles the looping correctly. I've also had success doing the wraparound by hand but its not a very rewarding experience

using UnityEngine;
public class RotFollow : MonoBehaviour
{
    [SerializeField] Transform carTransform;
    [SerializeField] float smoothTime = .4f; 

    float currentYAngle;
    float targetYAngle;
    float angleVel;
    void Update()
    {
        targetYAngle = carTransform.rotation.eulerAngles.y;
        currentYAngle =  Mathf.SmoothDampAngle(currentYAngle, targetYAngle, ref angleVel, smoothTime);
        transform.rotation = Quaternion.Euler(
                                        transform.rotation.eulerAngles.x,
                                        currentYAngle, 
                                        transform.rotation.eulerAngles.z);
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM