『功能项目』怪物的有限状态机【42】
本章项目成果展示
我们打开上一篇41项目优化 - 框架加载资源的项目,
本章要做的事情是按照框架的思想构建项目并完成怪物的自动巡逻状态,当主角靠近怪物时,怪物会朝向主角释放技能
首先新建脚本:BossCtrl.cs
(通常把xxxCtrl.cs脚本写在中间层,后续会增加xxxOpt.cs脚本进行调用xxxCtrl.cs中的函数)
(xxxOpt.cs脚本在上层调用)
using UnityEngine;
public class BossCtrl : MonoBehaviour{protected bool isDead;Animator animator;public int hp;public int currentHp;public int attackValue;public int defineValue;public void Init() {isDead = false;hp = currentHp = 1000;attackValue = 700;defineValue = 700;animator = GetComponent<Animator>();animator.SetBool("IsMoving", false);}
}
将控制层(xxxCtrl.cs)增加在资源框架脚本中:
此时怪物身上就有了血量攻击力防御力等数据
接下来再增加一个xxxOpt.cs脚本调用xxxCtrl.cs脚本的数据以及通用机制(此时xxxCtrl.cs还没有写通用机制,可以理解为后续将机制写在xxxCtrl.cs中 而调用写在xxxOpt.cs脚本中)
新建脚本:BossOpt.cs
using UnityEngine;
public class BossOpt : MonoBehaviour{FSM fsm;public BossBlackboard blackboard;Vector3 playerPos;Vector3 selfPos;Transform blackboardTransform;Vector3 blackboardTargetPos;Animator animator;public void Start(){blackboardTransform = GameObject.Find("Boss01").gameObject.transform;blackboardTargetPos = new Vector3 (0, 45, 15);blackboard = new BossBlackboard(5,3, blackboardTransform, blackboardTargetPos, transform.position);fsm = new FSM(blackboard);fsm.AddState(StateType.Idle, new AI_IdleState(fsm));fsm.AddState(StateType.Move, new AI_MoveState(fsm));blackboard.initPos = transform.position; fsm.SwitchState(StateType.Idle);animator = GetComponent<Animator>();}void Update(){selfPos = transform.position;playerPos = GameObject.Find("PlayerNormal").gameObject.transform.position;if (Vector3.Distance(selfPos, playerPos) < 10) {animator.SetBool("IsSkill", true);transform.LookAt(playerPos + new Vector3(0,3,0)); }if (Vector3.Distance(selfPos, playerPos) >= 10) {animator.SetBool("IsSkill", false);fsm.OnUpdate();transform.LookAt(blackboard.targetPos);}}
}
此时会有很多红色报错,因为少了一些自定义的类,接下来我们创建FSM类
也就是说BossOpt.cs是调用FSM(有限状态机)类的脚本,接下来我们需要写有限状态机类:
新建脚本:Blackboard.cs
using System;
[Serializable]
public class Blackboard{//此处存储共享数据 或者向外展示的数据 可配置数据
}
新建脚本:BossBlackboard.cs
using System;
using UnityEngine;
[Serializable]
public class BossBlackboard : Blackboard{//闲置时间public float idleTime;public float moveSpeed;public Transform transform;public Vector3 targetPos;public Vector3 initPos;public BossBlackboard(float idleTime, float moveSpeed,Transform transform, Vector3 targetPos, Vector3 initPos){this.idleTime = idleTime;this.moveSpeed = moveSpeed;this.transform = transform;this.targetPos = targetPos;this.initPos = initPos;}
}
新建脚本:IState.cs
public interface IState{void OnEnter();void OnExit();void OnUpdate();
}
新建脚本:FSM.cs
using System.Collections.Generic;
public enum StateType{Idle,Move,
}
public class FSM {public IState curState;public Dictionary<StateType, IState> states;public Blackboard blackboard;public FSM(Blackboard blackboard) {this.states = new Dictionary<StateType, IState>();this.blackboard = blackboard;}//外部使用 - 增加状态public void AddState(StateType stateType, IState state) {if (states.ContainsKey(stateType)) {return;}states.Add(stateType,state);}//外部使用 - 切换状态public void SwitchState(StateType stateType) {if (!states.ContainsKey(stateType)) {return;}if (curState != null) {curState.OnExit();}curState = states[stateType];curState.OnEnter();}public void OnUpdate() {curState.OnUpdate();}
}
新建脚本:AI_IdleState.cs
using UnityEngine;
public class AI_IdleState : IState{//闲置计时器public float idleTimer;public AI_IdleState(FSM fsm){this.fsm = fsm;blackboard = fsm.blackboard as BossBlackboard;}FSM fsm;BossBlackboard blackboard;public void OnEnter(){idleTimer = 0;}public void OnUpdate(){idleTimer += Time.deltaTime;if (idleTimer > blackboard.idleTime){fsm.SwitchState(StateType.Move);}}public void OnExit() { }
}
新建脚本:AI_MoveState.cs
using UnityEngine;
public class AI_MoveState : IState{Animator animator;public float idleTimer;FSM fsm;BossBlackboard blackboard;public AI_MoveState(FSM fsm){this.fsm = fsm;blackboard = fsm.blackboard as BossBlackboard;}public void OnEnter(){animator = GameObject.Find("Boss01").GetComponent<Animator>();float randomAngle = Random.Range(0, 360);float randomRadius = Random.Range(0, 7);blackboard.targetPos = new Vector3(blackboard.initPos.x + Mathf.Cos(Mathf.Deg2Rad * randomAngle) * randomRadius,blackboard.transform.position.y,blackboard.initPos.z + Mathf.Sin(Mathf.Deg2Rad * randomAngle) * randomRadius);}public void OnExit() { }public void OnUpdate(){if (Vector3.Distance(blackboard.transform.position, blackboard.targetPos) < 0.1f){fsm.SwitchState(StateType.Idle);animator.SetBool("IsMoving", false);}else{blackboard.transform.position = Vector3.MoveTowards(blackboard.transform.position,blackboard.targetPos, blackboard.moveSpeed * Time.deltaTime);animator.SetBool("IsMoving", true);}}
}
保存代码将调用FSM(有限状态机类)的BossOpt.cs脚本增加到GameManager.cs资源框架上
运行项目 - Boss就会Idle状态5秒钟后随机移动任意方向5秒钟进行循环并且不会超过以自身为原点半径为7的圆范围
本章利用有限状态机FSM做了Idle与Move下的转换,并且当主角靠近怪物时 怪物会释放技能
接下来利用前几章的知识增加一些脚本,增加技能特效,怪物UI信息,以及伤害计算让主角持续掉血
首先创建怪物UI信息
以前文章有制作教程
将UI对象放在指定文件夹下
之前导入的技能包中可找到该技能或者重新导入个新技能修改其名字放进指定文件夹即可
修改脚本:
using System.Collections;
using UnityEngine;
public class BossOpt : MonoBehaviour{FSM fsm;public BossBlackboard blackboard;Vector3 playerPos;Vector3 selfPos;Transform blackboardTransform;Vector3 blackboardTargetPos;Animator animator;#region UI信息GameObject infoUIPrefab;GameObject infoUIInstance;bool Count;#endregion#region 技能特效GameObject boss01SkillPrefab;#endregion#region 伤害计算GameManager gm;BossCtrl bossCtrl;#endregionpublic void Start(){blackboardTransform = GameObject.Find("Boss01").gameObject.transform;blackboardTargetPos = new Vector3 (0, 45, 15);blackboard = new BossBlackboard(5,3, blackboardTransform, blackboardTargetPos, transform.position);fsm = new FSM(blackboard);fsm.AddState(StateType.Idle, new AI_IdleState(fsm));fsm.AddState(StateType.Move, new AI_MoveState(fsm));blackboard.initPos = transform.position; fsm.SwitchState(StateType.Idle);animator = GetComponent<Animator>();#region UI信息infoUIPrefab = Resources.Load<GameObject>("Prefabs/Images/Boss01UI");Count = false;#endregion#region 技能特效boss01SkillPrefab = Resources.Load<GameObject>("Prefabs/Effects/Boss01Effect");#endregion#region 伤害计算gm = GameManager.Instance;bossCtrl = gameObject.GetComponent<BossCtrl>();#endregion}void Update(){selfPos = transform.position;playerPos = GameObject.Find("PlayerNormal").gameObject.transform.position;if (Vector3.Distance(selfPos, playerPos) < 10) {animator.SetBool("IsSkill", true);transform.LookAt(playerPos + new Vector3(0,3,0));#region UI信息 -> 技能特效if (!Count) {infoUIInstance = Instantiate(infoUIPrefab, new Vector3(0f, -50f, 0f), Quaternion.identity);infoUIInstance.transform.SetParent(GameObject.Find("CurrentCanvas").transform, false);Count = true;infoUIInstance.AddComponent<Boss01UIInfo>();#region 技能特效StartCoroutine(WaitTwoSStartBoss01Skill());#endregion}#endregion}if (Vector3.Distance(selfPos, playerPos) >= 10) {animator.SetBool("IsSkill", false);fsm.OnUpdate();transform.LookAt(blackboard.targetPos);#region UI信息 -> 技能特效if (Count) {Destroy(infoUIInstance);Count = false;#region 技能特效Destroy(GameObject.Find("Boss01Effect(Clone)").gameObject);#endregion}#endregion}}#region 技能特效IEnumerator WaitTwoSStartBoss01Skill(){yield return new WaitForSeconds(2);Instantiate(boss01SkillPrefab, transform.position, transform.localRotation);while (true) {gm.infoSys.playerCurrentHP -= bossCtrl.attackValue - gm.infoSys.defineValue;yield return new WaitForSeconds(2);if (Vector3.Distance(selfPos, playerPos) >= 10)break;}}#endregion
}
新建脚本:Boss01UIInfo.cs
using UnityEngine;
using UnityEngine.UI;
public class Boss01UIInfo : MonoBehaviour{BossCtrl bossCtrl;Slider hp;void Start(){bossCtrl = FindObjectOfType<BossCtrl>();hp = transform.Find("Slider").GetComponent<Slider>();}void Update(){if (hp != null)hp.value = bossCtrl.currentHp;}
}
运行项目即可实现 - 主角不在怪物攻击范围之内 ,怪物进行停留五秒随机行走三秒但不会超过半径为7米的圆范围, 一旦主角进入敌人范围,怪物会朝向主角释放技能,生成怪物UI信息,并且每次释放技能会让主角失去一定血量,当主角离开范围内,怪物回到巡逻状态
本章做了主角不在怪物攻击范围之内 ,怪物进行停留五秒随机行走三秒但不会超过半径为7米的圆范围, 一旦主角进入敌人范围,怪物会朝向主角释放技能,生成怪物UI信息,并且每次释放技能会让主角失去一定血量,当主角离开范围内,怪物回到巡逻状态的功能
接下来要实现:
1.战士职业平A(按A键)使怪物掉血的功能
2.窗口可拖拽脚本
3.点击名称寻找地点功能
4.隐藏怪物的生成
5.怪物I攻击范围内的主动攻击
6.掉落坐骑蛋的获取
7.异步传送转换场景
以及开放回合制、坐骑系统、宠物系统、背包系统、神炼系统、商城系统、Boss的目标跟随任务导航系统以及UI播放3D动画效果等等。
具体项目运行效果请关注water1024的b站视频项目演示《破碎纪元》
【Unity回合2.5D】破碎纪元_单机游戏热门视频 (bilibili.com)https://www.bilibili.com/video/BV1rZY4e9Ebs/?spm_id_from=333.999.0.0&vd_source=547091a95b03acfa8e8a9e46ef499cd6
相关文章:

『功能项目』怪物的有限状态机【42】
本章项目成果展示 我们打开上一篇41项目优化 - 框架加载资源的项目, 本章要做的事情是按照框架的思想构建项目并完成怪物的自动巡逻状态,当主角靠近怪物时,怪物会朝向主角释放技能 首先新建脚本:BossCtrl.cs (通常把xxxCtrl.cs脚…...

【C++】模板进阶:深入解析模板特化
C语法相关知识点可以通过点击以下链接进行学习一起加油!命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与Queue 本章将…...

Python数据分析-世界上最富有的1000人
一、研究背景 随着全球化的加速发展和技术的进步,财富分配问题日益成为全球关注的焦点。财富的不平等现象日益明显,少数极富有的个人掌握了全球大部分的财富资源。了解全球最富有个人的财富分布及其背后的行业和国家因素,对于分析全球经济趋…...
CSS中隐藏滚动条的同时保留滚动功能
在CSS中,我们可以通过一些技巧来隐藏滚动条,同时保留滚动功能。以下是几种常用的方法和具体的实现步骤。 1. 使用 overflow 和 ::-webkit-scrollbar 这种方法适用于大多数现代浏览器。通过设置 overflow 属性启用滚动,同时利用 ::-webkit-s…...

我的标志:奇特的头像
<!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>与妖为邻</title><style>figu…...

中国空间计算产业链发展分析
2024中国空间计算产业链拆解 空间计算设备主要包括AR、VR、MR等终端设备。VR设备通常包括头戴式显示器(VR头盔)、手柄或追踪器等组件,用以完全封闭用户视野,营造虚拟环境体验。这些设备配备高分辨率显示屏、内置传感器和跟踪器。 …...

DAY14信息打点-JS 架构框架识别泄漏提取API 接口枚举FUZZ 爬虫插件项目
本课意义: 1.如何从表现中的JS提取价值信息 2.如何从地址中FUZZ提取未知的JS文件 3.如何从JS开放框架WebPack进行测试 一、JS 前端架构-识别&分析 在JS中寻找更多的URL地址,在JS代码逻辑(加密算法、APIKey配置、验证逻辑)中进…...

TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
目录 1,前言2,二者关系2.1,使用 3,遇到的问题3.1,TS 中使用 JS 1,前言 通过 Vite 创建的 Vue3 TS 项目,根目录下会有 tsconfig.json 和 tsconfig.node.json 文件,并且存在引用关系…...

revisiting拉普拉斯模板
二维向量的二阶微分是Hessian矩阵,拉普拉斯算子是将两个独立的二阶微分求和,对二阶微分的近似。 我不认同冈萨雷斯的8邻域拉普拉斯模板。 MATLAB图像处理工具箱中fspecial函数’laplacian’参数给的拉普拉斯模板: 对于数字滤波器ÿ…...

深入分析计算机网络性能指标
速率带宽吞吐量时延时延带宽积往返时间RTT利用率丢包率图书推荐内容简介作者简介 速率 连接在计算机网络上的主机在数字信道上传送比特的速率,也称为比特率或数据率。 基本单位:bit/s(b/s、bps) 常用单位:kb/s&#x…...

pyflink 安装和测试
FPY Warning! 安装 apache-Flink # pip install apache-Flink -i https://pypi.tuna.tsinghua.edu.cn/simple/ Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/ Collecting apache-FlinkDownloading https://pypi.tuna.tsinghua.edu.cn/packages/7f/a3/ad502…...
《网络故障处理案例:公司网络突然中断》
网络故障处理案例:公司网络突然中断 一、故障背景 某工作日上午,一家拥有 500 名员工的公司突然出现整个网络中断的情况。员工们无法访问互联网、内部服务器和共享文件,严重影响了工作效率。 二、故障现象 1. 所有员工的电脑…...
JavaSE:9、数组
1、一维数组 初始化 import com.test.*;public class Main {public static void main(String [] argv){int a[]{1,2};int b[]new int[]{1,0,2};// int b[]new int[3]{1,2,3}; ERROR 要么指定长度要么大括号里初始化数据算长度int[] c{1,2};int d[]new int[10];} }基本类型…...

【裸机装机系列】2.kali(ubuntu)-裸机安装kali并进行磁盘分区-2024.9最新
【前言】 2024年为什么弃用ubuntu,请参考我写的另一篇博文:为什么不用ubuntu,而选择基于debian的kali操作系统-2024.9最新 【镜像下载】 1、镜像下载地址 https://www.kali.org/get-kali/选择installer-image,进入界面下载相应的ISO文件 我…...

解决:Vue 中 debugger 不生效
目录 1,问题2,解决2.1,修改 webpack 配置2.2,修改浏览器设置 1,问题 在 Vue 项目中,可以使用 debugger 在浏览器中开启调试。但有时却不生效。 2,解决 2.1,修改 webpack 配置 通…...

Mac笔记本上查看/user/目录下的文件的几种方法
在Mac笔记本上查看/user/下的文件,可以通过多种方法实现。以下是一些常见的方法: 一、使用Finder 打开Finder:点击Dock栏中的Finder图标,或者使用快捷键Command F。 导航到用户目录: 在Finder的菜单栏中࿰…...
工程师 - ACPI和ACPICA的区别
ACPI(高级配置和电源接口)和 ACPICA(ACPI 组件架构)密切相关,但在系统电源管理和配置方面却有不同的作用。以下是它们的区别: ACPI(高级配置和电源接口) - 定义: ACPI 是…...
一文快速上手-create-vue脚手架
文章目录 初识 create-vuecreate-vue新建项目Vue.js 3 项目目录结构项目的运行和打包vite.config.js文件解析其他:webpack和Vite的区别 初识 create-vue create-vue类似于Vue CLI脚手架,可以快速创建vuejs 3项目,create-vue基于Vite。Vite支…...
笔记整理—内核!启动!—kernel部分(7)rcs文件和登录部分与密码解析
该文件的位置在/etc/init.d/rcs,前文说过这个是一个配置文件,最开始的地方首先就是PATH相关的用export导出相关的PATH做环境变量,将可执行路径导为PATH执行时就不用写全路径了,该位置的PATH路径导出了/bin、/sbin、/usr/bin、/usr…...
朴素贝叶斯 (Naive Bayes)
朴素贝叶斯 (Naive Bayes) 通俗易懂算法 朴素贝叶斯(Naive Bayes)是一种基于概率统计的分类算法。它的核心思想是通过特征的条件独立性假设来简化计算复杂度,将复杂的联合概率分布分解为特征的独立概率分布之积。 基本思想 朴素贝叶斯基于…...

手机照片太多了存哪里?
手机相册里塞满了旅行照片、生活碎片,每次清理都舍不得删?NAS——一款超实用的存储方案,让你的回忆安全又有序~ 1️⃣自动备份解放双手 手机 / 电脑 / 相机照片全自动同步到 NAS,再也不用手动传文件 2️⃣远程访问像…...

详解鸿蒙仓颉开发语言中的计时器
今天又到了大家喜闻乐见的科普环节,也可以说是踩坑环节,哈哈哈。今天聊一聊仓颉开发语言中的计时器,这部分可老有意思了。 为什么这么说呢,因为关于仓颉的计时器你几乎搜不到任何的文档,也没有相关的代码提示…...

基于大数据的个性化购房推荐系统设计与实现(源码+定制+开发)面向房产电商的智能购房推荐与数据可视化系统 基于Spark与Hive的房源数据挖掘与推荐系统设计
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
stm与51单片机哪个更适合新手学
一句话总结 51单片机:像学骑自行车,简单便宜,但只能在小路上骑。 STM32:像学开汽车,复杂但功能强,能上高速公路,还能拉货载人(做复杂项目)。 1. 为啥有人说“先学51单片…...

HTML实现端午节主题网站:龙舟争渡,凭吊祭江诵君赋。
名人说:龙舟争渡,助威呐喊,凭吊祭江诵君赋。——苏轼《六幺令天中节》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、项目概览:传统与现代的技术碰撞1. 核心特…...
websocket在vue中的使用步骤,以及实现聊天
一、WebSocket集成步骤 连接初始化 在Vue组件中创建WebSocket实例,建议在mounted生命周期中执行: data() {return {socket: null,messages: []} }, mounted() {this.socket new WebSocket(wss://your-server-endpoint); }事件监听配置 连接成…...
基于随机函数链接神经网络(RVFL)的锂电池健康状态(SOH)预测
基于随机函数链接神经网络(RVFL)的锂电池健康状态(SOH)预测 一、RVFL网络的基本原理与结构 随机向量功能链接(Random Vector Functional Link, RVFL)网络是一种单隐藏层前馈神经网络的随机化版本,其核心特征在于输入层到隐藏层的权重随机生成且固定,输出层权重通过最…...

前端基础学习html+css+js
HTML 区块 div标签,块级标签 span包装小部分文本,行内元素 表单 CSS css选择器 css属性 特性blockinlineinline-block是否换行✅ 换行❌ 不换行❌ 不换行可设置宽高✅ 支持❌ 不支持✅ 支持常见元素div容器 p段落 h标题span文本容器 a超链接img图片…...

Microsoft Fabric - 尝试一下Data Factory一些新的特性(2025年5月)
1.简单介绍 Microsoft Fabric是微软提供的一个数据管理和分析的统一平台,感觉最近的新特性也挺多的。 Data Factory是Microsoft Fabric的一个功能模块,也是一个cloud service。Data Factory可以和多种数据源进行连接,同时提供了data movemen…...

C# NX二次开发-查找连续倒圆角面
在QQ群里有人问怎么通过一个选择一个倒圆角面来自动选中一组倒圆角面。 可以通过ufun函数 UF_MODL_ask_face_type 和 UF_MODL_ask_face_props 可判断处理选择相应的一组圆角面。 代码: Tag[] 查找连续倒圆角面(Tag faceTag) {theUf.Modl.AskFaceType(faceTag, out int typ…...