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;
        }
}
相关推荐
EanoJiang4 小时前
【UE】支持所有Graph的截图插件
游戏
还是大剑师兰特4 小时前
Unity3D(Unity)完整详细介绍
unity·游戏引擎
ellis19708 小时前
u3d插件xLua[七]例6 Coroutine
unity
还是大剑师兰特9 小时前
Unity 从零搭建简易3D场景(新手分步教程)
3d·unity·游戏引擎
神码编程9 小时前
【Unity】TankBattle联机坦克大战(三)创建关卡(生成地块)
unity·游戏引擎·帧同步·坦克大战
淡海水10 小时前
C#与常用数据结构源码剖析-全篇导览
开发语言·数据结构·unity·面试·职场和发展·c#
玖玥拾1 天前
Unity3D RPG 入门项目(四)背包拖拽、物品悬浮提示、项目开发思维
3d·unity·游戏引擎
xcLeigh1 天前
Unity基础:Start与Update方法——Unity脚本生命周期初探
java·unity·游戏引擎·教程
郝学胜-神的一滴1 天前
[简化版 GAMES 104] 现代游戏引擎 05:游戏引擎世界构建核心机制深度解析
c++·程序人生·unity·游戏引擎·计算机图形学·opengl
雪碧透心凉_1 天前
Python游戏自动化实战案例
python·游戏·自动化