【问题标题】:Camera Rotation Issue in Unity3D C# (likely easy fix)Unity3D C# 中的相机旋转问题(可能很容易修复)
【发布时间】:2016-07-19 02:44:16
【问题描述】:

我在这里有一些 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;
        }
    }
}

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

【问题讨论】:

    标签: c# android unity3d camera rotation


    【解决方案1】:

    你是对的——这是一个非常容易解决的问题。更改旋转轴所需要做的就是调整以下行(大约第 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 值。希望这会有所帮助!

    【讨论】:

    • 谢谢!尽管我现在从测试中看到了一个问题。启动旋转后,其他滑动功能不再起作用。因此,如果我向一侧滑动然后旋转,我将无法再滑动。这似乎很奇怪,我希望这是一个快速修复。另外,有没有办法让它向内旋转? Atm 它随着相机朝外旋转。谢谢:)
    • 似乎在重新启动和第二次测试后刷卡工作,所以也许这只是一个奇怪的错误。但是,我仍然希望任何人都知道有关让相机朝内旋转的任何信息!
    • 所以我认为您所追求的是让相机围绕相机外部​​的一个点旋转,而不是围绕相机的局部轴之一。这是一项更难完成的任务,因为您必须首先在世界空间中指定一个相机应围绕其旋转的参考点。这可能是固定的,例如,在相机前面 20 个单位,或者您可能想要选择一个自定义点/对象来旋转。不知道你在追求什么,我真的帮不上什么忙。对此感到抱歉。
    • 是的,我希望相机绕其前面的空间运行。没有特定的游戏对象,只是有一定的距离,这会使旋转看起来很自然。此刻它朝外旋转。我相信我正好相反,但是为了做到这一点,我确实意识到它需要绕着它前面的空间运行。
    • 如果可以,我会尽量回复您,因为我现在没有时间编写解决方案。不过,我建议您与您的程序员交谈,因为他或她会更好地了解您的目标。
    【解决方案2】:

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

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

    对于简单(但更严格)的方法,请将您的 TouchCamera 脚本附加到 Empty GameObject。从您的相机中删除 TouchCamera 脚本。现在将这一行 public Camera camera 添加到脚本中 Update 方法的开头上方。在您的脚本中,将所有出现的GetComponent&lt;Camera&gt;() 替换为camera。保存您的脚本并返回 Unity。最后,单击您的 Empty GameObject 并将您的 Camera 拖到 TouchCamera 组件中的 Serialized Camera 字段中。这种方法实质上是将相机的控制权转移到了 Empty GameObject。

    对于更复杂(但更灵活)的方法,创建一个新的 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;
    }
    

    }

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

    【讨论】:

    • 哇!非常感谢您的帮助!谢谢:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多