【unity实战】在unity实现一套可扩展的Model-View-Data (MVD) 系统架构设计
最终效果
文章目录
- 最终效果
- 前言
- 1、什么是MVD架构
- 2、组件关系示意图
- 3、Model模型和Data数据的区别
- 4、基础文件结构设计
- 5、游戏开发中的扩展应用
- 5.1 可扩展卡牌系统
- 5.2 角色系统
- 5.3 道具/装备系统
- 5.4 技能系统
- 5.5 场景交互对象
- 5.6 UI系统
- 实例:实现一个可扩展卡牌系统
- 1、创建MVD架构
- 1.1 数据层 (Data)
- 1.2 模型层 (Model)
- 1.3 视图层 (View)
- 2、测试调用
- 2.1 游戏管理器脚本
- 2.2 配置不同的卡牌模板数据
- 2.3 创建CardView预制体
- 2.4 配置GameManager
- 2.5 配置按钮调用DrawCard抽卡方法方法
- 2.6 2D场景中的 UI 和物体交互
- 3、运行效果
- 参考
- 专栏推荐
- 完结
前言
1、什么是MVD架构
Model-View-Data (MVD)是一种类似于MVC(Model-View-Controller)的架构模式,特别适合游戏开发。它将应用程序分为三个主要部分:
- View: 处理游戏对象的视觉表现
- Model: 管理游戏的核心数据和逻辑
- Data: 存储和管理静态或配置数据
这种架构实现了:
-
数据与逻辑分离
-
状态与表现分离
-
支持灵活的实例化
-
便于扩展和维护
2、组件关系示意图
3、Model模型和Data数据的区别
虽然模型和数据看起来很相似,但还是有一些差异。
- 数据是静态模板(每个类型只有一份)
- 模型是动态实例(可根据数据创建多个)
示例说明,以"史莱姆卡牌"为例:
-
数据层定义:
-
基础攻击力:5
-
基础生命值:10
-
初始效果:治疗+2
-
-
游戏运行时:
-
可以创建多个史莱姆卡牌实例
-
每个实例继承数据层的初始值
-
各实例的状态可独立变化(如一个生命值提升为11,另一个仍保持7)
-
视图实时显示每个实例的当前状态
-
4、基础文件结构设计
Assets/
├── Scripts/
│ ├── Core/
│ │ ├── Models/ // 模型层
│ │ ├── Views/ // 视图层
│ │ ├── Data/ // 数据层
│ ├── Utilities/ // 工具类
│ └── GameManager.cs // 游戏入口
5、游戏开发中的扩展应用
5.1 可扩展卡牌系统
- 数据层:存储基础属性(名称/图标/基础数值)、定义卡牌效果模板、提供卡牌生成蓝图
- 模型层:维护卡牌当前属性(攻击力/生命值等)、管理临时状态和效果(增益/减益)、执行游戏逻辑运算
- 视图层:显示卡牌的实时状态和数据、处理玩家交互(点击/拖拽等)、播放视觉特效和动画
5.2 角色系统
- 数据层:角色基础属性(血量/攻击力)、技能模板
- 模型层:实时状态(当前血量/装备加成)、Buff/Debuff
- 视图层:3D模型、血条UI、技能特效
5.3 道具/装备系统
- 数据层:武器基础伤害、耐久度、图标
- 模型层:当前耐久度、强化等级、附魔效果
- 视图层:背包图标、装备外观、粒子特效
5.4 技能系统
- 数据层:技能CD、伤害公式、动画触发参数
- 模型层:当前冷却时间、连击计数
- 视图层:技能图标、施法特效、屏幕震动
5.5 场景交互对象
- 数据层:可破坏物件的抗性参数
- 模型层:当前耐久值、破坏状态
- 视图层:裂纹贴图、破碎动画
5.6 UI系统
- 数据层:窗口布局配置、文字内容
- 模型层:打开/关闭状态、动态数据绑定
- 视图层:实际渲染的UI元素
实例:实现一个可扩展卡牌系统
1、创建MVD架构
1.1 数据层 (Data)
using UnityEngine;//存储卡牌数据
[CreateAssetMenu(menuName = "Card Data")]
public class CardData : ScriptableObject
{[field: SerializeField] public Sprite Sprite { get; private set; } // 卡牌图片[field: SerializeField] public int Cost { get; private set; } // 卡牌费用[field: SerializeField, TextArea] public string Effect { get; private set; } // 卡牌效果描述
}
-
功能:卡牌原始定义库
-
职责:
-
存储基础属性(名称/图标/基础数值)
-
定义卡牌效果模板
-
提供卡牌生成蓝图
-
-
特性:
-
使用ScriptableObject实现
-
只读设计(运行时不可修改)
-
单数据可生成多实例
-
1.2 模型层 (Model)
using UnityEngine;public class Card
{private readonly CardData cardData; // 只读的卡牌基础数据// 构造函数:用CardData初始化卡牌public Card(CardData cardData){this.cardData = cardData;Effect = cardData.Effect; // 初始化效果Cost = cardData.Cost; // 初始化费用}// 属性public Sprite Sprite => cardData.Sprite; // 获取卡牌图片(简写属性)public string Title => cardData.name; // 卡牌标题使用ScriptableObject的名称public int Cost { get; set; } // 卡牌费用(可修改)public string Effect { get; set; } // 卡牌效果(可修改)// 执行卡牌效果public void PerformEffect(){Debug.Log($"触发卡牌效果:{Effect},费用:${Cost}");// 这里可以扩展实际游戏效果逻辑}
}
-
功能:卡牌运行时动态状态容器
-
职责:
-
维护卡牌当前属性(攻击力/生命值等)
-
管理临时状态和效果(增益/减益)
-
执行游戏逻辑运算
-
-
特性:
-
基于数据层实例化
-
支持运行时状态修改
-
每个卡牌实例拥有独立模型
-
1.3 视图层 (View)
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;public class CardView : MonoBehaviour, IPointerClickHandler // 实现点击接口
{[SerializeField] private SpriteRenderer cardImage; // 卡牌图片渲染器[SerializeField] private TMP_Text title; // 卡牌标题文本(TextMeshPro)[SerializeField] private TMP_Text cost; // 卡牌费用文本(TextMeshPro)[SerializeField] private TMP_Text effect; // 卡牌效果描述文本(TextMeshPro)private Card card; // 关联的卡牌逻辑对象// 初始化卡牌视图public void Setup(Card card){this.card = card;cardImage.sprite = card.Sprite; // 设置卡牌图片title.text = card.Title; // 设置标题cost.text = card.Cost.ToString(); // 设置费用effect.text = card.Effect; //设置卡牌效果描述}// 点击卡牌时的处理public void OnPointerClick(PointerEventData eventData){card.PerformEffect(); // 执行卡牌效果Destroy(gameObject); // 使用后销毁卡牌(可根据需求修改)}
}
-
功能:卡牌在游戏世界中的可视化表现
-
职责:
-
显示卡牌的实时状态和数据
-
处理玩家交互(点击/拖拽等)
-
播放视觉特效和动画
-
-
特性:纯表现层,不存储业务逻辑
2、测试调用
2.1 游戏管理器脚本
这里我们创建一个小型的游戏管理器脚本,以便我们可以测试调用前面创建的MVD架构
using System.Collections.Generic;
using UnityEngine;public class GameManager : MonoBehaviour
{[SerializeField] private List<CardData> cardDatas; // 所有卡牌数据列表[SerializeField] private CardView cardView; // 卡牌视图预制体private List<Card> deck; // 卡组private void Start(){InitializeDeck(); // 初始化卡组}// 初始化卡组(创建10张随机卡牌)private void InitializeDeck(){deck = new List<Card>();for (int i = 0; i < 10; i++){// 随机选择卡牌数据CardData data = cardDatas[Random.Range(0, cardDatas.Count)];// 创建新卡牌并加入卡组Card card = new Card(data);deck.Add(card);}}// 抽卡方法public void DrawCard(){if (deck.Count == 0) return; // 卡组为空时不抽卡// 随机选择一张卡Card drawnCard = deck[Random.Range(0, deck.Count)];deck.Remove(drawnCard); // 从卡组移除// 实例化卡牌视图CardView view = Instantiate(cardView);view.Setup(drawnCard); // 初始化卡牌视图}
}
2.2 配置不同的卡牌模板数据
2.3 创建CardView预制体
2.4 配置GameManager
2.5 配置按钮调用DrawCard抽卡方法方法
2.6 2D场景中的 UI 和物体交互
注意,前面CardView代码里我们使用EventSystem
系统的IPointerClickHandler
接口的OnPointerClick
方法实现点击卡牌时触发卡牌效果。要使用它处理 2D 场景中的 UI 和物体交互,我们还需要注意下面的准备:
-
确保物体上有Collider2D组件
-
场景中需要有EventSystem对象(新建UI时会自动创建)
-
主相机需要有Physics2DRaycaster组件
3、运行效果
参考
https://www.youtube.com/@thecodeotter
专栏推荐
地址 |
---|
【unity游戏开发入门到精通——C#篇】 |
【unity游戏开发入门到精通——unity通用篇】 |
【unity游戏开发入门到精通——unity3D篇】 |
【unity游戏开发入门到精通——unity2D篇】 |
【unity实战】 |
【制作100个Unity游戏】 |
【推荐100个unity插件】 |
【实现100个unity特效】 |
【unity框架/工具集开发】 |
【unity游戏开发——模型篇】 |
【unity游戏开发——InputSystem】 |
【unity游戏开发——Animator动画】 |
【unity游戏开发——UGUI】 |
【unity游戏开发——联网篇】 |
【unity游戏开发——优化篇】 |
【unity游戏开发——shader篇】 |
【unity游戏开发——编辑器扩展】 |
【unity游戏开发——热更新】 |
【unity游戏开发——网络】 |
完结
好了,我是向宇
,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!