通过输入

时间:2017-12-05 06:09:42

标签: unity3d

Example

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

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

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

由于我拥有所有可能目标以及原点的所有变换位置,我想知道通过比较这些坐标的矢量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;
        }
    }
}

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

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

修改

经过对dot产品的一些试验后,我确信这很可能是我想要去的地方。但是,我需要继续存在很多不一致之处。 这是我最近的尝试:

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&gt; 0.5f)更好的案例比较。另外,我粗略的假设是,如果我不为每个Key更新字典m_targetInfo的值,那么如果这些目标移动,我会有另一个不一致。无论如何,我仍然很困惑如何正确地利用它来实现我的最终目标。

1 个答案:

答案 0 :(得分:2)

由于你在该区域拥有所有想要的游戏对象,你可以创建一个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;
}