在Unity中触摸(或单击)椭圆旋转

时间:2018-01-06 11:04:57

标签: c# unity3d unity5 ellipse orbit

我正在制作一个围绕鸡蛋旋转的相机。我无法弄清楚如何做到这一点。旋转在x和y各自夹紧-90 +90。我制作了一个代码,根据枢轴的当前x旋转更改摄像机位置,但它不能给我一个准确的结果。这是代码:

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

public class CameraMotionScript : MonoBehaviour {

public Transform thePivot, theCamera;
public float rotSpeed = 5f, lerpSpeed, minX, maxX, minY, maxY, maxDist, divRatio;

private float   rotX = 0f,
                rotY = 0f,
                dX = 0f,
                dY = 0f,
                rotateDirection = -1f,
                cachedRotSpeed = 0f,
                minDist = 0f;

private bool rotationActive = false;

void Start () {
    cachedRotSpeed = rotSpeed;
    minDist = Mathf.Abs (theCamera.localPosition.z);
    divRatio = maxX / maxDist;
}

void Update () {

    if (Input.GetMouseButton (0)) {
        rotSpeed = cachedRotSpeed;
        dX = Input.GetAxis ("Mouse X");
        dY = Input.GetAxis ("Mouse Y");
        rotationActive = true;
    }

    if (Input.GetMouseButtonUp (0)) {
        rotationActive = false;
    }

    rotX += dY * rotSpeed * rotateDirection * Time.deltaTime;
    rotY += dX * rotSpeed * -rotateDirection * Time.deltaTime;

    rotX = Mathf.Clamp (rotX, minX, maxX);
    rotY = Mathf.Clamp (rotY, minY, maxY);

    if (thePivot != null)
        thePivot.eulerAngles = new Vector3 (rotX, rotY, 0f);

    if (!rotationActive) {
        rotSpeed = Mathf.Lerp (rotSpeed, 0, Time.deltaTime * lerpSpeed);
        if (rotSpeed < 1)
            rotSpeed = 0;
    }

    MaintainDistanceAt (Mathf.Abs (rotX));
}

void MaintainDistanceAt (float f) {
    if (f != 0) {
        float zVal = f / divRatio;
        if (zVal < minDist)
            zVal = minDist;
        theCamera.localPosition = new Vector3 (0f, 0f, zVal * -1f);
    }
}

}

对于此代码,我的相机是枢轴的子项,我通过鼠标单击旋转轴。我接受枢轴的x旋转并计算相机的距离。我根据枢轴的运行时间x旋转来修改它。 我也在其中添加了平滑的速度代码,但暂时忽略了它。

所以问题是,我写的距离代码将相机的位置设置为线性矢量,因此它会穿过蛋网并剪切它。

我希望能够将相机移动到蛋周围的椭圆轨道上。 有关如何解决此问题的任何建议? 提前谢谢。

2 个答案:

答案 0 :(得分:2)

获得椭圆模式的简便方法是使用cos / sin函数。

void Update () 
{
    float x = xAmplitude * Mathf.Cos (Time.time + phase);
    float z = zAmplitude * Mathf.Sin (Time.time + phase)
    transform.localPosition = new Vector3(x, 0, z);
}

对您而言,重要的部分是您从输入中获得的xAmplitude和zAmplitude。

我建议你从这个方法开始,这样你就可以看到它的表现,然后一直玩它,直到你做到你想要的为止。

编辑: 什么是“阶段”? 相位是用于替换起点的值。在你的情况下,我知道你不想连续旋转但是根据鼠标位置找到椭圆上的位置。您可以丢弃创建连续移动的Time.time。然后你可以找出起点(0)和当前鼠标位置之间的角度(或使用鼠标的delta移动,你的选择)并将其转换为0到360或0和2Pi之间的值(我想Unity在cos / sin中使用那个。

这是一个简单的例子,让我们看看你是不是想要的。

  • 放置一个空的游戏对象,它将成为您的支点。
  • 添加一个球体作为孩子。
  • 向场景添加UI滑块
  • 创建新的Movement.cs脚本

    公共课运动:MonoBehaviour   {     public Transform child = null;     public float xAmplitude = 1f;     public float zAmplitude = 1f;     private float phase = 0;     公共滑块滑块;

    void Start()
    {
        slider.onValueChanged.AddListener(delegate
        {
            this.phase = 2 * Mathf.PI * slider.value;
            float x = xAmplitude * Mathf.Cos(phase);
            float z = zAmplitude * Mathf.Sin(phase);
            child.localPosition = new Vector3(x, 0, z);
        });
    }
    

    }

  • 将脚本添加到父级并将子项拖动到子级中,将滑块拖动到滑块中。

你已经完成了。然后你可以跑,拖动滑块,看看孩子四处走动。给xAmplitude和zAmplitude赋予不同的值,你有一个椭圆。

this.phase = 2 * Mathf.PI * slider.value;
float x = xAmplitude * Mathf.Cos(phase);
float z = zAmplitude * Mathf.Sin(phase);

看看时间如何消失,这将停止恒定运动,因为cos / sin中的值是固定的(但仍然可以根据我们的滑块改变)。 现在,相位值由滑块值(0到1)转换为2Pi范围。 相位被传递给sin / cos,并且这些值被相应的幅度相应地延长。

答案 1 :(得分:0)

我一直想做同样的事情。我使用了@Everts阶段作为起点。

代码可在此处找到:https://gist.github.com/xepherys/1a22ed93e6c6efde61f1667f45a80a72 动作的视频可以在这里找到:https://youtu.be/4z27uTwS-gU

带有注释的完整代码:

using System;
using UnityEngine;

/// <summary>
/// The MainCameraEllipticalMWE class provides motion of the camera in an ellipse (or a circle)
/// given sizeX and sizeZ where one is the major axis and the other the minor axis.  Which is
/// which isn't important, and they can be equal (x == z) if the camera is to track in a circle.
///
/// The size values assume a 2D surface where x=0, z=0 is at the bottom left and built in both x+
/// and z+ directions.
/// </summary>
public class MainCameraEllipticalMWE : MonoBehaviour
{
    // sizeX and sizeZ are provided here to provide a reference point. In use, my version
    // of this script omits these values and gets values from a manager object fed into
    // the FixCamera() method where xAmplitude and zAmplitude are set.
    int sizeX = 12;
    int sizeZ = 3;
    Vector3 center;
    float height;
    float fudgeFactor = 1.0f;

    float phase = 0f;
    float xAmplitude = 0f;
    float zAmplitude = 0f;
    float x;
    float z;

    void Awake()
    {
        this.FixCamera(sizeX, sizeZ);
    }

    /// <summary>
    /// On Update(), if the appropriate key is pressed, rotate the camera around the center
    /// of the area defined. The camera will tilt as appropriate to maintain the same center
    /// point of view.  The greater the difference between the major and minor axes, the
    /// greater the difference of speed as the camera traverses the outsides of the major axis.
    /// </summary>
    void Update()
    {
        if (Input.GetKey(KeyCode.A))
        {
            // Move left
            phase -= 0.01f;
            x = xAmplitude * Mathf.Cos(phase);
            z = zAmplitude * Mathf.Sin(phase);
            transform.localPosition = new Vector3(x, height, z) + center;
            this.GetComponent<Camera>().transform.LookAt(center);
        }

        else if (Input.GetKey(KeyCode.F))
        {
            // Move right
            phase += 0.01f;
            x = xAmplitude * Mathf.Cos(phase);
            z = zAmplitude * Mathf.Sin(phase);
            transform.localPosition = new Vector3(x, height, z) + center;
            this.GetComponent<Camera>().transform.LookAt(center);
        }
    }

    /// <summary>
    /// FixCamera() provides the initial camera position, sets the camera height, and
    /// resolves the center position based on the horizontal and vertical sizes of
    /// the screen area.
    /// </summary>
    /// <param name="horizontalSize"></param>
    /// <param name="verticalSize"></param>
    public void FixCamera(int horizontalSize, int verticalSize)
    {
        xAmplitude = horizontalSize;
        zAmplitude = verticalSize;
        height = Math.Max(horizontalSize, verticalSize) + fudgeFactor;
        center = new Vector3((float)horizontalSize / 2, 0, (float)verticalSize / 2);

        float x = xAmplitude * Mathf.Cos(phase);
        float z = zAmplitude * Mathf.Sin(phase);
        transform.localPosition = new Vector3(x, height, z) + center;
        this.GetComponent<Camera>().transform.LookAt(center);
    }
}