首页 > 解决方案 > 如何找到两个或多个对象的中心位置?

问题描述

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

public class MoveCameraBehind : MonoBehaviour
{
    public GameObject camera;
    public List<GameObject> targets = new List<GameObject>();
    public float cameraDistance = 10.0f;
    public bool behindMultipleTargets = false;
    public string cameraWarningMsgs = "";
    public string targetsWarningMsgs = "";

    // Use this for initialization
    void Start()
    {
        if (camera == null)
        {
            var cam = GetComponent<Camera>();
            if (cam != null)
            {
                cameraWarningMsgs = "Gettig camera component.";

                camera = transform.gameObject;
            }
            else
            {
                cameraWarningMsgs = "Creating a new camera component.";

                GameObject NewCam = Instantiate(new GameObject(), transform);
                NewCam.name = "New Camera";
                NewCam.AddComponent<Camera>();
                camera = NewCam;
            }
        }

        if(targets.Count == 0)
        {
            targetsWarningMsgs = "No targets found.";
        }
    }

    void FixedUpdate()
    {
        if (targets.Count > 0)
        {
            MoveCameraToPosition();
        }
    }

    public void MoveCameraToPosition()
    {
        if (targets.Count > 1 && behindMultipleTargets == true)
        {
            var center = CalculateCenter();
            transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
        }

        if (behindMultipleTargets == false)
        {
            Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
            transform.position = new Vector3(center.x, center.y + 2, center.z);
        }
    }

    private Vector3 CalculateCenter()
    {
        Vector3 center = new Vector3();

        var totalX = 0f;
        var totalY = 0f;
        foreach (var target in targets)
        {
            totalX += target.transform.position.x;
            totalY += target.transform.position.y;
        }
        var centerX = totalX / targets.Count;
        var centerY = totalY / targets.Count;

        center = new Vector3(centerX, centerY);

        return center;
    }
}

CalculateCenter 函数使目标(对象)改变位置并消失在很远的地方。即使只有一个目标。

我想要做的是,如果有一个对象,例如一个 3d 立方体,则将相机放置在立方体后面。如果有更多的立方体,例如两个或十个,并且相机在其他地方,则计算目标后面的中间位置并将相机定位在它们后面的中间。

为了说明我在这个例子中的意思,视图(就像一个相机)在两个士兵的后面,从后面处于他们之间的中间位置。

但是如果有 5 名士兵,我怎样才能找到中间位置,然后像屏幕截图中的这个例子一样将相机放在他们身后呢?

示例视图

这是我的旧脚本版本运行良好,但仅适用于 1 或 2 个目标。但是,如果有 5 个目标(士兵),我如何将相机放在他们身后的中间?就像在屏幕截图示例中一样。

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

public class MoveCameraBehind : MonoBehaviour
{
    public GameObject camera;
    public List<GameObject> targets = new List<GameObject>();
    public float cameraDistance = 10.0f;
    public bool behindTwoTargets = false;
    public string warningMsgs = "";

    // Use this for initialization
    void Start()
    {
        if (camera == null)
        {
            var cam = GetComponent<Camera>();
            if (cam != null)
            {
                warningMsgs = "Gettig Camera omponent.";

                camera = transform.gameObject;
            }
            else
            {
                warningMsgs = "Creating a new camera component.";

                GameObject NewCam = Instantiate(new GameObject(), transform);
                NewCam.name = "New Camera";
                NewCam.AddComponent<Camera>();
                camera = NewCam;
            }
        }

        camera.transform.Rotate(0, 180, 0);

    }

    void FixedUpdate()
    {
        if (targets.Count > 0)
        {
            MoveCameraToPosition();
        }
    }

    public void MoveCameraToPosition()
    {
        if (targets.Count == 2 && behindTwoTargets == true)
        {
            Vector3 center = ((targets[0].transform.position - targets[1].transform.position) / 2.0f) + targets[1].transform.position;
            camera.transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
        }

        if (behindTwoTargets == false)
        {
            Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
            camera.transform.position = new Vector3(center.x, center.y + 2, center.z);
        }
    }
}

这是我仍在使用 CalculateCenter 函数的工作代码的最后一个版本:

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

public class CameraLook : MonoBehaviour
{
    public GameObject camera;
    public List<GameObject> targets = new List<GameObject>();
    public float cameraDistance = 10.0f;
    public float cameraHeight = 2f;
    public float rotateTime = 2f;
    public bool multipleTargets = false;
    public bool changeRandomTarget = false;
    public bool behindFront = false;
    public bool targetsRandomRot = false;
    public string cameraWarningMsgs = "";
    public string targetsWarningMsgs = "";

    private List<Vector3> vectors = new List<Vector3>();

    //Random move rotation timer part
    Quaternion qTo;
    float speed = 3f;
    float timer = 0.0f;

    // Use this for initialization
    void Start()
    {
        qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));

        if (camera == null)
        {
            var cam = GetComponent<Camera>();
            if (cam != null)
            {
                cameraWarningMsgs = "Gettig camera component.";

                camera = transform.gameObject;
            }
            else
            {
                cameraWarningMsgs = "Creating a new camera component.";

                GameObject NewCam = Instantiate(new GameObject(), transform);
                NewCam.name = "New Camera";
                NewCam.AddComponent<Camera>();
                camera = NewCam;
            }
        }

        if (targets.Count == 0)
        {
            targetsWarningMsgs = "No targets found.";
        }
        else
        {
            foreach(GameObject vector in targets)
            {
                vectors.Add(vector.transform.position);
            }
        }
    }

    void FixedUpdate()
    {
        if (targets.Count > 0)
        {
            MoveCameraToPosition();

            if (targetsRandomRot == true)
            {
                RotateTargetsRandom();
            }
        }
    }

    public void MoveCameraToPosition()
    {
        Vector3 center = CalculateCenter();
        camera.transform.position = center;

        if (behindFront == false)
        {
            camera.transform.rotation = Quaternion.LookRotation(-center, Vector3.up);
        }
        else
        {
            camera.transform.rotation = Quaternion.LookRotation(center, Vector3.up);
        }
    }

    private Vector3 CalculateCenter()
    {
        Vector3 center = new Vector3();

        var x = targets[0].transform.position.x;
        var y = targets[0].transform.position.y;
        var z = targets[0].transform.position.z;

        if (multipleTargets == true)
        {
            for (int i = 1; i < targets.Count; i++)
            {
                x += targets[i].transform.position.x;
                y += targets[i].transform.position.y;
                z += targets[i].transform.position.z;
            }
        }
        else
        {
            x += targets[0].transform.position.x;
            y += targets[0].transform.position.y;
            z += targets[0].transform.position.z;
        }

        if(changeRandomTarget == true)
        {
            for (int i = 1; i < targets.Count; i++)
            {
                x += targets[i].transform.position.x;
                y += targets[i].transform.position.y;
                z += targets[i].transform.position.z;
            }
        }

        x = x / targets.Count;
        y = y / targets.Count;
        z = z / targets.Count;

        if (behindFront == false)
        {
            center = new Vector3(x, y + cameraHeight, z + cameraDistance);
        }
        else
        {
            center = new Vector3(x, y + cameraHeight, z - cameraDistance);
        }

        return center;
    }

    private void RotateTargetsRandom()
    {
        timer += Time.deltaTime;

        if (timer > rotateTime)
        { // timer resets at 2, allowing .5 s to do the rotating
            qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
            timer = 0.0f;
        }

        foreach (var target in targets)
        {
            target.transform.rotation = Quaternion.Slerp(target.transform.rotation, qTo, Time.deltaTime * speed);
        }
    }
}

现在我想添加和使用 bool 标志 changeRandomTarget :但不知道该怎么做:

if(changeRandomTarget == true)
        {
            for (int i = 1; i < targets.Count; i++)
            {
                x += targets[i].transform.position.x;
                y += targets[i].transform.position.y;
                z += targets[i].transform.position.z;
            }
        }

我希望每 X 秒它会选择一个随机中心并根据它改变相机位置。例如,目标中的第一项列出最后一项和所有项目,因此每 X 秒,中心将落后于目标 [0] 或目标1或目标 [i]

不知道如何使用我的代码或 derHugo 解决方案来做到这一点。

标签: c#unity3d

解决方案


当然你只是找到平均值

所以

if (mobcount > 1)
{
    var x=mob[0].position.x;
    var y=mob[0].position.y;
    var z=mob[0].position.z;

   for(int i=1; i<mobcount; i++)
   {
      x += mob[i].position.x;
      y += mob[i].position.y;
      z += mob[i].position.z;
   }

   x = x / mobcount;
   y = y / mobcount;
   z = z / mobcount;
}

因此相机应该看位置 x,y,z.. 并且可能将距离设置为最近的生物后面的固定距离......


推荐阅读