【问题标题】:How can I rotate the camera around group of objects and not only a single one?如何围绕一组对象而不是单个对象旋转相机?
【发布时间】:2018-06-01 08:43:40
【问题描述】:

相机只是一名士兵的孩子,目标也是这名士兵。

以及附加到相机的脚本。

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

public class CameraMove : MonoBehaviour
{

    public Transform target;
    public float speed = 0.1f;

    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {
        transform.RotateAround(target.transform.position, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
    }


}

但现在我想做两件事。使相机围绕整个士兵旋转,而不仅仅是特定的一个。并且还可以让相机在面对士兵时缓慢停止。现在开始游戏时相机落后了。

如果为真,则使用布尔标志使相机围绕士兵旋转,直到它面向他们,然后停止旋转并继续与士兵一起移动。

如果未选中 false,则使相机围绕焊料旋转不停。

更新我到目前为止的尝试:

此代码将使它围绕所有士兵旋转,并且运行良好:

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

public class CameraMove : MonoBehaviour
{
    public float speed = 0.1f;

    private List<GameObject> Soldiers = new List<GameObject>();

    // Use this for initialization
    void Start()
    {
        Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
    }

    // Update is called once per frame
    void Update()
    {
        RotateAround();
    }

    private void RotateAround()
    {
        transform.RotateAround(GetAverageLocationOfSoliders(), new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
    }

    private Vector3 GetAverageLocationOfSoliders()
    {
        var total = new Vector3();

        foreach (var soldier in Soldiers)
            total += soldier.transform.position;

        return total / Soldiers.Count();    // Assuming Soldiers is List<Soldier>
    }
}

然后我尝试添加一个 slowDown 布尔标志变量,但我把它搞砸了,它根本不起作用。

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

public class CameraMove : MonoBehaviour
{
    public float speed = 0.1f;
    public bool slowDown = false;

    private List<Vector3> SoldiersPositions = new List<Vector3>();
    private List<Vector3> SoldiersFacingDirection = new List<Vector3>();

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void FixedUpdate()
    {
        RotateAround();
    }

    private void RotateAround()
    {
        var getSoldiers = GameObject.FindGameObjectsWithTag("Soldier");
        foreach (GameObject soldier in getSoldiers)
        {
            SoldiersPositions.Add(soldier.transform.position);
            SoldiersFacingDirection.Add(soldier.transform.forward);
        }

        var Center = GetAverageLocationOfSoliders();
        var FacingDirections = GetAverageFacingDirectionOfSoldiers();
        if (slowDown == true)
        {
            var D = transform.position - Center;
            var CamAngle = Vector3.Angle(D, FacingDirections);
            speed = speed - CamAngle;
        }

        transform.RotateAround(Center, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
        SoldiersPositions = new List<Vector3>();
        SoldiersFacingDirection = new List<Vector3>();
    }

    private Vector3 GetAverageLocationOfSoliders()
    {
        var total = new Vector3();

        foreach (var soldier in SoldiersPositions)
            total += soldier;

        return total / SoldiersPositions.Count();    // Assuming Soldiers is List<Soldier>
    }

    private Vector3 GetAverageFacingDirectionOfSoldiers()
    {
        var total = new Vector3();

        foreach (var soldierfacingdir in SoldiersFacingDirection)
            total += soldierfacingdir;

        return total / SoldiersFacingDirection.Count();
    }
}
  1. 我不确定第一个仅用于旋转的代码示例是否符合我编写的方式。它正在工作,但不确定这是否是编写代码的好方法?

  2. 在我看来,在第一个代码中只有旋转相机有点晃动或卡顿我的意思是相机在旋转时移动不顺畅。在编辑器的游戏视图中几乎很难看到,但我认为您可以在场景视图中看到它。

  3. 我调用 RotateAround(); 的原因在更新中,士兵们正在不断前进。

  4. 我应该如何做减速部分?

更新 2:

这是现在的完整男女同校:

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

public class CameraMove : MonoBehaviour
{
    [Header("Spin")]
    public bool spin = false;
    public Vector3 Direction;
    [Range(0, 300)]
    public float speed = 10f;
    public bool randomSpeed = false;
    public bool randomDirection = false;
    [Range(0f, 100f)]
    public float timeDirChange;
    public Vector3 defaultDirection;

    [Space(5)]

    [Header("Move in circles")]
    public bool moveInCircles = true;
    public GameObject rotateAroundTarget;
    public Vector3 axis;//by which axis it will rotate. x,y or z.
    public float rotationSpeed; //or the speed of rotation.
    public float upperLimit, lowerLimit, delay;// upperLimit & lowerLimit: heighest & lowest height;
    public bool randomHeight = false;
    public bool stopRotatingWhenFacing = false;
    private float height, prevHeight, time;//height:height it is trying to reach(randomly generated); prevHeight:stores last value of height;delay in radomness;


    [Space(5)]

    [Header("Follow objects")]
    public GameObject[] objectsToFollow;
    public bool randomFollow;

    private float nextRotationTime = 0f;
    private int counter = 0;
    private List<GameObject> Soldiers = new List<GameObject>();

    // Use this for initialization
    void Start()
    {
        Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
    }

    private void Update()
    {
        if (randomSpeed)
        {
            speed = UnityEngine.Random.Range(0, 300);
        }

        if (spin)
        {
            if (randomDirection == false)
            {
                nextRotationTime = 0;
                timeDirChange = 0;
                Direction = defaultDirection;
            }
            else
            {
                if (Time.time > nextRotationTime)
                {
                    nextRotationTime += timeDirChange;
                    RandomDirection();
                }
            }

            transform.Rotate(Direction, speed * Time.deltaTime);
        }
        else
        {
            timeDirChange = 0;
            randomDirection = false;
            randomSpeed = false;
        }

        if (moveInCircles)
        {
            MoveInCircles();
        }
    }

    private void RandomDirection()
    {
        Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
        while (Direction == new Vector3(0, 0, 0))
        {
            counter++;
            Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));

            if (counter == 2)
            {
                Direction = new Vector3(1, 0, 0);
                break;
            }
        }

        counter = 0;
    }

    private void MoveInCircles()
    {
        var F = GetAverageDirectionsOfSoliders();
        var D = transform.position - GetAverageLocationOfSoliders();
        var angle = Vector3.Angle(D, F);

        if (angle < 5f)
        {
            rotationSpeed -= 0.1f;
        }

        transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
        time += Time.deltaTime;
        //Sets value of 'height' randomly within 'upperLimit' & 'lowerLimit' after delay 
        if (time > delay)
        {
            prevHeight = height;
            if (randomHeight)
            {
                height = UnityEngine.Random.Range(lowerLimit, upperLimit);
            }
            time = 0;
        }

        if (randomHeight == false)
        {
            height = transform.position.y;
        }

        if (randomHeight)
        {
            //Mathf.Lerp changes height from 'prevHeight' to 'height' gradually (smooth transition)  
            transform.position = new Vector3(transform.position.x, Mathf.Lerp(prevHeight, height, time), transform.position.z);
        }
        else
        {
            transform.position = new Vector3(transform.position.x, height, transform.position.z);
        }
    }

    private Vector3 GetAverageLocationOfSoliders()
    {
        var total = new Vector3();

        foreach (var soldier in Soldiers)
        {
            total += soldier.transform.position;
        }

        return total / Soldiers.Count();    // Assuming Soldiers is List<Soldier>
    }

    private Vector3 GetAverageDirectionsOfSoliders()
    {
        var totalf = new Vector3();

        foreach (var soldier in Soldiers)
        {
            totalf += soldier.transform.forward;
        }

        return totalf / Soldiers.Count();
    }
}

RotateAround 部分工作正常:

transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);

但是减速部分不起作用。当镜头对着士兵时,它根本没有减速。

这就是我计算所有士兵的平均 transform.forward 向量的方法:

private Vector3 GetAverageDirectionsOfSoliders()
    {
        var totalf = new Vector3();

        foreach (var soldier in Soldiers)
        {
            totalf += soldier.transform.forward;
        }

        return totalf / Soldiers.Count();
    }

然后在 MoveInCircles 方法中我做了:

var F = GetAverageDirectionsOfSoliders();
        var D = transform.position - GetAverageLocationOfSoliders();
        var angle = Vector3.Angle(D, F);

        if (angle < 5f)
        {
            rotationSpeed -= 0.1f;
        }

但它永远不会到达这条线:

rotationSpeed -= 0.1f;

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    围绕所有士兵旋转:

    1. 获取所有士兵的中心(将所有士兵的世界位置相加除以N士兵数量)
    2. 获取士兵与中心的最大距离
    3. 围绕中心旋转摄像头,并确保其距离中心的距离超过最大距离

    在面对士兵前方时放慢镜头:

    1. 平均所有士兵的transform.forward 向量。我们将此向量称为F。这是公平的,因为您的所有士兵通常都面向同一个大方向,这样请求才有意义。
    2. 计算方向D,即从士兵中心到摄像机的方向。这很简单:D = camera.transform.position - soldiersCenter
    3. 最后,使用Vector3.Angle() 找到DF 之间的锐角。如果该角度低于某个阈值,则减小摄像头的moveSpeed

    实际的代码很容易编写,但我会让你练习。如果您需要任何帮助,请告诉我

    【讨论】:

    • 我试过了。第一部分围绕所有士兵旋转似乎工作正常。但是慢下来的第二部分搞砸了。用我所做的更改更新了我的问题。
    • @BenziAvrumi 1. 检查您的if slowDown == true 块,是否有意义?有没有将slowDown 变量设置为true/false 的地方? 2. 检查您的speed = speed - camAngle 行。 camAngle 是度数,你会 speed 变成负数吗?修复这几行中的逻辑。还有一些其他不好的做法,例如在更新块中实例化列表,但我们将在逻辑修复后进行处理。
    • 我更改了脚本并再次尝试使用减速部分。用 UPDATE 2 部分再次更新了我的问题。减速部分还没有工作。
    • @BenziAvrumi 现在似乎有很多不必要的代码。这很简单:更新循环应该使用speed 变量来更新您的凸轮位置:ds = speed * Time.deltaTime。如果 u 在角度阈值内,请将speed 设置为较低的值。无论如何,您应该尝试自己进行一般调试,找出问题所在和问题,从长远来看会有所帮助
    【解决方案2】:

    从它的声音来看,它似乎已经能够围绕单个士兵进行轨道运行,所以对不止一个士兵做,只需取他们位置的平均值。

    伪代码:

    transform.RotateAround(GetAverageLocationOfSoliders(), ...);
    ...
    private static Vector3 GetAverageLocationOfSoliders
    {
        var total = new Vector3();
    
        foreach(var soldier in Soldiers)
            total += soldier.transform.position;
    
        return total / Soliders.Count();    // Assuming Soldiers is List<Soldier>
    }
    

    现在,Vector3 可能没有 Vector3 += Vector3Vector3 / int 之类的东西,但如果是这种情况,只需创建自己的方法(如果您手动执行此操作)(添加 vectorA.x + vectorB.xvectorA.x / num 等。

    至于让相机在前面停下来,这有点棘手。您可能需要先进行一些检查以确保它们都具有相同的旋转,然后检查每个Update,如果相机的旋转将指向其中一名士兵。

    但是,如果你想让它慢下来,那么,不要检查lookAtRotation 是否可以指向士兵,而是检查它是否可以指向相机旋转的某个offset,如下所示:

    伪代码:

    lookRotation(transform.Rotation + offset)   // Use something like this to find Soldiers[0]
    

    然后,如果找到了,您可以在速度上使用Lerp 将速度降低到 0。

    您还必须以某种方式维护List&lt;Soldier&gt;Soldier[]

    【讨论】:

      猜你喜欢
      • 2019-01-26
      • 2016-11-23
      • 2021-10-24
      • 2013-05-21
      • 1970-01-01
      • 2013-08-30
      • 2021-03-13
      • 2018-01-23
      • 2015-02-07
      相关资源
      最近更新 更多