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;
        }
}
相关推荐
冰凌糕19 分钟前
Unity3D 单例模式
unity
幻狐boke5 小时前
【游戏模组】星际争霸1代模组燃烧之地,泰伦帝国对决UED。特效华丽兵种巨多特别好玩
游戏
科技资讯早知道11 小时前
java计算机毕设课设—坦克大战游戏
java·开发语言·游戏·毕业设计·课程设计·毕设
程序猿阿伟1 天前
《C++游戏人工智能开发:开启智能游戏新纪元》
c++·人工智能·游戏
Artistation Game1 天前
九、怪物行为逻辑
游戏·unity·游戏引擎
百里香酚兰1 天前
【AI学习笔记】基于Unity+DeepSeek开发的一些BUG记录&解决方案
人工智能·学习·unity·大模型·deepseek
妙为1 天前
unreal engine5制作动作类游戏时,我们使用刀剑等武器攻击怪物或敌方单位时,发现攻击特效、伤害等没有触发
游戏·游戏引擎·虚幻·碰撞预设
网站领航1 天前
服装时尚与动漫游戏的跨界联动:创新运营与策划策略研究
游戏·流量运营·用户运营
龙智DevSecOps解决方案1 天前
Perforce演讲回顾(上):从UE项目Project Titan,看Helix Core在大型游戏开发中的版本控制与集成使用策略
游戏·ue5·源代码管理·perforce·helix core
dangoxiba2 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十三集:制作小骑士的接触地刺复活机制以及完善地图的可交互对象
游戏·unity·visualstudio·c#·游戏引擎