Unity——游戏AI实例

上文Unity------模拟AI视觉已经实现了敌人视野探测功能,本文来完善敌人AI。

注意:若要阅读此文,务必在阅读完Unity------模拟AI视觉的基础上阅读


效果预展示:

AI敌人追击


接下来用最简单的方式实现敌人的AI状态机。首先,定义敌人的3个状态------待机、进攻和返回。

cs 复制代码
 enum AIState
    {
        Idle,   //待机状态
        Attack,  //进攻状态
        Back,    //返回状态
    } 

然后将Update函数改为状态机的模式,直接用switch-case语句实现

cs 复制代码
  enum AIState
    {
        Idle,   //待机状态
        Attack,  //进攻状态
        Back,    //返回状态
    } 
    AIState state;
 void Update()
    {
       
        switch (state)
        {
            case AIState.Idle:
                {
                    //待机状态。进行实现检测,若发现玩家则进攻
                    FieldOfView();
                }
                break;
                case AIState.Attack:
                {
                    //进攻状态,若离玩家或起点太远,则返回
                }
                break ;
                case AIState.Back:
                {
                    //返回状态
                }
                break;
        }
     }

状态机的原理比较复杂,但只需要用一个switch-case语句就能实现,或者用if语句编写也可以。之后只要把设计思路按部就班地编写成程序代码即可。

  1. 在待机状态下,要不断进行射线检测。如果射线检测发现了玩家,就可以将玩家的引用保存起来,以便后面进攻时使用。需要注意的是,应当将玩家及其子物体的Tag都改为Player,方便判断。
  2. 在进攻状态下,不断向目标位置移动(利用导航系统)。同时检测当前位置与起点或玩家之间的距离,如果距离过远就返回。
  3. 在返回状态下,先朝起点的位置移动,当移动到位后,再转向正面,回到一开始的朝向。有必要一开始就把初始的位置和朝向记录下来,分别是homePos和homeRot。
cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AIEnemy : MonoBehaviour
{
    Transform target;   //目标角色
    Vector3 homePos;  //起始位置
    Quaternion homeRot;  //起点的朝向 
    UnityEngine.AI.NavMeshAgent agent;
    public int viewRadius = 4;  //视野距离
    public int viewLines = 30; //射线数量
    public MeshFilter viewMeshFilter;
    List<Vector3> viewVerts;  //定点列表
    List<int> viewIndices;  //定点序号列表
    enum AIState
    {
        Idle,   //待机状态
        Attack,  //进攻状态
        Back,    //返回状态
    } 
    AIState state;   //AI状态机的状态
    void Start()
    {
        Transform view = transform.Find("view");
        viewMeshFilter = view.GetComponent<MeshFilter>();
        agent=GetComponent<UnityEngine.AI.NavMeshAgent>();

        viewVerts = new List<Vector3>();
        viewIndices = new List<int>();
        state = AIState.Idle;

        homePos = transform.position;
        homeRot = transform.rotation;
    }


    void Update()
    {
       
        switch (state)
        {
            case AIState.Idle:
                {
                    //待机状态。进行射线检测,若发现玩家则进攻
                    FieldOfView();
                    if (target != null)
                    {
                        state= AIState.Attack;  //切换状态
                    }
                }
                break;
                case AIState.Attack:
                {
                    //进攻状态,若离玩家或起点太远,则返回
                    agent.SetDestination(target.position);
                    if(Vector3.Distance(transform.position, target.position) > 10)
                    {
                        target = null;
                        state= AIState.Back;
                    }
                    if (Vector3.Distance(transform.position, homePos)>15)
                    {
                        target = null;
                        state = AIState.Back;
                    }
                }
                break ;
                case AIState.Back:
                {
                    //返回状态
                    agent.SetDestination(homePos);
                    if (!agent.hasPath)
                    {
                        //回到起点,匀速转到正面
                        if(Quaternion.Angle(homeRot,transform.rotation)>0.5f)
                        {
                            //逐步向目标角度转动,每次最多转2°
                            Quaternion q = Quaternion.RotateTowards(transform.rotation, homeRot, 2f);
                                transform.rotation = q;
                        }
                        else
                        {
                            state = AIState.Idle;
                        }
                    }
                }
                break;
        }
     }
        void FieldOfView()
        {
            viewVerts.Clear();
            viewVerts.Add(Vector3.zero);  //加入起点坐标,局部坐标系


            //获得最左边那条射线的向量,相对正前方,角度是-45°
            Vector3 forward_left = Quaternion.Euler(0, -45, 0) * transform.forward * viewRadius;
            //依次处理每条射线
            for (int i = 0; i <= viewLines; i++)
            {
                Vector3 v = Quaternion.Euler(0, (90.0f / viewLines) * i, 0) * forward_left;
                //角色位置+v,就是射线终点pos
                Vector3 pos = transform.position + v;

                //实际发射射线。注意RayCast的参数,重载很多容易搞错
                RaycastHit hitInfo;
                if (Physics.Raycast(transform.position, v, out hitInfo, viewRadius))
                {
                    //碰到物体,终点改为碰到的点
                    pos = hitInfo.point;
                if (hitInfo.transform.CompareTag("Player"))
                {
                    target=hitInfo.transform;
                }
                }
                //将每个点的位置加入列表,注意转为局部坐标系
                Vector3 p = transform.InverseTransformPoint(pos);
                viewVerts.Add(p);

            }
            //根据顶点绘制模型
            RefreshView();
        }
        void RefreshView()
        {
            viewIndices.Clear();
            //逐个加入三角面,每个三角面都以起点开始
            for (int i = 1; i < viewVerts.Count - 1; i++)
            {
                viewIndices.Add(0);
                viewIndices.Add(i);
                viewIndices.Add(i + 1);
            }
            //填写Mesh信息
            Mesh mesh = new Mesh();
            mesh.vertices = viewVerts.ToArray();
            mesh.triangles = viewIndices.ToArray();
            viewMeshFilter.mesh = mesh;
        }
}
相关推荐
DK1858383225215 小时前
【源码开源部署】电竞代练护航陪玩小程序:全游戏服务平台完整解决方案(附宝塔部署教程)
游戏·微信小程序·uni-app·开源·php
这料鬼有毒19 小时前
二刷hot100-45.跳跃游戏Ⅱ
游戏
玖玥拾19 小时前
Lua 基础语法(二)
开发语言·unity·lua
沧沧凉凉1 天前
两个小时,AI 把我 2018 年那个 Unity 版保卫萝卜搬进了浏览器
前端·游戏·ai编程
玖玥拾1 天前
Lua 基础语法(三) 元表 metatable、元方法、模拟面向对象
开发语言·unity·lua
Maynor9961 天前
「原子弹爆炸」级别:Astra 复刻游戏合集(含实机截图)
java·linux·运维·数据库·gpt·游戏
wind100323 天前
DLSS5 开启保姆级教程:RTX20/30/40 显卡通用 鸣潮 / 异环 / 绝区零全适配
游戏·电脑·英伟达·dlss·鸣潮
谢斯3 天前
[unity]如何在unity中添加newtonsoft-json
unity·json·游戏引擎
全速向光3 天前
JoiPlay 模拟器:在手机上畅玩你所热爱的独立游戏
游戏·智能手机
天人合一peng3 天前
Unity标记固定颜色及投影标记
unity