本人游戏策划一枚,爱好游戏设计开发

今天实现的内容是怪物AI,看了一些网上的AI,不是特别符合我的需求,于是就自己研究了一种AI,大致和魔兽类的RPG游戏效果差不多。

AI效果如下:

1. 将怪物分为如下几个状态:

待机状态(该状态内有3种行为:原地呼吸、原地观察、和游走,可通过权重配置待机状态下三种行为发生的比例);

警戒状态(怪物向玩家发出警告,并持续盯着玩家);

追击状态(怪物跑向玩家)

返回状态(跑回出生位置,该状态下不再理会玩家)

2. 可以为怪物配置各项状态的数值

游走半径,待机状态下,怪物游走时不会超出这个范围,根据出生点计算

警戒半径,当玩家与怪物之间距离小于警戒半径时进入警戒状态,根据怪物实时位置计算

自卫半径,当玩家与怪物之间距离小于自卫半径时进入追击状态

追击半径,怪物追击玩家时,自身不会超出这个范围,超出后跑回出生点,可以理解为最大活动范围

攻击距离,当玩家与怪物之间的距离小于攻击距离时触发战斗(我这边是进入之前做好的回合制战斗场景)

3. 各项数值设定的关系如下

比较合理的关系是:追击半径>警戒半径>自卫半径>攻击距离,游走半径只需要小于追击半径即可

1)自卫半径不建议大于警戒半径,否则就无法触发警戒状态,直接开始追击了

2)攻击距离不建议大于自卫半径,否则就无法触发追击状态,直接开始战斗了

3)游走半径不建议大于追击半径,否则怪物可能刚刚开始追击就返回出生点

我这边自己测试时,设置的属性如下:

接下来就是脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;public class MonsterWander : MonoBehaviour {private GameObject playerUnit;          //获取玩家单位private Animator thisAnimator;          //自身动画组件private Vector3 initialPosition;            //初始位置public float wanderRadius;          //游走半径,移动状态下,如果超出游走半径会返回出生位置public float alertRadius;         //警戒半径,玩家进入后怪物会发出警告,并一直面朝玩家public float defendRadius;          //自卫半径,玩家进入后怪物会追击玩家,当距离<攻击距离则会发动攻击(或者触发战斗)public float chaseRadius;            //追击半径,当怪物超出追击半径后会放弃追击,返回追击起始位置public float attackRange;            //攻击距离public float walkSpeed;          //移动速度public float runSpeed;          //跑动速度public float turnSpeed;         //转身速度,建议0.1private enum MonsterState{STAND,      //原地呼吸CHECK,       //原地观察WALK,       //移动WARN,       //盯着玩家CHASE,      //追击玩家RETURN      //超出追击范围后返回}private MonsterState currentState = MonsterState.STAND;          //默认状态为原地呼吸public float[] actionWeight = { 3000, 3000, 4000 };         //设置待机时各种动作的权重,顺序依次为呼吸、观察、移动public float actRestTme;            //更换待机指令的间隔时间private float lastActTime;          //最近一次指令时间private float diatanceToPlayer;         //怪物与玩家的距离private float diatanceToInitial;         //怪物与初始位置的距离private Quaternion targetRotation;         //怪物的目标朝向private bool is_Warned = false;private bool is_Running = false;void Start () {playerUnit = GameObject.FindGameObjectWithTag("Player");thisAnimator = GetComponent<Animator>();//保存初始位置信息initialPosition = gameObject.GetComponent<Transform>().position;//检查并修正怪物设置//1. 自卫半径不大于警戒半径,否则就无法触发警戒状态,直接开始追击了defendRadius = Mathf.Min(alertRadius, defendRadius);//2. 攻击距离不大于自卫半径,否则就无法触发追击状态,直接开始战斗了attackRange = Mathf.Min(defendRadius, attackRange);//3. 游走半径不大于追击半径,否则怪物可能刚刚开始追击就返回出生点wanderRadius = Mathf.Min(chaseRadius, wanderRadius);//随机一个待机动作RandomAction();}/// <summary>/// 根据权重随机待机指令/// </summary>void RandomAction(){//更新行动时间lastActTime = Time.time;//根据权重随机float number = Random.Range(0, actionWeight[0] + actionWeight[1] + actionWeight[2]);if (number <= actionWeight[0]){currentState = MonsterState.STAND;thisAnimator.SetTrigger("Stand");}else if (actionWeight[0] < number && number <= actionWeight[0] + actionWeight[1]){currentState = MonsterState.CHECK;thisAnimator.SetTrigger("Check");}if (actionWeight[0] + actionWeight[1] < number && number <= actionWeight[0] + actionWeight[1] + actionWeight[2]){currentState = MonsterState.WALK;//随机一个朝向targetRotation = Quaternion.Euler(0, Random.Range(1, 5) * 90, 0);thisAnimator.SetTrigger("Walk");}}void Update () {switch (currentState){//待机状态,等待actRestTme后重新随机指令case MonsterState.STAND:if (Time.time - lastActTime > actRestTme){ RandomAction();         //随机切换指令}//该状态下的检测指令EnemyDistanceCheck();break;//待机状态,由于观察动画时间较长,并希望动画完整播放,故等待时间是根据一个完整动画的播放长度,而不是指令间隔时间case MonsterState.CHECK:if (Time.time - lastActTime > thisAnimator.GetCurrentAnimatorStateInfo(0).length){RandomAction();         //随机切换指令}//该状态下的检测指令EnemyDistanceCheck();break;//游走,根据状态随机时生成的目标位置修改朝向,并向前移动case MonsterState.WALK:transform.Translate(Vector3.forward * Time.deltaTime * walkSpeed);transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed);if (Time.time - lastActTime > actRestTme){RandomAction();         //随机切换指令}//该状态下的检测指令WanderRadiusCheck();break;//警戒状态,播放一次警告动画和声音,并持续朝向玩家位置case MonsterState.WARN:if (!is_Warned){thisAnimator.SetTrigger("Warn");gameObject.GetComponent<AudioSource>().Play();is_Warned = true;}//持续朝向玩家位置targetRotation = Quaternion.LookRotation(playerUnit.transform.position - transform.position, Vector3.up);transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed);//该状态下的检测指令WarningCheck();break;//追击状态,朝着玩家跑去case MonsterState.CHASE:if (!is_Running){thisAnimator.SetTrigger("Run");is_Running = true;}transform.Translate(Vector3.forward * Time.deltaTime * runSpeed);//朝向玩家位置targetRotation = Quaternion.LookRotation(playerUnit.transform.position - transform.position, Vector3.up);transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed);//该状态下的检测指令ChaseRadiusCheck();break;//返回状态,超出追击范围后返回出生位置case MonsterState.RETURN://朝向初始位置移动targetRotation = Quaternion.LookRotation(initialPosition - transform.position, Vector3.up);transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed);transform.Translate(Vector3.forward * Time.deltaTime * runSpeed);//该状态下的检测指令ReturnCheck();break;}}/// <summary>/// 原地呼吸、观察状态的检测/// </summary>void EnemyDistanceCheck(){diatanceToPlayer = Vector3.Distance(playerUnit.transform.position, transform.position);if (diatanceToPlayer < attackRange){SceneManager.LoadScene("Battle");}else if (diatanceToPlayer < defendRadius){currentState = MonsterState.CHASE;}else if (diatanceToPlayer < alertRadius){currentState = MonsterState.WARN;}}/// <summary>/// 警告状态下的检测,用于启动追击及取消警戒状态/// </summary>void WarningCheck(){diatanceToPlayer = Vector3.Distance(playerUnit.transform.position, transform.position);if (diatanceToPlayer < defendRadius){is_Warned = false;currentState = MonsterState.CHASE;}if (diatanceToPlayer > alertRadius){is_Warned = false;RandomAction();}}/// <summary>/// 游走状态检测,检测敌人距离及游走是否越界/// </summary>void WanderRadiusCheck(){diatanceToPlayer = Vector3.Distance(playerUnit.transform.position, transform.position);diatanceToInitial = Vector3.Distance(transform.position, initialPosition);if (diatanceToPlayer < attackRange){SceneManager.LoadScene("Battle");}else if (diatanceToPlayer < defendRadius){currentState = MonsterState.CHASE;}else if (diatanceToPlayer < alertRadius){currentState = MonsterState.WARN;}if (diatanceToInitial > wanderRadius){//朝向调整为初始方向targetRotation = Quaternion.LookRotation(initialPosition - transform.position, Vector3.up);}}/// <summary>/// 追击状态检测,检测敌人是否进入攻击范围以及是否离开警戒范围/// </summary>void ChaseRadiusCheck(){diatanceToPlayer = Vector3.Distance(playerUnit.transform.position, transform.position);diatanceToInitial = Vector3.Distance(transform.position, initialPosition);if (diatanceToPlayer < attackRange){SceneManager.LoadScene("Battle");}//如果超出追击范围或者敌人的距离超出警戒距离就返回if (diatanceToInitial > chaseRadius || diatanceToPlayer > alertRadius){currentState = MonsterState.RETURN;}}/// <summary>/// 超出追击半径,返回状态的检测,不再检测敌人距离/// </summary>void ReturnCheck(){diatanceToInitial = Vector3.Distance(transform.position, initialPosition);//如果已经接近初始位置,则随机一个待机状态if (diatanceToInitial < 0.5f){is_Running = false;RandomAction();}}}

以上脚本经过多次测试,运行结果均较为理想。

Unity游戏开发 怪物巡逻AI相关推荐

  1. (Unity游戏开发)五天时间做出一款饥荒类的生存游戏Demo,项目在手,还怕面试官不给offer?

    游戏行业作为当下最火热的行业之一,受到了很多人的喜爱,也有很多同学想要进入游戏开发行业,但常常找不到靠谱的学习资源,不知道如何在入行前拥有项目经验,我为大家准备了最实用的unity游戏开发学习资料,助 ...

  2. 总结下花了大约半年的时间从零开始的unity游戏开发(1)

    从那个2016年8月份左右 ,受了自己爱好的影响,入坑了Unity游戏开发的路上了.知道现在2017年3月20号,我在一家手游公司呆了4个月了,其中加班的日子总是星期一到星期六,每天早上9点上到晚上1 ...

  3. Unity游戏开发大师班

    大小解压后:8.63G 持续时间19h 包含项目文件 1280X720 MP4 语言:英语+中英文字幕(根据原英文字幕机译更准确) Unity游戏开发大师班 信息: 要求 –没有课程要求,展示了开发过 ...

  4. 最全面的Unity游戏开发指南视频教程 第2卷

    最全面的Unity游戏开发指南视频教程 第2卷 流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小 ...

  5. Unity 游戏开发技巧集锦之使用cookie类型的纹理模拟云层的移动

    Unity 游戏开发技巧集锦之使用cookie类型的纹理模拟云层的移动 使用cookie类型的纹理模拟云层的移动 现实生活中,当阳光直射大地,而天空中又有很多云时,云层的影子总是会投射在大地上,风吹着 ...

  6. Unity 游戏开发技巧集锦之创建透明的材质

    Unity 游戏开发技巧集锦之创建透明的材质 Unity创建透明的材质 生活中不乏透明或者半透明的事物.例如,擦的十分干净的玻璃,看起来就是透明的:一些塑料卡片,看起来就是半透明的,如图3-23所示. ...

  7. Unity 游戏开发技巧集锦之创建部分光滑部分粗糙的材质

    Unity 游戏开发技巧集锦之创建部分光滑部分粗糙的材质 创建部分光滑部分粗糙的材质 生活中,有类物体的表面既有光滑的部分,又有粗糙的部分,例如丽江的石板路,如图3-17所示,石板的表面本来是粗糙的, ...

  8. Unity 游戏开发技巧集锦之创建自发光材质

    Unity 游戏开发技巧集锦之创建自发光材质 创建自发光材质 自发光材质(self-illuminated material)是指自己会发光的材质.生活中与之相似的例子,就是液晶显示屏上显示的信息,文 ...

  9. ​Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机

    ​Unity 游戏开发技巧集锦之制作一个望远镜与查看器摄像机 Unity中制作一个望远镜 本节制作的望远镜,在鼠标左键按下时,看到的视图会变大:当不再按下的时候,会慢慢缩小成原来的视图.游戏中时常出现 ...

最新文章

  1. webpack打开项目命令_配置webpack中dev.env.js、prod.env.js,解决不同命令下项目启动和打包到指定的环境...
  2. Python编写爬虫编写到Excel中
  3. 中国人工智能学会通讯——搜狗搜索:从搜索到问答 1.1 引言
  4. Python-OpenCV 处理图像(五):图像中边界和轮廓检测
  5. hadoop datajoin
  6. python带界面的计算器
  7. matlab中统计数组中各数字(元素)出现的次数
  8. java ==和equals的区别
  9. 主板扩展槽图解_子板:扩展到主板
  10. Swin Transformer(W-MSA详解)代码+图解
  11. 小程序入门到精通:微信小程序介绍及开发准备工作(一)
  12. input之question
  13. MySQL Innodb引擎和MyIASM引擎的区别
  14. MVC进阶学习--HtmlHelper控件解析(五)
  15. 利用工作流给Windows SharePoint Service 3.0添加Skype通知功能
  16. 社会工程学之ip获取和定位
  17. 阿里软件测试工程师推荐|自动化测试——HTTP之URL
  18. Axure原型设计灯箱效果
  19. Python教学案例 - 三天打渔、两天晒网
  20. php身份证实名认证接口

热门文章

  1. 如何删除windows中的服务
  2. c语言三个字母比较大小,C语言stricmp()函数:比较两个字符串大小
  3. JS本地存储和会话存储的区别
  4. 压缩机振动探头本特利330904-06-14-05-02-00
  5. UE4之多人局域网游戏中GameMode/PlayerController/Pawn/Character/GameInstance/GameState/PlayState 6个类的生成情况和生成个数
  6. WinForm实现Rabbitmq官网6个案例-Publishe/Subscribe
  7. 粤教版管理计算机中的文件教案,粤教版高中信息技术教案(数据库).doc
  8. Ubuntu下键盘输入错乱问题
  9. 有限元方法简介与COMSOL操作入门
  10. 推荐算法遇到后悔药:评蚂蚁的ESCM2模型