繁体   English   中英

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

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

我在这里有一些CS代码,我试图在Unity中围绕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,并将其设置在您希望相机绕轨道运行的固定点上。 确保GameObject位于Camera的视线范围内。 然后将您的相机添加到Empty GameObject。

对于简单(但更严格)的方法,将TouchCamera脚本附加到Empty GameObject。 从相机中删除TouchCamera脚本。 现在在脚本中的Update方法的开头上方添加此行public Camera camera 在你的脚本替换所有出现的GetComponent<Camera>()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;
}

}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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