【问题标题】:Finding gameObject via direction of input通过输入方向查找游戏对象
【发布时间】:2017-12-05 06:09:41
【问题描述】:

我有一个游戏对象列表添加到区域内的列表中,如图所示。我需要的是从原点选择目标的方向输入。我已经得到了这个原点。

我的第一次尝试是通过 rayCast 获得它,但这样做有时需要定向输入直接通过射线击中目标对象。如果输入像案例 #1 那样完成,这没有问题。

但是,我需要它真正起作用的是,当输入方向就像 case #2 或 #3 时,输入仍然会得到一个目标。我的第二次尝试是使用 sphereCast 执行此操作,但它仍然需要一个接近 sphereCast 的目标,并且 sphereCast 击中的多个目标仍然需要通过输入仅导致一个更准确的目标选择。

由于我拥有所有可能目标的所有 transform.position 以及原点,我想有一种更优雅的方法来解决这个问题,即通过比较这些坐标的 vector3(原点和大致方向上的目标)。

这是我的最新方法:

//
// m_targetList is the list containing all GameObjects as GameObjects in other script m_collector. All m_collector does is this.
//

using System.Collections.Generic;
using UnityEngine;

public class TargetSwitcher : MonoBehaviour
{
    private TargetCollector m_collector;
    private Transform m_origin;

    public bool m_targetChanged = false;

    public GameObject m_target;

    public LayerMask m_targetMask;

    private Dictionary<Vector3, float> m_targetInfo = new Dictionary<Vector3, float>();

    private void Awake()
    {
        m_collector = GetComponent<TargetCollector>();
        m_origin = GameObject.Find("TargetOrigin").transform;
        m_tracker = GameObject.Find("TargetTracker").transform;
        m_bound = GetComponent<BoxCollider>();
    }

    public void UpdateBearing(GameObject origin)
    {
        m_origin = origin.transform;

        foreach (GameObject target in m_collector.m_targetList)
        {
            Vector3 dir = (target.transform.position - origin.transform.position).normalized
            float dist = Vector3.Distance(origin.transform.position, target.transform.position);

            m_targetInfo.Add(dir, dist);
        }
    }

    public void SwitchTarget()
    {
        if (!m_targetChanged)
        {
            Vector2 dir = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")).normalized;

            // Find closest direction value from Dictionary to dir of here
            // Compare distance from origin if multiple targets and choose the nearest
        }
    }

    public void ReturnToIdle()
    {
        m_origin.position = m_target.transform.position;
        m_targetChanged = false;
        m_targetInfo.Clear();
    }

    public struct TargetInfo
    {
        public Vector3 bearing;
        public float distance;

        public TargetInfo(Vector3 bearing, float distance)
        {
            this.bearing = bearing;
            this.distance = distance;
        }
    }
}

一般来说,我试图在 SwitchTarget() 之前将方向输入的归一化向量与从原点到每个目标的归一化向量进行比较。这里的输入法是 Gamepad 轴 x 和 y 水平和垂直。

重新发布这个问题,因为提供的答案离问题很远并且被标记为重复(给出的答案是关于仅通过距离查找游戏对象,这个问题是关于方向和距离部分是在找到多个项目时进行二手比较方向)

编辑

在对点积进行了一些试验之后,我确信这很可能是我想要的方向。不过,我需要处理很多不一致的地方。 这是我最近的尝试:

private void Update()
{
    UpdateBearing();

    Vector3 input = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0);

    if (input != Vector3.zero)
    {
        SwitchTarget();
    }
}

public void UpdateBearing(GameObject origin)
{
    m_origin.position = origin.transform.position;

    foreach (GameObject target in m_collector.m_targetList)
    {
        Vector3 dir = (target.transform.position - origin.transform.position).normalized;
        if (!m_targetInfo.ContainsKey(target))
        {
            m_targetInfo.Add(target, dir);
        }
    }
}

public void SwitchTarget()
{
    GameObject oldTarget = m_collector.m_target;

    if (!m_targetChanged)
    {
        Vector3 dir = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0).normalized;
        Debug.DrawRay(m_origin.position, dir * 100, Color.yellow, 0.5f);

        foreach (KeyValuePair<GameObject, Vector3> possibleTarget in m_targetInfo)
        {
            float dot = Vector3.Dot(dir, possibleTarget.Value);

            if (dot > 0.5f) // Compare DP difference of added dot and input dot
            {
                GameObject newTarget = possibleTarget.Key;

                if (oldTarget != newTarget)
                {
                    Debug.Log(possibleTarget.Value + " // " + dot);

                    m_target = newTarget;
                    m_collector.m_target = newTarget;
                    m_targetChanged = true;
                }
            }
        }
    }
}

有了这个,我可以在没有光线投射和丢失任何目标的情况下选择游戏对象。但是,我确信我需要比 if(dot > 0.5f) 更好的案例比较。另外,我粗略的假设是,如果我不为每个键更新字典 m_targetInfo 的值,那么如果这些目标移动了,我就会有另一个不一致的地方。无论如何,我仍然很困惑如何正确地利用它来实现我的最终目标。

【问题讨论】:

    标签: unity3d


    【解决方案1】:

    由于您在该区域中拥有所有所需的游戏对象,您可以创建一个 for 循环并检查您的观看方向与其位置之间的角度,如果它低于某个值(您可以将其设置为超低以便精确或稍高一点以允许一些误差)将其放入游戏对象列表中,如果有多个对象,则获得最接近的一个。

    获取角度最近的物体的代码如下所示:

    GameObject CheckObjects()
    {
        List<GameObject> InAngle = new List<GameObject>();
    
        for(int i = 0; i < YourObjectsList.Count; i++)
        {
            GameObject tested = YourObjectsList[i];
    
            Vector3 dir = tested.transform.position - origin.transform.forward;
    
            // I'm assuming here that youre rotating your origin with the 
            directional input, not then instead of origin.transform.forward 
            place there your directional vector3
    
            float angle = Vector3.Angle(dir, tested.transform.position);
    
            if(angle <= desiredAngle)
            {
                InAngle.Add(tested);
            }
        }
    
        GameObject closest = null;
    
        for(int j = 0; j < InAngle.Count; i++)
        {
            GameObject tested = InAngle[i];
    
            Vector3 dir1 = tested.transform.position - origin.transform.position;
            Vector3 dir2 = closest.transform.position - origin.transform.position;
    
            if(!closest)
            {
                closest = tested;
            }
            else
            {
                if(dir2.sqrMagnitude > dir1.sqrMagnitude)
                {
                    closest = tested;
                }
            }
        }
    
        return closest;
    }
    

    【讨论】:

    • 感谢您的示例和提示!在您回答之前,我只是想获得近似值并进行比较。如果您在目标向量 3 上设置原点时看到我的图表,则列表中所有其他可能的目标都将具有从原点开始的方向作为归一化向量 3。我试图存储那些归一化的向量,并找到这些存储的值并将其与方向输入进行比较,方向输入也返回归一化的向量3。我正在尝试循环遍历它们,如您的示例代码所示,但我觉得我仍然在偏离正确/最有效的轨道。
    • 如果你的原点是动态的,那么在字典中存储方向和距离真的没有意义,最好将游戏对象简单地存储在一个列表中,每次你需要获取方向时就运行该功能,因为它不是太贵。我很确定这比每次移动时更新字典要有效得多。
    • 优化需要考虑的几件事。首先我会运行点积而不是角度,因为角度使用 cos。点只是基本的算术。您可以与 0.7 进行比较,而不是与实际角度值进行比较,这样您就可以得到 90 度的 FOV。其次,您可以使用 sqrMagnitude 代替距离。它应该避免 sqr 根计算。有了这两个,我不能保证,但我会说它会运行得更快。
    • 点表示你比较两个向量,如果值为负表示你的角度大于180所以落后。如果为 1,则表示 90 度,如果为 0,则表示两个向量对齐。 cos(45) 大约在 0.7 左右,因此它意味着向左 45 和向右 45,因此是 90。点就是加法和乘法。如果你在一个平面系统上,你甚至可以放弃所有计算的 z 部分。
    • 如果新事物能够帮助您实现目标,那么这始终是您熟悉新事物的好时机
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    相关资源
    最近更新 更多