首页 > 爆料站 > 好好玩
游戏开发框架设计规则!_RegEvent
2020-02-28 20:53:07 作者:佚名

原标题:游戏开发框架设计规则!

目的

  • 新增新功能时更加快速便捷,不会导致其他模块的改变,上下文清晰,更不容易出逻辑缺陷
  • 方便调试时理清逻辑关系,快速定位问题
编程思维
  • DOTS、OOP、组件式开发的优缺点
  • 设定条条框框的规则,能尽量private就尽量private,强迫程序员设计出更好的代码
Singleton
  • 优点
    • 简单易用
    • 内部不透明,无需了解内部实现直接用(多用于工具类)
  • 缺点
    • 引用混乱
    • 代码依赖性和耦连
    • 违反匿名者原则(越少人知道越好)
  • 不用它,可以强迫设计出更好的代码
低耦合 中间件和单例模式 综述
  • 强调 系统间 的交互
  • 系统之间不要直接交流,而是通过中间件交流,例如事件管理器,观察者模式
  • 尽量不用单例模式,全局变量容易交叉使用,造成理解混乱和系统之间的耦连
  • 分离判端逻辑和执行逻辑
例子
  • 游玩过程每获得100金币则获得一个成就,并且播放成就音效
糟糕的代码:
publicclassGameCoreSystem: MonoBehaviour { privatevoidGameLoop( ) { ... //游戏逻辑 //金币大于100时 if(coin++ > 100) { coin = 0; //成就系统获得成就 AchievementManager.instance.Achieve( "coin_over_100"); //音频系统播放音频 AudioManager.instance.PlayOneShot( "coin_over_100_audio"); } } }

现在看起来复杂,执行效率看起来很低,但是方便以后维护的代码:

usingPeroTools2.Commons; usingPeroTools2.Managers;

publicclassGameEvent{//全局变量事件publicconstintON_COIN_OVER_100 = 1; }

publicclassGameCoreSystem{privateintm_Coin;

privatevoidUpdate( ) {//...//每获得100金币触发成就事件if(m_Coin++ > 100) {m_Coin = 0; EventManager.instance.Invoke(GameEvent.ON_COIN_OVER_100);}}}

publicclassAchievementManager{publicAchievementManager( ) {//注册"获得成就"的事件EventManager.instance.RegEvent(GameEvent.ON_COIN_OVER_100).trigger += OnAchieved;}

privatevoidOnAchieved( objectsender, objectreciever, object[] args ) {//获得成就后的逻辑varachievementUid = ( int)args[ 0]; if(achievementUid == GameEvent.ON_COIN_OVER_100) {//...}}

~AchievementManager{//随着成就系统内存释放,去掉注册事件EventManager.instance.RegEvent(GameEvent.ON_COIN_OVER_100).trigger -= OnAchieved;}}

publicclassGameAudioSystem: AudioManager{protectedoverridevoidOnInit( ) {//在音频系统注册"获得成就"的事件EventManager.instance.RegEvent(GameEvent.ON_COIN_OVER_100).trigger += OnTrigger;}

privatevoidOnTrigger( objectsender, objectreciever, object[] args ) {//实现逻辑PlayOneShot( "sfx_button_enter"); }

privatevoidOnDestroy( ) {//随着音频系统内存释放,去掉注册事件EventManager.instance.RegEvent(GameEvent.ON_COIN_OVER_100).trigger -= OnTrigger;}}

高内聚: internal和Assembly Definition 综述

  • 强调 系统内 逻辑
  • 程序集去代表一个模块的功能,上级只引用该程序集中仅有的一个对外的管理该程序集的类
  • 强迫程序员设计出更好的代码,高内聚更体现代码的复用性
  • 编译根据程序集来进行,节约时间
MD2的框架设计
  • 脑图

  • 程序集和目录结构

  • 设计原则
  1. 一个程序集所有类可以对外public,有一个管理的类,名称为$"{程序集名称}System",有一个单例静态引用为internal,方便其他子系统访问
  2. 除了NoteSystem,所有类的对外接口限定词为internal,包括构造函数,保证了接口的封闭性与安全性
  3. 一个母系统配合几个子系统完成这个系统模块的功能,从而提供对外统一在大系统的接口,保证代码设计的高内聚
publicclassNoteSystem{///<summary>///Note包含了这个Note的特定数据 ///如什么时候是最佳打击点,是空中还是地面等 ///</summary>publicstructNote {publicinttick { get; } publicbytenoteDataUid { get; } publicNoteDataSystem.NoteData noteData => instance.m_NoteDataSystem.GetNoteData(noteDataUid);

internalNote( int_tick, byte_noteDataUid ) {tick = _tick;noteDataUid = _noteDataUid;}}

privateNativeArray<Note> m_Notes;

privatereadonlyNoteDataSystem m_NoteDataSystem;

privatereadonlyNoteTickSystem m_NoteTickSystem;

internalstaticNoteSystem instance;

publicNoteSystem( ) {instance = this; m_NoteDataSystem = newNoteDataSystem; m_NoteTickSystem = newNoteTickSystem; }...

NoteDataSystem

publicclassNoteDataSystem{publicstructNoteData {publicbyteuid { get; } publicbytetype { get; } ...

privateList< string> GetStrings( intnumber, List< string> list ) {...}

internalNoteData( byte_uid, byte_type, uint_score, uint_hp, uint_mp, uint_damage, byte_audio, byte_effect, int_bmss, int_renderer ) {...}

internalvoidSetNoteData( stringbms, stringscene ) {...} }

privateNativeArray<NoteData> m_NoteDatas; ...

internalNoteDataSystem( ) {...}

internalNoteData GetNoteData( stringbms, stringscene ) {...}

internalNoteData GetNoteData( byteuid ) {...}

~NoteDataSystem {...}}

NoteTickSystem

namespaceGameCore.Note{publicclassNoteTickSystem{///<summary>///NoteTick是以毫秒为单位分布在Note周围的判定点 ///如一首歌有100个Note,一个Note的有-50ms~50ms的判定(包括Great、Perfect之类的),那么这首歌就有100 * 100个NoteTick ///</summary>publicstructNoteTick {publicbyteuid { get; } publicbyteoffset { get; } publicboolisLeft { get; }

internalNoteTick( byte_uid, byte_offset, bool_isLeft ) {uid = _uid;offset = _offset;isLeft = _isLeft;}}

privateDictionary< int, NativeArray<NoteTick>> m_NoteTicks;

internalNoteTickSystem( ) {}

internalvoidSetup( NativeArray<NoteSystem.Note> notes) {Debug.Log( "NoteTickSystem Setup!"); }

internalNativeArray<NoteTick> GetNoteTicks( inttick ) {returnm_NoteTicks[tick]; }...

  • GameCoreSystem也同理
namespaceGameCore{publicclassGameCoreSystem{privateNoteSystem m_NoteSystem;

publicGameCoreSystem( ) {m_NoteSystem = newNoteSystem; }...

PeroTools2

  1. 部分Mnanager将不再支持外部的单例模式,游戏过程用到的Manager并且和特定属性有关的去单例,如AudioManager、UIManager、ServerManager、SceneManager,要承接上下文的则不去单例,如ResourcesManager、ConfigManager、CoroutineManager。
//新增SingletonInternal只针对PeroTools2内部拥有单例模式publicclassSingletonInternal<T> whereT: new{privatestaticT s_Instance;

internal staticT instance {get{if(s_Instance == null) {s_Instance = newT; Singleton.Init(s_Instance);}returns_Instance; }}

publicvoidReset{Singleton.Destroy(s_Instance);s_Instance = default; }}

publicclassSingleton<T> : SingletonInternal<T> where T : new{publicnewstaticT instance => SingletonInternal<T>.instance; }

  1. 通用代码的叫Manager, 特殊代码的叫System
  2. 无法单例的Manager通过继承来完成功能
publicclassGameAudioSystem: AudioManager{protectedoverridevoidOnInit( ) {EventManager.instance.RegEvent(GameEvent.ON_COIN_OVER_100).trigger += OnTrigger;}

privatevoidOnTrigger( objectsender, objectreciever, object[] args ) {PlayOneShot( "sfx_button_enter"); }

privatevoidOnDestroy( ) {EventManager.instance.RegEvent(GameEvent.ON_COIN_OVER_100).trigger -= OnTrigger;}}

其他 Unity如何创建程序集

  • 引用上你需要用到的其他程序集
  • 不同平台程序集的开启和关闭
设计模式
Zenject
  • 反注入依赖

来源:Muse Dash主程,peropero技术渣渣担当游戏网

责任编辑:



相关文章

234游戏网站地图
游戏中心
手机游戏
app大全
单机游戏
网络游戏
网页游戏
手机网游
新闻中心
网游新闻
手游新闻
单机新闻
原创栏目
综合热点
实用问答
专题文章
图片中心
美女图片
爆笑图
二次元
网游图片
单机图片
手游图片
视频中心
单机视频
手游视频
网游视频
视频综合
游戏赛事
攻略中心
单机攻略
手游攻略
网游攻略
爆料中心
娱乐八卦
新鲜事
国内新闻
评测中心
单机评测
手游评测
网游评测
子站导航
234游戏网
234问答
234游戏论坛
vr频道
问答2
问答3

大家都在搜