• 怪物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);
        }
    }
  • 相关阅读:
    error LNK2019: 无法解析的外部符号 该符号在函数 中被引用 解决方案
    【OSG】运行OSG示例出现的奶牛不完整问题
    python 遍历文件夹
    python os操作
    python io操作
    python request 代理/超时/证书
    python tuple
    python dict
    python request post
    python request get
  • 原文地址:https://www.cnblogs.com/SHOR/p/5490601.html
Copyright © 2020-2023  润新知