Unity3D C# 中的相机旋转问题(可能很容易修复)

Camera Rotation Issue in Unity3D C# (likely easy fix)

我这里有一些 CS 代码,我试图统一使用它来围绕 y 轴旋转相机。问题是相机目前似乎绕着 z 轴旋转,这在我的游戏中造成了一些视觉困难。

public class TouchCamera : MonoBehaviour {
Vector2?[] oldTouchPositions = {
    null,
    null
};
Vector2 oldTouchVector;
float oldTouchDistance;

void Update() {
    if (Input.touchCount == 0) {
        oldTouchPositions[0] = null;
        oldTouchPositions[1] = null;
    }
    else if (Input.touchCount == 1) {
        if (oldTouchPositions[0] == null || oldTouchPositions[1] != null) {
            oldTouchPositions[0] = Input.GetTouch(0).position;
            oldTouchPositions[1] = null;
        }
        else {
            Vector2 newTouchPosition = Input.GetTouch(0).position;

            transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] - newTouchPosition) * GetComponent<Camera>().orthographicSize / GetComponent<Camera>().pixelHeight * 2f));

            oldTouchPositions[0] = newTouchPosition;
        }
    }
    else {
        if (oldTouchPositions[1] == null) {
            oldTouchPositions[0] = Input.GetTouch(0).position;
            oldTouchPositions[1] = Input.GetTouch(1).position;
            oldTouchVector = (Vector2)(oldTouchPositions[0] - oldTouchPositions[1]);
            oldTouchDistance = oldTouchVector.magnitude;
        }
        else {
            Vector2 screen = new Vector2(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight);

            Vector2[] newTouchPositions = {
                Input.GetTouch(0).position,
                Input.GetTouch(1).position
            };
            Vector2 newTouchVector = newTouchPositions[0] - newTouchPositions[1];
            float newTouchDistance = newTouchVector.magnitude;

            transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] + oldTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y));
            transform.localRotation *= Quaternion.Euler(new Vector3(0, 0, Mathf.Asin(Mathf.Clamp((oldTouchVector.y * newTouchVector.x - oldTouchVector.x * newTouchVector.y) / oldTouchDistance / newTouchDistance, -1f, 1f)) / 0.0174532924f));
            GetComponent<Camera>().orthographicSize *= oldTouchDistance / newTouchDistance;
            transform.position -= transform.TransformDirection((newTouchPositions[0] + newTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y);

            oldTouchPositions[0] = newTouchPositions[0];
            oldTouchPositions[1] = newTouchPositions[1];
            oldTouchVector = newTouchVector;
            oldTouchDistance = newTouchDistance;
        }
    }
}

我是艺术家,绝不是编码员,此代码不是我创作的。我只是寻求帮助来纠正它以满足我的需要。因此,如果有人能让我知道我可以对当前代码进行的最简单的调整,我将不胜感激。我知道这不是最常规的问题,我只是希望得到一点帮助。

你是对的——这真的很容易修复。更改旋转轴所需要做的就是调整以下行(大约第 49 行):

transform.localRotation *= Quaternion.Euler(new Vector3(0, 0, Mathf.Asin(Mathf.Clamp((oldTouchVector.y * newTouchVector.x - oldTouchVector.x * newTouchVector.y) / oldTouchDistance / newTouchDistance, -1f, 1f)) / 0.0174532924f));

您会注意到开始的部分

new Vector3

其中有三个参数,

new Vector3(x value, y value, z value)

现在,Vector3 设置为

new Vector3(x value = 0, y value = 0, z value = rotation data)

要围绕其 y 轴旋转相机,请为此换行

transform.localRotation *= Quaternion.Euler(new Vector3(0, Mathf.Asin(Mathf.Clamp((oldTouchVector.y * newTouchVector.x - oldTouchVector.x * newTouchVector.y) / oldTouchDistance / newTouchDistance, -1f, 1f)) / 0.0174532924f, 0));

我所做的只是交换新 Vector3 中 y 和 z 值的当前设置。希望这对您有所帮助!

有关此答案的上下文,请参阅我之前答案的评论线程。

有两种方法可以让您的相机围绕一个点旋转。在你做任何其他事情之前,在 Unity 中创建一个空的 GameObject 并将其设置在你希望你的相机围绕其旋转的固定点。确保游戏对象在相机的视线内。然后将您的相机作为 Empty GameObject 的父级。

对于简单(但更严格)的方法,将您的 TouchCamera 脚本附加到空游戏对象。从相机中删除 TouchCamera 脚本。现在将此行 public Camera camera 添加到脚本中 Update 方法开头的上方。在您的脚本中,将所有出现的 GetComponent<Camera>() 替换为 camera。保存您的脚本并返回到 Unity。最后,单击您的 Empty GameObject 并将您的 Camera 拖到 TouchCamera 组件中的 Serialized Camera 字段中。这种方法实质上是将摄像机的控制移至空游戏对象。

对于更复杂(但更灵活)的方法,创建一个新的 C# 脚本并将其命名为 "CameraControl"。然后将以下代码复制并粘贴到脚本中(替换任何已有的代码)。

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;

public class CameraControl : MonoBehaviour {

Vector2?[] oldTouchPositions = {
    null,
    null
};
Vector2 oldTouchVector;
float oldTouchDistance;

public Transform CenterOfRotation;
public Camera camera;

private Vector2 actualCenter;
private Vector2 prevTouchDelta;
private Vector3 prevMousePosition;
private bool rotate;

void Start()
{
    //swap with below commented line for y rotation.
    actualCenter = new Vector2(CenterOfRotation.position.x, CenterOfRotation.position.z);
    //actualCenter = new Vector2(CenterOfRotation.position.x, CenterOfRotation.position.y);
}

void Update() {
    if(!rotate){

        if (Input.touchCount == 0) {
            oldTouchPositions[0] = null;
            oldTouchPositions[1] = null;
        }
        else if (Input.touchCount == 1) {
            if (oldTouchPositions[0] == null || oldTouchPositions[1] != null) {
                oldTouchPositions[0] = Input.GetTouch(0).position;
                oldTouchPositions[1] = null;
            }
            else {
                Vector2 newTouchPosition = Input.GetTouch(0).position;

                transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] - newTouchPosition) * camera.orthographicSize / camera.pixelHeight * 2f));

                oldTouchPositions[0] = newTouchPosition;
            }
        }
        else {
            if (oldTouchPositions[1] == null) {
                oldTouchPositions[0] = Input.GetTouch(0).position;
                oldTouchPositions[1] = Input.GetTouch(1).position;
                oldTouchVector = (Vector2)(oldTouchPositions[0] - oldTouchPositions[1]);
                oldTouchDistance = oldTouchVector.magnitude;
            }
            else {
                Vector2 screen = new Vector2(camera.pixelWidth, camera.pixelHeight);

                Vector2[] newTouchPositions = {
                    Input.GetTouch(0).position,
                    Input.GetTouch(1).position
                };
                Vector2 newTouchVector = newTouchPositions[0] - newTouchPositions[1];
                float newTouchDistance = newTouchVector.magnitude;


                transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] + oldTouchPositions[1] - screen) * camera.orthographicSize / screen.y));
                //transform.localRotation *= Quaternion.Euler(new Vector3(0, Mathf.Asin(Mathf.Clamp((oldTouchVector.y * newTouchVector.x - oldTouchVector.x * newTouchVector.y) / oldTouchDistance / newTouchDistance, -1f, 1f)) / 0.0174532924f, 0));
                camera.orthographicSize *= oldTouchDistance / newTouchDistance;
                transform.position -= transform.TransformDirection((newTouchPositions[0] + newTouchPositions[1] - screen) * camera.orthographicSize / screen.y);

                oldTouchPositions[0] = newTouchPositions[0];
                oldTouchPositions[1] = newTouchPositions[1];
                oldTouchVector = newTouchVector;
                oldTouchDistance = newTouchDistance;
            }
        }
    }
    else{
        InwardRotation();
    }

}

void OnGUI()
{
    rotate = GUILayout.Toggle(rotate, "Toggle For Rotation", "Button");
}

void InwardRotation()
{
    //mouse version
    if(Input.GetMouseButton(0))
    {
        //distance from center of screen to touch
        Vector3 centerScreen = camera.ViewportToScreenPoint(new Vector3(0.5f, 0.5f, 1));
        Vector3 mouseDelta = Input.mousePosition - new Vector3(centerScreen.x, centerScreen.y, 0f);

        //if mouse doesn't move very much, don't rotate
        if(mouseDelta.sqrMagnitude < 0.1f)
            return;

        //attempts to make movement smoother
        if(prevMousePosition == Vector3.zero)
            prevMousePosition = mouseDelta;

        //this gets the angle between the current touch and the last touch
        float theta = Mathf.Atan2(mouseDelta.y, mouseDelta.x) - Mathf.Atan2(prevMousePosition.y, prevMousePosition.x);

        //Gets the rotated coordinates of the camera. Swap with below commented line for y rotation.
        Vector2 newPos = RotatedCoordinates(transform.position.x, transform.position.z, theta, CenterOfRotation.position, true);
        //Vector2 newPos = RotatedCoordinates(transform.position.x, transform.position.y, theta, CenterOfRotation.position, true);
        Debug.Log("New Pos = " + newPos);

        //swap with below commented line for y rotation.
        transform.localPosition = new Vector3(newPos.x, transform.localPosition.y, newPos.y);
        //transform.localPosition = new Vector3(newPos.x, newPos.y, transform.localPosition.z);

        transform.LookAt(CenterOfRotation);

        prevMousePosition = mouseDelta;
    }
    if(Input.touches.Length > 0f)
    {
        //distance from center of screen to touch
        Vector3 centerScreen = camera.ViewportToScreenPoint(new Vector3(0.5f, 0.5f, 1));
        Vector2 touchDelta = Input.GetTouch(0).position - new Vector2(centerScreen.x, centerScreen.y);

        //if mouse doesn't move very much, don't rotate
        if(touchDelta.sqrMagnitude < 0.1f)
            return;

        //attempts to make movement smoother
        if(prevTouchDelta == Vector2.zero)
            prevTouchDelta = touchDelta;

        //this gets the angle between the current touch and the last touch
        float theta = Mathf.Atan2(touchDelta.y, touchDelta.x) - Mathf.Atan2(prevTouchDelta.y, prevTouchDelta.x);

        //Gets the rotated coordinates of the camera. Swap with below commented line for y rotation.
        Vector2 newPos = RotatedCoordinates(transform.position.x, transform.position.z, theta, CenterOfRotation.position, true);
        //Vector2 newPos = RotatedCoordinates(transform.position.x, transform.position.y, theta, CenterOfRotation.position, true);
        Debug.Log("New Pos = " + newPos);

        //swap with below commented line for y rotation.
        transform.localPosition = new Vector3(newPos.x, transform.localPosition.y, newPos.y);
        //transform.localPosition = new Vector3(newPos.x, newPos.y, transform.localPosition.z);

        transform.LookAt(CenterOfRotation);

        prevTouchDelta = touchDelta;
    }

    else{
        prevTouchDelta = Vector2.zero;
    }
}

/// <summary>
/// This method returns the coordinates of a plane rotated about its origin. It translates a point from one place on a unit circle to another. 
/// </summary>
/// <returns>The coordinates.</returns>
/// <param name="x">The x coordinate.</param>
/// <param name="y">The y coordinate.</param>
/// <param name="theta">Theta.</param>
/// <param name="ThetaInRad">If set to <c>true</c> theta in RAD.</param>
public Vector2 RotatedCoordinates(float x, float y, float theta, Vector2 center, bool ThetaInRad = false)
{
    if(!ThetaInRad)
        theta *= Mathf.Deg2Rad;

    Vector2 XY = new Vector2((Mathf.Cos(theta) * (x - center.x) - Mathf.Sin(theta) * (y - center.y)) + center.x, (Mathf.Sin(theta) * (x - center.x) + Mathf.Cos(theta) * (y - center.y)) + center.y);
    return XY;
}

}

现在将其附加到您的相机(它应该是空 GameObject 的子项)并删除 TouchCamera 脚本。您会注意到 CameraControl 组件中的两个字段,一个显示为 "Center Of Rotation",另一个显示为 "Camera"。将 Empty GameObject 和您的 Camera 分别拖到这些字段上。如果您跳过此步骤,此脚本将抛出空引用错误。现在只需点击播放。当您单击播放 window 左上角的 Toggle For Rotation 按钮时,您可以通过围绕屏幕中心拖动鼠标指针或单指来旋转相机。您可以从 Empty GameObject 中取消 Camera 的父级,脚本仍然有效。您还可以通过提供不同的变换围绕 space 中的任何点进行轨道运动。通过一些编辑,您还可以完全消除变换并使用 Vector3 作为世界 Space 中的参考点,但是如果没有线 transform.LookAt(CenterOfRotation);,您将需要自己控制相机的实际旋转。您可以通过编辑三行来更改旋转轴,大致位于第 30 行、第 145 行和第 151 行。