使用箭头键在Unity / C#中围绕球体旋转相机

时间:2019-09-23 11:36:52

标签: c# unity3d

我目前正在学习Unity,并且在我正在做的项目上停留了一段时间。

我有一个火星模型,该模型被赋予旋转扭矩,并且有两个卫星绕其旋转。我希望能够使用箭头键在周围移动相机,但是似乎无法弄清楚。

当前代码(全部在一个名为GameManager的脚本中):

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

public class GameManagerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject mars;//planet
    public GameObject phobos;//moon1
    public GameObject deimos;//moon2
    public GameObject refpoint;//empty game object I placed inside mars
    //All object are referenced using the inspector

    void Start()
    {
        Camera.main.transform.position = new Vector3(0,0,-200);

        Camera.main.transform.LookAt(mars.transform.position);

        Rigidbody rb = mars.GetComponent<Rigidbody>();
        rb.angularVelocity = new Vector3(0,20,0);
    }

    // Update is called once per frame
    void Update()
    {

        if(Input.GetKey("up")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.right, 50* Time.deltaTime);
        }
        else if(Input.GetKey("down")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.right, -50* Time.deltaTime);
        }else if(Input.GetKey("right")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.up, -50* Time.deltaTime);
        }else if(Input.GetKey("left")){
            Camera.main.transform.transform.RotateAround(refpoint.transform.position, Vector3.up, 50* Time.deltaTime);
        }

        phobos.transform.RotateAround(mars.transform.position, phobos.transform.up, 60*Time.deltaTime);
        deimos.transform.RotateAround(mars.transform.position, deimos.transform.up, 50*Time.deltaTime);

    }
}

最初效果很好,但是一旦在上/下之后使用左/右,反之亦然,方向就会变得混乱。

任何帮助表示赞赏。

4 个答案:

答案 0 :(得分:1)

如果您定义了另一个函数来获取新的Vector旋转,可能会更好,例如:

Vector3 CalculateRotationVector(){
    Vector3 RotationVector = Vector3.zero;

    if(Input.GetKey("up")){
        RotationVector += Vector3.right;
    }
    else if(Input.GetKey("down")){
        RotationVector -= Vector3.right;
    }else if(Input.GetKey("right")){
        RotationVector -= Vector3.right;
    }else if(Input.GetKey("left")){
        RotationVector += Vector3.right;
    }

    return RotationVector;

}

在更新功能中,您可以这样称呼它:

void Update(){
    Camera.main.transform.RotateAround(refpoint.transform.position, CalculateRotationVector(), 50* Time.deltaTime);
}

但是我不确定这是否行得通,因为我现在无法统一尝试,可能会给您一个想法。

答案 1 :(得分:0)

您并不总是希望绕全局右轴旋转。您可以在全局down与参考点到相机的方向之间使用叉积,以找到合适的轴。

此逻辑要求您防止照相机直接在行星上方或下方移动。根据全局上/下角度与从参考点到摄像机的方向之间的夹角以及垂直于上/下轴的摄像机的“最小角度”来夹紧垂直旋转。

此外,Camera.main在内部调用FindGameObjectsWithTag,因此recommended来缓存结果。

总的来说,看起来像这样:

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

public class GameManagerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject mars;//planet
    public GameObject phobos;//moon1
    public GameObject deimos;//moon2
    public GameObject refpoint;//empty game object I placed inside mars
    //All object are referenced using the inspector

    private Camera mainCam;
    private float cameraRotateSpeed = 50f;
    private float cameraMinVerticalAngle = 10f;

    void Start()
    {
        mainCam = Camera.main;

        mainCam.transform.position = new Vector3(0,0,-200);

        mainCam.transform.LookAt(mars.transform.position);

        Rigidbody rb = mars.GetComponent<Rigidbody>();
        rb.angularVelocity = new Vector3(0,20,0);
    }

    // Update is called once per frame
    void Update()
    {

        float horizontalRotateDirection = 0f;
        float verticalRotateDirection = 0f;


        if(Input.GetKey("up")){
            doRotate = true;
            verticalRotateDirection += 1f;
        }

        if(Input.GetKey("down")){
            doRotate = true;
            verticalRotateDirection -= 1f;
        }

        if(Input.GetKey("right")){
            doRotate = true;
            horizontalRotateDirection += 1f;
        }

        if(Input.GetKey("left")){
            doRotate = true;
            verticalRotateDirection -= 1f;
        }

        float horizontalRotateAmount = horizontalRotateDirection 
                * cameraRotateSpeed * Time.deltaTime;

        float verticalRotateAmount = verticalRotateDirection 
                * cameraRotateSpeed * Time.deltaTime;

        // Prevent camera from flipping
        Vector3 fromRefToCam = (mainCam.transform.position - refpoint.transform.position).normalized;

        float maxRotateDown = Vector3.Angle(Vector3.down, fromRefToCam);
        float maxRotateUp = Vector3.Angle(Vector3.up, fromRefToCam)

        verticalRotateAmount = Mathf.Clamp(verticalRotateAmount, 
                cameraMinVerticalAngle - maxRotateDown, 
                maxRotateUp - cameraMinVerticalAngle);

        Vector3 verticalRotateAxis = Vector3.Cross(Vector3.down, fromRefToCam); 

        //Rotate horizontally around global down
        mainCam.transform.RotateAround(refpoint.transform.position, 
                    Vector3.up, 
                    horizontalRotateAmount);

        // Rotate vertically around camera's right (in global space)
        mainCam.transform.RotateAround(refpoint.transform.position,
                    verticalRotateAxis, 
                    verticalRotateAmount);


        phobos.transform.RotateAround(mars.transform.position, phobos.transform.up, 
                60*Time.deltaTime);
        deimos.transform.RotateAround(mars.transform.position, deimos.transform.up, 
                50*Time.deltaTime);

    }
}

答案 2 :(得分:0)

我相信RotateAround是一个错误。使用其他建议的解决方案,您会很快迷失在旋转中,而相机倒置甚至侧向倾斜。

public class GameManagerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public GameObject mars;//planet
    public GameObject phobos;//moon1
    public GameObject deimos;//moon2
    public GameObject refpoint;//empty game object I placed inside mars
    //All object are referenced using the inspector

    public float cameraAngularVelocity = 60f;
    public float cameraDistance = 200;
    public float cameraAngleY = 0;
    public float cameraAngleX = 0;

    private Camera mainCam;

    void Start()
    {
        mainCam = Camera.main;
    }

    void Update()
    {
        float angleDelta = cameraAngularVelocity * Time.deltaTime;

        //Standard Input management
        if (Input.GetKey("up"))
        {
            cameraAngleX += angleDelta;
        }
        if (Input.GetKey("down"))
        {
            cameraAngleX -= angleDelta;
        }
        if (Input.GetKey("right"))
        {
            cameraAngleY -= angleDelta;
        }
        if (Input.GetKey("left"))
        {
            cameraAngleY += angleDelta;
        }
        //Alternative using axis
        cameraAngleX += Input.GetAxis("Vertical") * angleDelta;
        cameraAngleY += Input.GetAxis("Horizontal") * angleDelta;

        //Protections
        cameraAngleX = Mathf.Clamp(cameraAngleX, -90f, 90f);
        cameraAngleY = Mathf.Repeat(cameraAngleY, 360f);

        Quaternion cameraRotation =
            Quaternion.AngleAxis(cameraAngleY, Vector3.up)
            * Quaternion.AngleAxis(cameraAngleX, Vector3.right);

        Vector3 cameraPosition =
            refpoint.transform.position
            + cameraRotation * Vector3.back * cameraDistance;

        mainCam.transform.position = cameraPosition;
        mainCam.transform.rotation = cameraRotation;

        phobos.transform.RotateAround(mars.transform.position, phobos.transform.up, 60 * Time.deltaTime);
        deimos.transform.RotateAround(mars.transform.position, deimos.transform.up, 50 * Time.deltaTime);
    }
}

此解决方案可锁定您的侧倾,并防止垂直方向通过X旋转。

答案 3 :(得分:-2)

看看这个。

https://docs.unity3d.com/ScriptReference/Transform.RotateAround.html

借助此功能,您可以围绕给定点旋转。如果您将其与按键输入相结合,并且将恒定速度乘以Time.deltaTime,则可能会起作用