Unity 桥接模式(实例详解)
文章目录
- 示例1:角色与装备系统
- 示例2:UI控件库
- 示例3:渲染引擎模块
- 示例4:AI决策树算法
- 示例5:物理模拟引擎
在Unity游戏开发中,桥接模式(Bridge Pattern)是一种设计模式,它用于将抽象部分与其实现部分分离,从而允许它们独立变化。这种模式适用于以下场景:
- 当一个类有多个维度的变化,并且希望这些变化可以独立扩展而不影响彼此时。
- 如果直接使用继承来处理多维度变化会导致类爆炸问题,即需要创建大量子类。
桥接模式的组成部分:
- 抽象(Abstraction):定义了抽象接口,并包含对实现部分(Implementor)的操作。在Unity中,这可能是某个基础组件或接口,它提供了通用的功能描述,但不关心具体的实现细节。
例如:
public interface ICharacterControl
{void Move();void Attack();void SetWeapon(IWeapon weapon);
}public interface IWeapon
{void Fire();void Reload();
}
- 提炼的抽象(Refined Abstraction):继承自抽象类的具体角色,它可能会添加更多特定的行为,同时调用实现部分的方法。
public class Soldier : MonoBehaviour, ICharacterControl
{private IWeapon _currentWeapon;public void Move(){// 实现移动逻辑}public void Attack(){if (_currentWeapon != null)_currentWeapon.Fire();}public void SetWeapon(IWeapon weapon){_currentWeapon = weapon;}
}
- 实现(Implementor):定义了实现接口,这个接口通常代表了可变的部分,如不同的武器类型。
public abstract class WeaponBase : IWeapon
{public abstract void Fire();public abstract void Reload();
}public class Pistol : WeaponBase
{public override void Fire(){Debug.Log("Pistol fires!");}public override void Reload(){Debug.Log("Pistol is reloading...");}
}public class Shotgun : WeaponBase
{public override void Fire(){Debug.Log("Shotgun fires!");}public override void Reload(){Debug.Log("Shotgun is reloading...");}
}
五个实例说明:
-
角色和装备系统:游戏角色可以有不同的移动方式(跑、走、跳等)以及不同的武器(枪、剑、魔法等),通过桥接模式可以使角色类型和武器类型相互独立地扩展。
-
渲染引擎模块:抽象层为渲染器接口,具体实现包括不同的渲染技术(如Direct3D、OpenGL、Vulkan等)。不论游戏采用哪种渲染技术,上层的游戏对象渲染逻辑保持不变。
-
UI控件库:抽象层定义了一系列UI控件(按钮、文本框、滑块等)的公共行为,而具体实现可能基于不同的图形API或框架(Unity UI、NGUI、TextMeshPro等)。
-
AI决策树算法:抽象层是决策树接口,不同类型的AI实体可以根据需求选择不同的决策树实现(简单状态机、有限状态机、蒙特卡洛搜索树等)。
-
物理模拟引擎:抽象层提供物理模拟功能,如碰撞检测、刚体运动等,而具体实现可以切换为不同的物理引擎(Unity内置物理引擎、PhysX、Box2D等)。
以下是在Unity中应用桥接模式的五个不同场景的简化代码示例:
示例1:角色与装备系统
// 抽象部分 - 角色接口
public interface ICharacter
{void Move();void ChangeWeapon(IWeapon weapon);
}// 实现部分 - 武器接口
public interface IWeapon
{void Use();void Reload();
}// 具体抽象 - 战士类,继承自ICharacter
public class Warrior : MonoBehaviour, ICharacter
{private IWeapon currentWeapon;public void Move(){// 移动逻辑}public void ChangeWeapon(IWeapon weapon){currentWeapon = weapon;}public void Attack(){if (currentWeapon != null)currentWeapon.Use();}
}// 实现部分的具体类 - 短剑和长弓
public class ShortSword : IWeapon
{public void Use(){Debug.Log("Short sword is used for attack!");}public void Reload(){// 无需重新加载}
}public class LongBow : IWeapon
{public void Use(){Debug.Log("Long bow fires an arrow!");}public void Reload(){Debug.Log("Reloading the long bow...");}
}// 在游戏运行时切换武器
var warrior = GetComponent<Warrior>();
warrior.ChangeWeapon(new ShortSword());
warrior.Attack(); // 输出:"Short sword is used for attack!"
warrior.ChangeWeapon(new LongBow());
warrior.Attack(); // 输出:"Long bow fires an arrow!"
示例2:UI控件库
// 抽象部分 - UI控件接口
public interface IUIControl
{void Render();void SetText(string text);
}// 实现部分 - 不同UI框架下的文本框实现
public abstract class TextControlBase : IUIControl
{public abstract void Render();public abstract void SetText(string text);
}public class UnityUITextControl : TextControlBase
{public UnityEngine.UI.Text unityText; // Unity UI组件public override void Render(){// 使用Unity UI渲染文本}public override void SetText(string text){unityText.text = text;}
}public class NGUITextControl : TextControlBase
{// 假设NGUI有对应的文本组件引用public override void Render(){// 使用NGUI渲染文本}public override void SetText(string text){// 设置NGUI文本内容}
}// 在游戏运行时创建不同的UI文本框实例
var uiText = new UnityUITextControl();
uiText.SetText("Hello from Unity UI");
uiText.Render();var nguiText = new NGUITextControl();
nguiText.SetText("Hello from NGUI");
nguiText.Render();
示例3:渲染引擎模块
// 抽象部分 - 渲染器接口
public interface IRenderer
{void RenderScene(GameObject scene);
}// 实现部分 - 不同的渲染引擎实现
public class DirectXRenderer : IRenderer
{public void RenderScene(GameObject scene){// 使用DirectX渲染场景Debug.Log("Rendering scene with DirectX...");}
}public class OpenGLRenderer : IRenderer
{public void RenderScene(GameObject scene){// 使用OpenGL渲染场景Debug.Log("Rendering scene with OpenGL...");}
}// 游戏中的场景管理器调用渲染逻辑
public class SceneManager
{private IRenderer _renderer;public SceneManager(IRenderer renderer){_renderer = renderer;}public void RenderCurrentScene(){_renderer.RenderScene(currentScene);}
}// 在游戏启动时根据需要选择渲染引擎
var directXRenderer = new DirectXRenderer();
var sceneManager = new SceneManager(directXRenderer);
sceneManager.RenderCurrentScene(); // 输出:"Rendering scene with DirectX..."// 如果需要切换到OpenGL,只需更改渲染器实例
var openGLRenderer = new OpenGLRenderer();
sceneManager._renderer = openGLRenderer;
sceneManager.RenderCurrentScene(); // 输出:"Rendering scene with OpenGL..."
示例4:AI决策树算法
// 抽象部分 - 决策树接口
public interface IDecisionTree
{Action Decide(AIState state);
}// 实现部分 - 简单状态机和有限状态机
public class SimpleStateMachine : IDecisionTree
{public Action Decide(AIState state){// 根据简单状态机决定动作Debug.Log($"Decided action based on Simple State Machine: {state}");return () => { /* 执行具体动作 */ };}
}public class FiniteStateMachine : IDecisionTree
{public Action Decide(AIState state){// 根据有限状态机决定动作Debug.Log($"Decided action based on Finite State Machine: {state}");return () => { /* 执行具体动作 */ };}
}// AI角色类使用决策树接口
public class AIBot
{private IDecisionTree _decisionTree;public AIBot(IDecisionTree decisionTree){_decisionTree = decisionTree;}public void TakeAction(AIState currentState){var action = _decisionTree.Decide(currentState);action?.Invoke();}
}// 在游戏运行时选择不同的决策树
var simpleBot = new AIBot(new SimpleStateMachine());
simpleBot.TakeAction(AIState.Idle);var fsmBot = new AIBot(new FiniteStateMachine());
fsmBot.TakeAction(AIState.Patrolling);
示例5:物理模拟引擎
// 抽象部分 - 物理引擎接口
public interface IPhysicsEngine
{void Simulate();Rigidbody CreateRigidbody(GameObject obj);
}// 实现部分 - Unity内置物理引擎和Box2D
public class UnityPhysicsEngine : IPhysicsEngine
{public void Simulate(){// 调用Unity内置物理引擎进行模拟Physics.Simulate(Time.fixedDeltaTime);}public Rigidbody CreateRigidbody(GameObject obj){return obj.AddComponent<Rigidbody>();}
}public class Box2DPhysicsEngine : IPhysicsEngine
{// 假设有一个用于与Box2D交互的封装类Box2DBodypublic void Simulate(){// 使用Box2D进行物理模拟// ...}public Rigidbody CreateRigidbody(GameObject obj){// 创建一个Box2D对应的刚体组件并附加到对象上// 返回Box2DBody的引用或包装对象return null; // 这里简化处理,实际需要实现创建Box2D刚体}
}// 游戏中的物理世界管理器使用物理引擎接口
public class PhysicsWorldManager
{private IPhysicsEngine _physicsEngine;public PhysicsWorldManager(IPhysicsEngine physicsEngine){_physicsEngine = physicsEngine;}public void UpdatePhysics(){_physicsEngine.Simulate();}public Rigidbody AddRigidbody(GameObject obj){return _physicsEngine.CreateRigidbody(obj);}
}// 在游戏启动时选择物理引擎
var unityPhysics = new UnityPhysicsEngine();
var physicsManager = new PhysicsWorldManager(unityPhysics);
// ...// 如果要切换到Box2D
var box2DPhysics = new Box2DPhysicsEngine();
physicsManager._physicsEngine = box2DPhysics;
python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)
50个开发必备的Python经典脚本(11-20)
50个开发必备的Python经典脚本(21-30)
50个开发必备的Python经典脚本(31-40)
50个开发必备的Python经典脚本(41-50)
————————————————
最后我们放松一下眼睛

相关文章:
Unity 桥接模式(实例详解)
文章目录 示例1:角色与装备系统示例2:UI控件库示例3:渲染引擎模块示例4:AI决策树算法示例5:物理模拟引擎 在Unity游戏开发中,桥接模式(Bridge Pattern)是一种设计模式,它…...
Xftp连接不上Linux虚拟机的原因解决方法
前言: 在当今数字化时代,远程连接到Linux虚拟机是许多开发者和系统管理员日常工作的一部分。然而,有时候,面对Xftp连接不上Linux虚拟机的问题,我们可能感到困惑和无措。这个看似小问题可能导致工作中断,因…...
代码随想录刷题笔记 DAY12 | 二叉树的理论基础 | 二叉树的三种递归遍历 | 二叉树的非递归遍历 | 二叉树的广度优先搜索
Day 12 01. 二叉树的理论基础 1.1 二叉树的种类 满二叉树:除了叶子节点以外,每个节点都有两个子节点,整个树是被完全填满的完全二叉树:除了底层以外,其他部分是满的,底部可以不是满的但是必须是从左到右连…...
Linux问题 apt-get install时 无法解析域名“cn.archive.ubuntu.com”
问题描述: 在安装程序时会出现无法解析域名的错误 解决办法: 1、编辑文件 sudo vim /etc/resolv.conf 2、在最后加上(按键 i 进入编辑模式) nameserver 8.8.8.8 3、保存退出(:wq)...
蓝桥--鸡哥的购物挑战OJ(4169)
题目: 思路: 暴力: 直接枚举所有得偶数区间,找最大值,n2超时 优化: 分类讨论,只要醉倒不重不漏得分类不出意外就能AC了 图中的选择方式很简单了,不做解释了。 AC代码(我的代码可…...
MySQL--删除数据表(6)
MySQL中删除数据表是非常容易操作的,但是你在进行删除表操作时要非常小心,因为执行删除命令后所有数据都会消失。 语法 以下为删除 MySQL 数据表的通用语法: DROP TABLE table_name ; -- 直接删除表,不检查是否存在 或 DROP…...
常用界面设计组件 —— 时间日期与定时器
2.7 时间日期与定时器2.7.1 时间日期相关的类2.7.2 日期时间数据与字符串之间的 转换2.7.3 QCalendarWidget日历组件2.7.4 定时器 2.7 时间日期与定时器 2.7.1 时间日期相关的类 时间日期是经常遇到的数据类型,Qt中时间日期类型的 类如下: QTime &…...
GO 中高效 int 转换 string 的方法与高性能源码剖析
文章目录 使用 strconv.Itoa使用 fmt.Sprintf使用 strconv.FormatIntFormatInt 深入剖析1. 快速路径处理小整数2. formatBits 函数的高效实现 结论 Go 语言 中,将整数(int)转换为字符串(string)是一项常见的操作。 本文…...
YOLOv7调用摄像头检测报错解决
yolov7detect.py文件调用本地摄像头,把source参数设为0 parser.add_argument(--source, typestr, default0, helpsource) # file/folder, 0 for webcam 报错:cv2.error: OpenCV(3.4.2) 一堆地址:The function is not implemented. Rebuild the library…...
Git学习 -- 分支合并、版本修改相关
目录 learn GIT Learn Git Branching merge和rebase的使用 基础命令 版本回退 工作区和暂存区 管理修改 撤销修改 删除修改 learn GIT Learn Git Branching 这是Gitee上的Git学习教程 Learn Git Branching Git Rebase Learn Git Branching 最终的实操 merge和rebase的…...
【小呆的力学笔记】弹塑性力学的初步认知二:应力应变分析(2)
文章目录 1.4 主应力空间、八面体应力1.5 应变分析1.6 特殊应力、应变定义 1.4 主应力空间、八面体应力 一点的应力状态不论如何变化,其主应力和主方向一致的话,该点的应力状态就是唯一确定的。因此,我们用主应力方向建立一个三维坐标系来描…...
【学网攻】 第(6)节 -- 三层交换机实现VLAN间路由
文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4)节 -- 交换机划分Vlan【学网攻】 第(5)节 -- Cisco VTP的使用 前言 网络已经成为了我们生活中不可或缺的一部分,它连接了…...
C++之内联函数
函数调用在执行时,首先要在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址(该地址指明了函数执行结束后,程序应该回到哪里继续执行)放入栈中,最后…...
【Bugku-web】alert
1.打开场景 2.按"CtrlU"查看源代码 3.翻到页面最末尾会有一个HTML实体编码,用在线工具在线Html实体编码解码后,得到flag值。...
QQ数据包解密
Windows版qq数据包格式: android版qq数据包格式: 密钥:16个0 算法:tea_crypt算法 pc版qq 0825数据包解密源码: #include "qq.h" #include "qqcrypt.h" #include <WinSock2.h> #include…...
腾讯云上linux系统使用nginx,flask构建个人网站SSL证书过期换证书的操作步骤
ssl证书过期的时候,一般腾讯云提前一段时间给通知,让更换ssl证书,现在一般都可以免费更换,一般是一年期的,审核通过之后,需要下载nginx版本的证书,我的是4个文件,替换到nginx/cert文…...
git-clone的single-branch操作回退
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 最近使用git越来越多,一些git的功能使用也更熟悉了一些。 之前使用了single-branch下载分支,后来想取消掉,但怎么做呢,查了一些资料之后,了解到了怎么做&#x…...
03 SpringBoot实战 -微头条之首页门户模块(跳转某页面自动展示所有信息+根据hid查询文章全文并用乐观锁修改阅读量)
1.1 自动展示所有信息 需求描述: 进入新闻首页portal/findAllType, 自动返回所有栏目名称和id 接口描述 url地址:portal/findAllTypes 请求方式:get 请求参数:无 响应数据: 成功 {"code":"200","mes…...
YOCTO基础 - 创建meta层与bb文件
背景 在当前的嵌入式系统开发项目中,我们面临着构建定制化 Linux 发行版以满足项目需求的挑战。我们需要在目标硬件上运行一个轻量级、高度定制化的 Linux 映像,并确保它包含我们项目中所需的特定软件包和功能。为了实现这一目标,我们选择了…...
网络电视盒子哪个好?博主分享超高性价比网络电视盒子推荐
电视盒子是我们使用最多的数码产品,年货节很多朋友在纠结网络电视盒子哪个好,我这次的测评产品就是电视盒子,按照18款电视盒子的深度测评结果整理了网络电视盒子推荐,想知道网络电视盒子哪个好可以看看下面这五款电视盒子。 一&am…...
让 SACF 自动捕获授权对象,把新授权检查安全带进生产系统
很多 ABAP 老系统里,最敏感的改造不是性能优化,也不是把一个古早 FORM 重构成类方法,而是在已经稳定运行多年的业务代码里补授权检查。原因很直接,少一次授权检查,审计和安全团队会觉得风险很大,多一次授权检查,生产用户可能第二天就打不开业务功能。SACF,也就是 Switc…...
从静态分析到代码自愈:构建自动化自我审查工具提升代码质量
1. 项目概述:从“自我审视”到“代码自愈”的工程实践在软件开发的日常中,我们常常会陷入一种“当局者迷”的困境:自己写的代码,怎么看都觉得逻辑清晰、结构完美,但一旦交给同事评审或者上线运行,各种潜在的…...
题解:学而思编程 3或5的倍数
本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。 欢迎大…...
终极MifareOneTool使用指南:如何零基础玩转MIFARE经典卡的Windows图形化神器
终极MifareOneTool使用指南:如何零基础玩转MIFARE经典卡的Windows图形化神器 【免费下载链接】MifareOneTool A GUI Mifare Classic tool on Windows(停工/最新版v1.7.0) 项目地址: https://gitcode.com/gh_mirrors/mi/MifareOneTool …...
Java动态调试利器JDBG:无侵入线上问题诊断与热修复实战
1. 项目概述:一个为Java开发者准备的调试利器如果你是一名Java开发者,肯定对调试这件事又爱又恨。爱的是,它能帮你精准定位那些让人抓狂的Bug;恨的是,传统的调试方式——在IDE里打断点、单步执行——在面对复杂、分布式…...
C#实战:利用NModbus4库高效读写西门子PLC浮点数据
1. 为什么选择NModbus4与西门子PLC通信? 在工业自动化领域,西门子PLC作为主流控制器,经常需要与上位机进行数据交换。而Modbus TCP协议因其跨平台性和简单易用的特点,成为连接不同厂商设备的通用方案。我在多个工业数据采集项目中…...
VSCode调试STM32实战:解决Cortex-Debug插件配置JLink/OpenOCD时最常见的5个报错
VSCode调试STM32实战:破解Cortex-Debug插件五大经典报错 当你在深夜赶工STM32项目,按下F5期待调试器顺利启动时,终端却弹出鲜红的错误信息——这种挫败感每个嵌入式开发者都深有体会。本文不重复那些基础配置教程,而是直击VSCode…...
YOLOv8植物病害识别检测系统(项目源码+YOLO数据集+模型权重+UI界面+python+深度学习+环境配置)
摘要 植物病害是威胁全球农业产量与质量的主要因素之一,传统的人工识别方法依赖专家经验,效率低、主观性强。本文基于YOLOv8目标检测算法,构建了一套涵盖30类植物及其叶片病害的检测系统,包括苹果、玉米、马铃薯、番茄、葡萄等主…...
TypeScript代码质量扫描利器tscanner:超越tsc的类型安全检查实践
1. 项目概述:一个被低估的TypeScript代码质量扫描利器最近在重构一个遗留的TypeScript项目,代码库已经膨胀到几十万行,各种any满天飞,类型定义混乱不堪,手动审查根本无从下手。就在我头疼的时候,同事推荐了…...
