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

C# Unity FSM 状态机

C# Unity FSM 状态机

使用状态机可以降低代码耦合性,并且可以优化代码可读性,方便团队协作等。
对于游戏开发内容来讲游戏开发的流程控制玩家动画都可以使用FSM有限状态机来实现。

1.FsmState

每个状态的基类,泛型参数表示所拥有者

public abstract class FsmState<T> where T : class
{protected internal abstract void OnInit(IFsm<T> fsm);protected internal abstract void OnEnter(IFsm<T> fsm);protected internal abstract void OnUpdate(IFsm<T> fsm);protected internal abstract void OnLeave(IFsm<T> fsm);protected internal abstract void OnDestroy(IFsm<T> fsm);protected void ChangeState<TState>(IFsm<T> fsm) where TState : FsmState<T>{Fsm<T> fsmImplement = (Fsm<T>)fsm;if(fsmImplement == null){throw new Exception("FSM is invalid.");}fsmImplement.ChangeState<TState>();}protected void ChangeState(IFsm<T> fsm, Type stateType){Fsm<T> fsmImplement = (Fsm<T>)fsm;if (fsmImplement == null){throw new Exception("FSM is invalid.");}if (stateType == null){throw new Exception("State type is invalid.");}if (!typeof(FsmState<T>).IsAssignableFrom(stateType)){throw new Exception("State type is invalid.");}fsmImplement.ChangeState(stateType);}
}

2.IFsm

有限状态机的接口

public interface IFsm<T> where T : class
{string Name{get;}string FullName{get;}T Owner{get;}int FsmStateCount{get;}bool IsRunning{get;}bool IsDestroyed{get;}FsmState<T> CurrentState{get;}float CurrentStateTime{get;}void Start<TState>() where TState : FsmState<T>;bool HasState<TState>() where TState : FsmState<T>;TState GetState<TState>() where TState : FsmState<T>;FsmState<T> GetState(Type stateType);FsmState<T>[] GetAllStates();
}

3.IFsmManager

有限状态机管理器接口

public interface IFsmManager
{int Count { get; }bool HasFsm<T>() where T : class;bool HasFsm(Type ownerType);bool HasFsm<T>(string name) where T : class;bool HasFsm(Type ownerType, string name);IFsm<T> GetFsm<T>() where T : class;IFsm<T> GetFsm<T>(string name) where T : class;IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] fsmStates) where T : class;IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class;IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class;IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class;bool DestroyFsm<T>() where T : class;bool DestroyFsm(Type ownerType);bool DestroyFsm<T>(string name) where T : class;bool DestroyFsm(Type ownerType, string name);bool DestroyFsm<T>(IFsm<T> fsm) where T : class;
}

4.FsmBase

有限状态机的基类

public abstract class FsmBase
{private string m_Name;public FsmBase(){m_Name = string.Empty;}public string Name{get{return m_Name;}protected set{m_Name = value ?? string.Empty;}}public string FullName{get{return $"{OwnerType.FullName}.{Name}";}}public abstract Type OwnerType{get;}public abstract int FsmStateCount{get;}public abstract bool IsRunning{get;}public abstract bool IsDestroyed{get;}public abstract string CurrentStateName{get;}public abstract float CurrentStateTime{get;}public abstract void Update();public abstract void Shutdown();
}

5.Fsm

状态机类

public class Fsm<T> : FsmBase, IFsm<T> where T : class
{private T m_Owner;private readonly Dictionary<Type, FsmState<T>> m_States;private FsmState<T> m_CurrentState;private float m_CurrentStateTime;private bool m_IsDestroyed;public Fsm(){m_Owner = null;m_States = new Dictionary<Type, FsmState<T>>();m_CurrentState = null;m_CurrentStateTime = 0f;m_IsDestroyed = true;}public T Owner => m_Owner;public FsmState<T> CurrentState => m_CurrentState;public override Type OwnerType => typeof(T);public override int FsmStateCount => m_States.Count;public override bool IsRunning => m_CurrentState != null;public override bool IsDestroyed => m_IsDestroyed;public override string CurrentStateName => m_CurrentState != null ? m_CurrentState.GetType().FullName : null;public override float CurrentStateTime => m_CurrentStateTime;public static Fsm<T> Create(string name,T owner,params FsmState<T>[] states){if(owner == null){throw new Exception("FSM owner is invalid.");}if(states== null|| states.Length < 1){throw new Exception("FSM states is invalid.");}Fsm<T> fsm = Pool<Fsm<T>>.Rent();fsm.Name = name;fsm.m_Owner = owner;fsm.m_IsDestroyed = false;foreach (FsmState<T> oneState in states){if(oneState == null){throw new Exception("FSM states is invalid.");}Type stateType = oneState.GetType();if (fsm.m_States.ContainsKey(stateType)){throw new Exception($"{stateType} state is already exist");}fsm.m_States.Add(stateType, oneState);oneState.OnInit(fsm);}return fsm;}public static Fsm<T> Create(string name,T owner,List<FsmState<T>> states){if (owner == null){throw new Exception("FSM owner is invalid.");}if (states == null || states.Count < 1){throw new Exception("FSM states is invalid.");}Fsm<T> fsm = Pool<Fsm<T>>.Rent();fsm.Name = name;fsm.m_Owner = owner;fsm.m_IsDestroyed = false;foreach (FsmState<T> oneState in states){if (oneState == null){throw new Exception("FSM states is invalid.");}Type stateType = oneState.GetType();if (fsm.m_States.ContainsKey(stateType)){throw new Exception($"{stateType} state is already exist");}fsm.m_States.Add(stateType, oneState);oneState.OnInit(fsm);}return fsm;}public FsmState<T>[] GetAllStates(){int index = 0;FsmState<T>[] arr = new FsmState<T>[m_States.Count];foreach (FsmState<T> fsmState in m_States.Values){arr[index++] = fsmState;}return arr;}public bool HasState<TState>() where TState : FsmState<T>{return m_States.ContainsKey(typeof(TState));}public override void Shutdown(){Pool<Fsm<T>>.Return(this, (fsm) =>{if(m_CurrentState != null){m_CurrentState.OnLeave(this);}foreach (FsmState<T> oneState in m_States.Values){oneState.OnDestroy(this);}Name = null;m_Owner = null;m_States.Clear();m_CurrentState = null;m_CurrentStateTime = 0f;m_IsDestroyed = true;});}public void Start<TState>() where TState : FsmState<T>{if (IsRunning){throw new Exception("FSM is running, can not start again.");}FsmState<T> state = GetState<TState>();if (state == null){throw new Exception("can not start state");}m_CurrentStateTime = 0f;m_CurrentState = state;m_CurrentState.OnEnter(this);}public void Start(Type stateType){if (IsRunning){throw new Exception("FSM is running, can not start again.");}if (stateType == null){throw new Exception("State type is invalid.");}if (!typeof(FsmState<T>).IsAssignableFrom(stateType)){throw new Exception("State type is invalid.");}FsmState<T> state = GetState(stateType);if (state == null){throw new Exception("FSM can not start state which is not exist.");}m_CurrentStateTime = 0f;m_CurrentState = state;m_CurrentState.OnEnter(this);}public override void Update(){m_CurrentStateTime += Time.deltaTime;m_CurrentState.OnUpdate(this);}public TState GetState<TState>() where TState : FsmState<T>{if (m_States.TryGetValue(typeof(TState), out FsmState<T> fsmState)){return (TState)fsmState;}return null;}public FsmState<T> GetState(Type stateType){if (stateType == null){throw new Exception("State type is invalid.");}if (!typeof(FsmState<T>).IsAssignableFrom(stateType)){throw new Exception("State type is invalid.");}if (m_States.TryGetValue(stateType, out FsmState<T> fsmState)){return fsmState;}return null;}public void ChangeState<TState>(){ChangeState(typeof(TState));}public void ChangeState(Type stateType){if (m_CurrentState == null){throw new Exception("Current state is invalid.");}FsmState<T> state = GetState(stateType);if (state == null){throw new Exception("FSM can not change state which is not exist.");}m_CurrentState.OnLeave(this);m_CurrentStateTime = 0f;m_CurrentState = state;m_CurrentState.OnEnter(this);}
}

6.FsmManager

状态机管理器

public class FsmManager : Singleton<FsmManager>,IFsmManager,IUpdateSingleton
{private readonly Dictionary<string, FsmBase> m_FsmDic;private readonly List<FsmBase> m_TempFsms;public FsmManager(){m_FsmDic = new Dictionary<string, FsmBase>();m_TempFsms = new List<FsmBase>();}public int Count => m_FsmDic.Count;public IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] fsmStates) where T : class{return CreateFsm(string.Empty, owner, fsmStates);}public IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class{if (HasFsm<T>(name)){throw new Exception("Already exist FSM");}Fsm<T> fsm = Fsm<T>.Create(name, owner, states);m_FsmDic.Add(fsm.FullName, fsm);return fsm;}public IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class{return CreateFsm(string.Empty, owner, states);}public IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class{if (HasFsm<T>(name)){throw new Exception("Already exist FSM");}Fsm<T> fsm = Fsm<T>.Create(name, owner, states);m_FsmDic.Add(fsm.FullName, fsm);return fsm;}public bool DestroyFsm<T>() where T : class{return InternalDestroyFsm($"{typeof(T).FullName}.{string.Empty}");}public bool DestroyFsm(Type ownerType){if (ownerType == null){throw new Exception("Owner type is invalid.");}return InternalDestroyFsm($"{ownerType.FullName}.{string.Empty}");}public bool DestroyFsm<T>(string name) where T : class{return InternalDestroyFsm($"{typeof(T).FullName}.{name}");}public bool DestroyFsm(Type ownerType, string name){if (ownerType == null){throw new Exception("Owner type is invalid.");}return InternalDestroyFsm($"{ownerType.FullName}.{name}");}public bool DestroyFsm<T>(IFsm<T> fsm) where T : class{if (fsm == null){throw new Exception("FSM is invalid.");}return InternalDestroyFsm(fsm.FullName);}public IFsm<T> GetFsm<T>() where T : class{return (IFsm<T>)InternalGetFsm($"{typeof(T).FullName}.{string.Empty}");}public IFsm<T> GetFsm<T>(string name) where T : class{return (IFsm<T>)InternalGetFsm($"{typeof(T).FullName}.{name}");}public bool HasFsm<T>() where T : class{return InternalHasFsm($"{typeof(T).FullName}.{string.Empty}");}public bool HasFsm(Type ownerType){if(ownerType == null){throw new Exception("Owner type is invalid.");}return InternalHasFsm($"{ownerType.FullName}.{string.Empty}");}public bool HasFsm<T>(string name) where T : class{return InternalHasFsm($"{typeof(T).FullName}.{name}");}public bool HasFsm(Type ownerType, string name){if (ownerType == null){throw new Exception("Owner type is invalid.");}return InternalHasFsm($"{ownerType.FullName}.{name}");}private bool InternalDestroyFsm(string name){if(m_FsmDic.TryGetValue(name,out FsmBase fsmBase)){fsmBase.Shutdown();return m_FsmDic.Remove(name);}return false;}private FsmBase InternalGetFsm(string name){FsmBase fsm = null;if (m_FsmDic.TryGetValue(name, out fsm)){return fsm;}return null;}private bool InternalHasFsm(string name){return m_FsmDic.ContainsKey(name);}public void Update(){m_TempFsms.Clear();if (m_FsmDic.Count <= 0)return;foreach (FsmBase fsmBase in m_FsmDic.Values){m_TempFsms.Add(fsmBase);}foreach (FsmBase fsmBase in m_TempFsms){if (fsmBase.IsDestroyed)continue;fsmBase.Update();}}protected override void Load(int assemblyName){}protected override void UnLoad(int assemblyName){}
}

7.测试

(一)IdleState

public class IdleState : FsmState<FsmTest>
{protected internal override void OnDestroy(IFsm<FsmTest> fsm){Debug.Log("销毁 IdleState");}protected internal override void OnEnter(IFsm<FsmTest> fsm){Debug.Log("进入 IdleState");}protected internal override void OnInit(IFsm<FsmTest> fsm){}protected internal override void OnLeave(IFsm<FsmTest> fsm){Debug.Log("离开 IdleState");}protected internal override void OnUpdate(IFsm<FsmTest> fsm){if (Input.GetKeyDown(KeyCode.A)){ChangeState<WalkState>(fsm);}}
}

(二)WalkState

public class WalkState : FsmState<FsmTest>
{protected internal override void OnDestroy(IFsm<FsmTest> fsm){Debug.Log("销毁 WalkState");}protected internal override void OnEnter(IFsm<FsmTest> fsm){Debug.Log("进入 WalkState");}protected internal override void OnInit(IFsm<FsmTest> fsm){}protected internal override void OnLeave(IFsm<FsmTest> fsm){Debug.Log("离开 WalkState");}protected internal override void OnUpdate(IFsm<FsmTest> fsm){if (Input.GetKeyDown(KeyCode.B)){ChangeState<RunState>(fsm);}}
}

(三)RunState

public class RunState : FsmState<FsmTest>
{protected internal override void OnDestroy(IFsm<FsmTest> fsm){Debug.Log("销毁 RunState");}protected internal override void OnEnter(IFsm<FsmTest> fsm){Debug.Log("进入 RunState");}protected internal override void OnInit(IFsm<FsmTest> fsm){}protected internal override void OnLeave(IFsm<FsmTest> fsm){Debug.Log("离开 RunState");}protected internal override void OnUpdate(IFsm<FsmTest> fsm){if (Input.GetKeyDown(KeyCode.C)){ChangeState<IdleState>(fsm);}}
}

mono测试

public class FsmTest : MonoBehaviour
{private IFsm<FsmTest> m_TestFsm;void Start(){SingletonSystem.Initialize();AssemblyManager.Load(1, GetType().Assembly);m_TestFsm = FsmManager.Instance.CreateFsm<FsmTest>("MyTestFsm",this, new IdleState(),new WalkState(),new RunState());m_TestFsm.Start<IdleState>();}void Update(){SingletonSystem.Update();if (Input.GetKeyDown(KeyCode.P)){FsmManager.Instance.DestroyFsm(m_TestFsm);}}
}

相关文章:

C# Unity FSM 状态机

C# Unity FSM 状态机 使用状态机可以降低代码耦合性&#xff0c;并且可以优化代码可读性&#xff0c;方便团队协作等。 对于游戏开发内容来讲游戏开发的流程控制玩家动画都可以使用FSM有限状态机来实现。 1.FsmState 每个状态的基类&#xff0c;泛型参数表示所拥有者 publi…...

pytorch搭建squeezenet网络的整套工程,及其转tensorrt进行cuda加速

本来&#xff0c;前辈们用caffe搭建了一个squeezenet的工程&#xff0c;用起来也还行&#xff0c;但考虑到caffe的停更后续转trt应用在工程上时可能会有版本的问题所以搭建了一个pytorch版本的。 以下的环境搭建不再细说&#xff0c;主要就是pyorch&#xff0c;其余的需要什么p…...

【精读Uboot】SPL阶段的board_init_r详细分析

对于i.MX平台上的SPL来说&#xff0c;其不会直接跳转到Uboot&#xff0c;而是在SPL阶段借助BOOTROM跳转到ATF&#xff0c;然后再通过ATF跳转到Uboot。 board_init_f会初始化设备相关的硬件&#xff0c;最后进入board_init_r为镜像跳转做准备。下面是board_init_r调用的核心函数…...

canvas绘制渐变色三角形金字塔

项目需求:需要绘制渐变色三角形金字塔,并用折线添加标识 (其实所有直接用图片放上去也行,但是ui没切图,我也懒得找她要,正好也没啥事,直接自己用代码绘制算了,总结一句就是闲的) 最终效果如下图: (以上没用任何图片,都是代码绘制的) 在网上找了,有用canvas绘…...

企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图

功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外部供…...

Debain JDK8 安装

Debain JDK8 安装 首先请安装依赖&#xff1a; sudo apt-get update && sudo apt-get install -y wget apt-transport-https然后信任 GPG 公钥&#xff1a; wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | sudo tee /etc/apt/keyrings/…...

Python序列操作指南:列表、字符串和元组的基本用法和操作

文章目录 序列列表创建列表访问元素修改元素添加和删除元素 range()字符串创建字符串访问字符字符串切片修改字符串 元组创建元组访问元素获取元素数量元组的特点&#xff1a; 可变对象改变对象的值改变变量的指向比较运算符总结 python精品专栏推荐python基础知识&#xff08;…...

【已更新代码图表】2023数学建模国赛E题python代码--黄河水沙监测数据分析

E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变 化和人民生活的影响&#xff0c;以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾 等方面都具有重要的理论指导意义。 附件 1 给出了位于小浪底水…...

【前端】CSS-Grid网格布局

目录 一、grid布局是什么二、grid布局的属性三、容器属性1、display①、语句②、属性值 2、grid-template-columns属性、grid-template-rows属性①、定义②、属性值1&#xff09;、固定的列宽和行高2&#xff09;、repeat()函数3&#xff09;、auto-fill关键字4&#xff09;、f…...

计算机竞赛 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…...

2023-9-8 求组合数(二)

题目链接&#xff1a;求组合数 II #include <iostream> #include <algorithm>using namespace std;typedef long long LL; const int mod 1e9 7; const int N 100010;// 阶乘&#xff0c;阶乘的逆 int fact[N], infact[N];LL qmi(int a, int k, int p) {int res…...

k8s service的一些特性

文章目录 Service分发负载的策略同一端口通过不同协议暴露Headless Service的负载分发策略 Service分发负载的策略 大家都知道&#xff0c;一个service可以对应多个pod&#xff0c;那么一定要有一些方法来把service接收到的请求&#xff08;负载&#xff09;转发到pod上。 一般…...

C++中std::enable_if和SFINAE介绍

作为一个标准的C++模板类,我们先看下enable_if的定义: // STRUCT TEMPLATE enable_if template <bool _Test, class _Ty = void> struct enable_if {}; // no member "type" when !_Testtemplate <class _Ty> struct enable_if<true, _Ty> { //…...

华为OD机考算法题:数字加减游戏

目录 题目部分 解读与分析 代码实现 题目部分 题目数字加减游戏难度难题目说明小明在玩一个数字加减游戏&#xff0c;只使用加法或者减法&#xff0c;将一个数字 s 变成数字 t 。 每个回合&#xff0c;小明可以用当前的数字加上或减去一个数字。 现在有两种数字可以用来加减…...

WPF命令

在设计良好的Windows应用程序中&#xff0c;应用程序逻辑不应位于事件处理程序中&#xff0c;而应在更高层的方法中编写代码。其中的每个方法都代表单独的应用程序任务。每个任务可能依赖其他库。 使用这种设计最明显的方式是在需要的地方添加事件处理程序&#xff0c;并使用各…...

Unity中Shader的屏幕抓取 GrabPass

文章目录 前言一、抓取1、抓取指令2、在使用抓取的屏幕前&#xff0c;需要像使用属性一样定义一下,_GrabTexture这个名字是Unity定义好的 前言 Unity中Shader的屏幕抓取 GrabPass 一、抓取 1、抓取指令 屏幕的抓取需要使用一个Pass GrabPass{} GrabPass{“NAME”} 2、在使用…...

手撕 队列

队列的基本概念 只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 入队列&#xff1a;进行插入操作的一端称为队尾 出队列&#xff1a;进行删除操作的一端称为队头 队列用链表实现 队列的实现 队列的定义 队列…...

【autodl/linux配环境心得:conda/本地配cuda,cudnn及pytorch心得】-未完成

linux配环境心得&#xff1a;conda/本地配cuda&#xff0c;cudnn及pytorch心得 我们服务器遇到的大多数找不到包的问题一&#xff0c;服务器安装cuda和cudnn使用conda在线安装cuda和cudnn使用conda进行本地安装检查conda安装的cuda和cudnn本地直接安装cuda和cudnn方法一&#x…...

macOS Ventura 13.5.2(22G91)发布,附黑/白苹果镜像下载地址

系统介绍&#xff08;下载请百度搜索&#xff1a;黑果魏叔&#xff09; 黑果魏叔 9 月 8 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5.2 更新&#xff08;内部版本号&#xff1a;22G91&#xff09;&#xff0c;本次更新距离上次发布隔了 21 天。 本次更新查…...

vue 子组件向父组件传递参数 子传父

子组件中写&#xff1a; this.$emit(RowCount,res.data.RowCount); 父组件中写&#xff1a; getMFGLRowCount(val){ //父组件中的方法: 接收子组件传过来的参数值赋值给父组件的变量 //this.totalCount val; alert("这…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

深入解析光敏传感技术:嵌入式仿真平台如何重塑电子工程教学

一、光敏传感技术的物理本质与系统级实现挑战 光敏电阻作为经典的光电传感器件&#xff0c;其工作原理根植于半导体材料的光电导效应。当入射光子能量超过材料带隙宽度时&#xff0c;价带电子受激发跃迁至导带&#xff0c;形成电子-空穴对&#xff0c;导致材料电导率显著提升。…...