Unity3d 通过输入方向查找游戏对象

Unity3d 通过输入方向查找游戏对象,unity3d,Unity3d,我有一个游戏对象列表添加到区域内的列表中,如图所示。我需要的是从原点选择目标的方向输入。我已经找到了这个原点 我的第一次尝试是通过光线投射获得它,但通过这样做,有时定向输入需要直接通过光线击中目标对象。如果输入像案例1那样进行,这没有问题 然而,我需要它真正起作用的是,当输入方向像案例2或案例3那样时,输入仍然会得到一个目标。我的第二次尝试是使用sphereCast来实现这一点,但它仍然需要一个球体中的目标,并且sphereCast击中的多个目标仍然需要通过输入只产生一个更精确的目标选择 因为我

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

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

然而,我需要它真正起作用的是,当输入方向像案例2或案例3那样时,输入仍然会得到一个目标。我的第二次尝试是使用sphereCast来实现这一点,但它仍然需要一个球体中的目标,并且sphereCast击中的多个目标仍然需要通过输入只产生一个更精确的目标选择

因为我有了所有可能目标的所有transform.position以及原点,我想知道是否有一种更优雅的方法可以通过比较这些坐标(原点和目标在一般方向上)的矢量3来解决这个问题

以下是我的最新方法:

//
// 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;
        }
    }
}
//
//m_targetList是包含所有游戏对象作为其他脚本m_collector中的游戏对象的列表。m_collector所做的就是这个。
//
使用System.Collections.Generic;
使用UnityEngine;
公共类目标切换器:单行为
{
私人TargetCollector Mu collector;
私有转换m_起源;
公共布尔m_targetChanged=假;
公共游戏对象m_目标;
公共层掩码m_targetMask;
私有字典m_targetInfo=新字典();
私人空间
{
m_collector=GetComponent();
m_origin=GameObject.Find(“TargetOrigin”).transform;
m_tracker=GameObject.Find(“TargetTracker”).transform;
m_bound=GetComponent();
}
public void UpdateBearing(游戏对象来源)
{
m_origin=origin.transform;
foreach(m_collector.m_targetList中的游戏对象目标)
{
Vector3 dir=(target.transform.position-origin.transform.position)。标准化
float dist=矢量3.距离(origin.transform.position、target.transform.position);
m_targetInfo.Add(地区总监);
}
}
public-void-SwitchTarget()
{
如果(!m_targetChanged)
{
Vector2 dir=新的Vector2(Input.GetAxis(“水平”)、Input.GetAxis(“垂直”))。标准化;
//从字典中找到最接近此处目录的方向值
//如果有多个目标,比较与原点的距离,并选择最近的目标
}
}
公开作废的ReturnToIdle()
{
m_origin.position=m_target.transform.position;
m_targetChanged=假;
m_targetInfo.Clear();
}
公共结构TargetInfo
{
公共矢量3轴承;
公众浮标距离;
公共目标信息(矢量3方位,浮动距离)
{
这个轴承=轴承;
这个距离=距离;
}
}
}
通常,在SwitchTarget()之前,我尝试将方向输入的规范化向量与从原点到每个目标的规范化向量进行比较。这里的输入方法是Gamepad轴x和y,水平和垂直

重新发布此问题,因为提供的答案与问题相距甚远,并标记为重复(给出的答案是关于仅通过距离查找游戏对象,此问题是关于方向和距离的,当在方向上找到多个项目时,将间接比较)

编辑

在使用dot product进行了一些试验之后,我确信这很可能是我想要的方向。不过,我需要处理很多不一致的地方。 以下是我最近的一次尝试:

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;
                }
            }
        }
    }
}
private void Update()
{
UpdateBearing();
Vector3输入=新的Vector3(input.GetAxis(“水平”),input.GetAxis(“垂直”),0;
如果(输入!=Vector3.zero)
{
SwitchTarget();
}
}
public void UpdateBearing(游戏对象来源)
{
m_origin.position=origin.transform.position;
foreach(m_collector.m_targetList中的游戏对象目标)
{
Vector3 dir=(target.transform.position-origin.transform.position)。标准化;
如果(!m_targetInfo.ContainsKey(目标))
{
m_targetInfo.Add(target,dir);
}
}
}
public-void-SwitchTarget()
{
GameObject oldTarget=m_collector.m_target;
如果(!m_targetChanged)
{
Vector3 dir=新的Vector3(Input.GetAxis(“水平”),Input.GetAxis(“垂直”),0)。标准化;
Debug.DrawRay(m_原点位置,方向*100,颜色黄色,0.5f);
foreach(m_targetInfo中可能的键值对获取)
{
float dot=Vector3.dot(dir,possibleTarget.Value);
if(点>0.5f)//比较添加点和输入点的DP差异
{
GameObject newTarget=possibleTarget.Key;
如果(旧目标!=新目标)
{
Debug.Log(possibleTarget.Value+“/”+dot);
m_目标=新目标;
m_collector.m_target=newTarget;
m_targetChanged=真;
}
}
}
}
}

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

因为你在这个区域中有所有想要的游戏对象,你可以创建一个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;
}