当前位置: 首页 > news >正文

『功能项目』怪物的有限状态机【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)icon-default.png?t=O83Ahttps://www.bilibili.com/video/BV1rZY4e9Ebs/?spm_id_from=333.999.0.0&vd_source=547091a95b03acfa8e8a9e46ef499cd6

相关文章:

『功能项目』怪物的有限状态机【42】

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

【C++】模板进阶:深入解析模板特化

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

Python数据分析-世界上最富有的1000人

一、研究背景 随着全球化的加速发展和技术的进步&#xff0c;财富分配问题日益成为全球关注的焦点。财富的不平等现象日益明显&#xff0c;少数极富有的个人掌握了全球大部分的财富资源。了解全球最富有个人的财富分布及其背后的行业和国家因素&#xff0c;对于分析全球经济趋…...

CSS中隐藏滚动条的同时保留滚动功能

在CSS中&#xff0c;我们可以通过一些技巧来隐藏滚动条&#xff0c;同时保留滚动功能。以下是几种常用的方法和具体的实现步骤。 1. 使用 overflow 和 ::-webkit-scrollbar 这种方法适用于大多数现代浏览器。通过设置 overflow 属性启用滚动&#xff0c;同时利用 ::-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设备通常包括头戴式显示器&#xff08;VR头盔&#xff09;、手柄或追踪器等组件&#xff0c;用以完全封闭用户视野&#xff0c;营造虚拟环境体验。这些设备配备高分辨率显示屏、内置传感器和跟踪器。 …...

DAY14信息打点-JS 架构框架识别泄漏提取API 接口枚举FUZZ 爬虫插件项目

本课意义&#xff1a; 1.如何从表现中的JS提取价值信息 2.如何从地址中FUZZ提取未知的JS文件 3.如何从JS开放框架WebPack进行测试 一、JS 前端架构-识别&分析 在JS中寻找更多的URL地址&#xff0c;在JS代码逻辑&#xff08;加密算法、APIKey配置、验证逻辑&#xff09;中进…...

TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错

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

revisiting拉普拉斯模板

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

深入分析计算机网络性能指标

速率带宽吞吐量时延时延带宽积往返时间RTT利用率丢包率图书推荐内容简介作者简介 速率 连接在计算机网络上的主机在数字信道上传送比特的速率&#xff0c;也称为比特率或数据率。 基本单位&#xff1a;bit/s&#xff08;b/s、bps&#xff09; 常用单位&#xff1a;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…...

《网络故障处理案例:公司网络突然中断》

网络故障处理案例&#xff1a;公司网络突然中断 一、故障背景 某工作日上午&#xff0c;一家拥有 500 名员工的公司突然出现整个网络中断的情况。员工们无法访问互联网、内部服务器和共享文件&#xff0c;严重影响了工作效率。 二、故障现象 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,请参考我写的另一篇博文&#xff1a;为什么不用ubuntu&#xff0c;而选择基于debian的kali操作系统-2024.9最新 【镜像下载】 1、镜像下载地址 https://www.kali.org/get-kali/选择installer-image&#xff0c;进入界面下载相应的ISO文件 我…...

解决:Vue 中 debugger 不生效

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

Mac笔记本上查看/user/目录下的文件的几种方法

在Mac笔记本上查看/user/下的文件&#xff0c;可以通过多种方法实现。以下是一些常见的方法&#xff1a; 一、使用Finder 打开Finder&#xff1a;点击Dock栏中的Finder图标&#xff0c;或者使用快捷键Command F。 导航到用户目录&#xff1a; 在Finder的菜单栏中&#xff0…...

工程师 - ACPI和ACPICA的区别

ACPI&#xff08;高级配置和电源接口&#xff09;和 ACPICA&#xff08;ACPI 组件架构&#xff09;密切相关&#xff0c;但在系统电源管理和配置方面却有不同的作用。以下是它们的区别&#xff1a; ACPI&#xff08;高级配置和电源接口&#xff09; - 定义&#xff1a; ACPI 是…...

一文快速上手-create-vue脚手架

文章目录 初识 create-vuecreate-vue新建项目Vue.js 3 项目目录结构项目的运行和打包vite.config.js文件解析其他&#xff1a;webpack和Vite的区别 初识 create-vue create-vue类似于Vue CLI脚手架&#xff0c;可以快速创建vuejs 3项目&#xff0c;create-vue基于Vite。Vite支…...

笔记整理—内核!启动!—kernel部分(7)rcs文件和登录部分与密码解析

该文件的位置在/etc/init.d/rcs&#xff0c;前文说过这个是一个配置文件&#xff0c;最开始的地方首先就是PATH相关的用export导出相关的PATH做环境变量&#xff0c;将可执行路径导为PATH执行时就不用写全路径了&#xff0c;该位置的PATH路径导出了/bin、/sbin、/usr/bin、/usr…...

朴素贝叶斯 (Naive Bayes)

朴素贝叶斯 (Naive Bayes) 通俗易懂算法 朴素贝叶斯&#xff08;Naive Bayes&#xff09;是一种基于概率统计的分类算法。它的核心思想是通过特征的条件独立性假设来简化计算复杂度&#xff0c;将复杂的联合概率分布分解为特征的独立概率分布之积。 基本思想 朴素贝叶斯基于…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...