怪物AI之发现玩家(视觉范围发现系列)

在网上找到一些资料参考,然后写写自己的想法。

这里感谢MOMO等大神。

我们用玩家检测怪物的方法来测,这样比较试用与弱联网游戏,每次在同步玩家的时候来判断玩家与怪物的位置。

这里给出两个处理方式:

1.碰撞器R范围检测。

2.地图分块范围检测。

这两种处理方式适用于不同的游戏。

再讲解这两种方式之前,我们先了解一下一个核心问题,怪物在玩家R半径内时怎么判断怪物是否在玩家视觉范围内。

如下图

在图中,

玩家的位置与怪物的位置会成一个向量。设为V1

怪物的朝向也是一个向量。设为V2

如果怪物能看到60°的角度的话。那么Vector(V1,V2)如果小于30°则证明玩家在怪物的视觉范围内。

代码为:

    private bool Find(GameObject _Monster)
    {
        otherPos = _Monster.gameObject.transform.position;
        v = transform.position - otherPos;
        v.y = 0.5f; //处理一下y轴,因为判断建立在二维上
        w = _Monster.gameObject.GetComponent<FindPlayerAI>().getFace() - otherPos;
        w.y = 0.5f;
        if (Vector3.Angle(v, w) < 30)
        {
            return true;
        }
        return false;
    }

PS:如果想在三维上进行判断的话,同理在处理一下yz轴平面就ok了。

现在我们讲解一下第一种处理方式:

这种比较简单也很无脑。给Player加一个SphereCollider就好了,而且这样也可以判断三维状态。注:如果用Terrain做地面请屏蔽。

碰撞器代码

    void OnTriggerEnter(Collider other)
    {
        if (!other.name.Equals("Terrain"))
        {
            if (Find(other.gameObject)) //接上一个Find代码
            {
                Debug.Log("发现");
            }
        }
    }

然后就是第二种比较有想法的方式了。

将游戏地图分块。如下图

这里呢。大体思路为:

玩家在0号块,在这个状态的时候,只有a,b怪物可以与玩家进行角度判断,cdef都忽略掉。

代码如下:

Map.cs:

public class Map : MonoBehaviour{

    private static Map _Instance;

    public static Map Instance
    {
        get
        {
            if (_Instance == null)
            {
                _Instance = new GameObject("_Map").AddComponent<Map>();
            }
            return _Instance;
        }
    }

    private int PlayerPos = -1;

    private GameObject[][] Monster = new GameObject[100][];
    private int[] MonsterNum = new int[100];

    //public int n = 0;

    void Awake()
    {    
        for (int i = 0; i < 100; i++)
        {
            Monster[i] = new GameObject[10];
            MonsterNum[i] = 0;
        }
    }

    int getPos(GameObject go)
    {
        float x = go.transform.position.x;
        float z = go.transform.position.z;
        x /= 20;
        z /= 20;
        int pos = (int)(Mathf.Floor(x) + Mathf.Floor(z) * 10);
        return pos;
    }

    public void setMonsterPos(GameObject _Monster)
    {
        int pos = getPos(_Monster);
        Monster[pos][MonsterNum[pos]++] = _Monster;
        Debug.Log(pos + _Monster.name);
    }
    
    public int getPlayerPos(GameObject _Player)
    {
        int pos = getPos(_Player);
        if (PlayerPos == pos)
        {
            return -1;
        }
        else
        {
            PlayerPos = pos;
        }
        return pos;
    }

    public GameObject[] getMonster(int pos)
    {
        return Monster[pos];
    }

}

玩家AI.cs:

public class PlayerAI : MonoBehaviour {

    Vector3 v;
    Vector3 w;
    Vector3 otherPos;
    GameObject[] Monster = new GameObject[10];

    private bool Find(GameObject _Monster)
    {
        otherPos = _Monster.gameObject.transform.position;
        v = transform.position - otherPos;
        v.y = 0.5f;
        w = _Monster.gameObject.GetComponent<MonsterAI>().getFace() - otherPos;
        w.y = 0.5f;
        if (Vector3.Angle(v, w) < 30)
        {
            return true;
        }
        return false;
    }

    //void OnTriggerEnter(Collider other)
    //{
    //    if (!other.name.Equals("Terrain"))
    //    {
    //        if (Find(other.gameObject))
    //        {
    //            Debug.Log("发现");
    //        }
    //    }
    //}

    void Update()
    {
        int pos = Map.Instance.getPlayerPos(gameObject);
        if (pos != -1)
        {
            Monster = Map.Instance.getMonster(pos);
        }
        for (int i = 0; i < Monster.Length; i++)
        {
            if (Monster[i] != null)
            {
                if (Find(Monster[i]))
                {
                    Debug.Log(i + "发现");
                }
            }
        }
    }
}

怪物AI.cs:

public class MonsterAI : MonoBehaviour {

    public GameObject Player;

    private Vector3 Face;

    void Start () {
        Face = transform.position + transform.rotation * Vector3.forward * 10;
        Map.Instance.setMonsterPos(gameObject);
    }

    public Vector3 getFace()
    {
        return Face;
    }

    void Update()
    {
        Face = transform.position + transform.rotation * Vector3.forward * 10;
        //Debug.DrawLine(transform.position, Face, Color.red);
    }
}
原文地址:https://www.cnblogs.com/SHOR/p/5490601.html