Unity 框架學習--1

由淺入深,慢慢演化實現框架

兩個類的實現代碼完全一樣,就只有類名或類型不一樣的時候,而且還需要不斷擴展(未來會增加各種事件)的時候,這時候就用 泛型 + 繼承 來提取,繼承解決擴展的問題,泛型解決實現代碼一致,類不一致的問題,這是一個重構技巧。

表現和數據要分離

數據在大多數情況下需要在多個場景、界面、游戲物體之間是共享的,這些數據不但需要在空間上共享,還需要再時間上也需要共享(需要存儲起來),所以在這里,開發者的共識就是把數據的部分會抽離出來,單獨放在一個地方進行維護,而比較常見的開發架構就是使用 MVC 的開發架構,我們先不用 MVC 的開發架構,而只用 MVC 中的其中一個概念,就是 Model。

Model 就是管理數據、存儲數據,管理數據就是可以通過 Model 對象或類可以對數據進行增刪改查,有的時候還可以進行存儲。

public class GameModel{public static int KillCount = 0;public static int Gold = 0;public static int Score = 0;public static int BestScore = 0;}
  • 用泛型 + 繼承 提取 Event 工具類
  • 子節點通知父節點也可以用事件(根據情況)
  • 表現和需要共享的數據分離
  • 正確的代碼要放在正確的位置

如果是共享的數據就放在 Model 里,如果不是共享的就不需要。

這里共享的數據可以是配置數據、需要存儲的數據、多個地方需要訪問的數據

對于配置數據來說,游戲中的場景和 GameObject、Prefab 在運行游戲之前也是一種配置數據,因為他們本質上是用 Yaml(類似 json、xml 的數據格式)存儲在磁盤上的。

而需要存儲的數據是從時間這個維度共享的數據,即現在可以訪問以前某個時刻存儲的數據。

?

?復用? 可綁定屬性

using System;namespace FrameworkDesign
{public class BindableProperty<T> where T : IEquatable<T>{private T mValue;public T Value{get => mValue;set{if (!mValue.Equals(value)){mValue = value;OnValueChanged?.Invoke(value);}}}public Action<T> OnValueChanged;}
}

BidableProperty 是 數據 + 數據變更事件 的合體,它既存儲了數據充當 C# 中的 屬性這樣的角色,也可以讓別的地方監聽它的數據變更事件,這樣會減少大量的樣板代碼

  • 表現邏輯 適合用 事件 或 委托
  • 表現邏輯用方法調用會造成很多問題,Controller 臃腫難維護、
  • Model 和 View 是自底向上的關系
  • 自底向上用事件或委托
  • 自頂向下用方法調用

命令模式

用一個方法來寫的邏輯,改成用對象來實現,而這個對象只有一個執行方法。

我們先定義一個接口,叫做 ICommand,代碼如下:

namespace?FrameworkDesign
{public?interface?ICommand{void?Execute();}
}

實現接口:

public struct AddCountCommand : ICommand{public void Execute(){CounterModel.Count.Value++;}}

Command 模式就是邏輯的調用和執行是分離的

空間分離的方法就是調用的地方和執行的地方放在兩個文件里。

時間分離的方法就是調用的之后,Command 過了一點時間才被執行。

而 Command 模式由于有了調用和執行分離這個特點,所以我們可以用不同的數據結構去組織 Command 調用,比如命令隊列,再比如用一個命令的堆棧,來實現撤銷功能(ctrl + z)

引入單例

  • 靜態類沒有訪問限制。
  • 使用 static 去擴展模塊,其模塊的識別度不高。
public class Singleton<T> where T : class{public static T Instance{get{if (mInstance == null){// 通過反射獲取構造var ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);// 獲取無參非 public 的構造var ctor = Array.Find(ctors, c => c.GetParameters().Length == 0);if (ctor == null){throw new Exception("Non-Public Constructor() not found in " + typeof(T));}mInstance = ctor.Invoke(null) as T;}return mInstance;}}private static T mInstance;}

模塊化優化--引入 IOC 容器

IOC 容器,大家可以理解為是一個字典,這個字典以 Type 為 key,以對象即 Instance 為 value,非常簡單。

而 IOC 容器最少有兩個核心的 API,即根據 Type 注冊實例,根據 Type 獲取實例。

實現一個簡單的 IOC 容器

public class IOCContainer{/// <summary>/// 實例/// </summary>public Dictionary<Type, object> mInstances = new Dictionary<Type, object>();/// <summary>/// 注冊/// </summary>/// <param name="instance"></param>/// <typeparam name="T"></typeparam>public void Register<T>(T instance){var key = typeof(T);if (mInstances.ContainsKey(key)){mInstances[key] = instance;}else{mInstances.Add(key,instance);}}/// <summary>/// 獲取/// </summary>public T  Get<T>() where T : class{var key = typeof(T);object retObj;if(mInstances.TryGetValue(key,out retObj)){return retObj as T;}return null;}}

將這個代碼用起來:

我們先創建一個 CounterApp 類,用于注冊全部模塊,代碼如下:
using FrameworkDesign;namespace CounterApp
{public class CounterApp{private static IOCContainer mContainer = null;// 確保 Container 是有實例的static void MakeSureContainer(){if (mContainer == null){mContainer = new IOCContainer();Init();}}// 這里注冊模塊private static void Init(){mContainer.Register(new CounterModel());}// 提供一個獲取模塊的 APIpublic static T Get<T>() where T : class{MakeSureContainer();return mContainer.Get<T>();}}
}
接著我們把 CounterApp 類應用起來,代碼如下:
using FrameworkDesign;
using UnityEngine;
using UnityEngine.UI;namespace CounterApp
{public class CounterViewController : MonoBehaviour{private CounterModel mCounterModel;void Start(){// 獲取mCounterModel = CounterApp.Get<CounterModel>();// 注冊mCounterModel.Count.OnValueChanged += OnCountChanged;transform.Find("BtnAdd").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯new AddCountCommand().Execute();});transform.Find("BtnSub").GetComponent<Button>().onClick.AddListener(() =>{// 交互邏輯new SubCountCommand().Execute();});OnCountChanged(mCounterModel.Count.Value);}// 表現邏輯private void OnCountChanged(int newValue){transform.Find("CountText").GetComponent<Text>().text = newValue.ToString();}private void OnDestroy(){// 注銷mCounterModel.Count.OnValueChanged -= OnCountChanged;mCounterModel = null;}}/// <summary>/// 不需要是單例了/// </summary>public class CounterModel{public BindableProperty<int> Count = new BindableProperty<int>(){Value = 0};}
}
AddCountCommand.cs
using FrameworkDesign;namespace CounterApp
{public struct AddCountCommand : ICommand{public void Execute(){CounterApp.Get<CounterModel>().Count.Value++;}}
}
SubCountCommand.cs
using FrameworkDesign;namespace CounterApp
{public struct SubCountCommand : ICommand{public void Execute(){CounterApp.Get<CounterModel>().Count.Value--;}}
}

--dd,這就是框架嗎? orz

以下代碼容易重復

PiontGame.cs
namespace FrameworkDesign.Example
{public class PointGame {private static IOCContainer mContainer = null;// 確保 Container 是有實例的static void MakeSureContainer(){if (mContainer == null){mContainer = new IOCContainer();Init();}}// 這里注冊模塊private static void Init(){mContainer.Register(new GameModel());}// 提供一個獲取模塊的 APIpublic static T Get<T>() where T : class{MakeSureContainer();return mContainer.Get<T>();}}
}

優化一下:創建一個類,名字叫 Architecture.cs ,代碼如下:

namespace FrameworkDesign
{/// <summary>/// 架構/// </summary>/// <typeparam name="T"></typeparam>public abstract class Architecture<T> where T : Architecture<T>, new(){#region 類似單例模式 但是僅在內部課訪問private static T mArchitecture = null;// 確保 Container 是有實例的static void MakeSureArchitecture(){if (mArchitecture == null){mArchitecture = new T();mArchitecture.Init();}}#endregionprivate IOCContainer mContainer = new IOCContainer();// 留給子類注冊模塊protected abstract void Init();// 提供一個注冊模塊的 APIpublic void Register<T>(T instance){MakeSureArchitecture();mArchitecture.mContainer.Register<T>(instance);}// 提供一個獲取模塊的 APIpublic static T Get<T>() where T : class{MakeSureArchitecture();return mArchitecture.mContainer.Get<T>();}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36109.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36109.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36109.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【RabbitMQ與SpringBoot集成測試收發消息】

【RabbitMQ與SpringBoot集成測試收發消息】 一、環境說明二、實驗步驟三、小結 一、環境說明 安裝環境&#xff1a;虛擬機VMWare Centos7.6 Maven3.6.3 JDK1.8RabbitMQ版本&#xff1a;rabbitmq-server-3.8.8-1.el7.noarch.rpm編程工具Idea 運行JDK為17 二、實驗步驟 在Rab…

List和數組互轉方法以及踩坑點

一、數組轉List 1. 使用for循環逐個添加 String[] arr {"A", "B", "C"}; List<String> list new ArrayList<>(); for (String element : arr) {list.add(element); }2. 使用Arrays.asList(arr) String[] arr {"A", …

TypeScript 泛型的深入解析與基本使用

系列文章目錄 文章目錄 系列文章目錄前言一、泛型的概念二、泛型函數三、泛型類四、泛型接口五、泛型約束總結前言 泛型是TypeScript中的一個重要概念,它允許我們在定義函數、類或接口時使用參數化類型,增強了代碼的靈活性和重用性。本文將深入探討泛型的概念,以及如何在Ty…

智能駕駛系列報告之一:智能駕駛 ChatGPT時刻有望來臨

原創 | 文 BFT機器人 L3 功能加速落地&#xff0c;政策標準有望明確 L2 發展日益成熟&#xff0c;L3 功能加速落地。根據市場監管總局發布的《汽車駕駛自動化分級》與 SAE發布的自動駕駛分級標準&#xff0c;自動駕駛主要分為 6 個級別&#xff08;0 級到 5 級&#xff0c;L0 …

Tomcat多實例部署及nginx+tomcat的負載均衡和動靜分離

Tomcat多實例部署 安裝 jdk、tomcat&#xff08;流程可看之前博客&#xff09; 配置 tomcat 環境變量 [rootlocalhost ~]# vim /etc/profile.d/tomcat.sh#tomcat1 export CATALINA_HOME1/usr/local/tomcat/tomcat1 export CATALINA_BASE1/usr/local/tomcat/tomcat1 export T…

Delphi調用WindowsAPI獲取窗口進程

Delphi有封裝的很好的WindowsAPI&#xff0c;直接調用即可&#xff0c;大體上和C差不多&#xff0c;有些地方需要額外處理。 給出一個實例&#xff1a; varg_process: THandle;procedure initGlobal(); beginvarg_handle: HWND;g_handle : FindWindow(clsName, name);if g_ha…

矩陣定理復習記錄

矩陣復習 矩陣導數定理 若A是一個如下矩陣&#xff1a; A [ a 11 a 12 a 21 a 22 ] A \begin{bmatrix}a_{11}&a_{12}\\a_{21}&a_{22}\end{bmatrix} A[a11?a21??a12?a22??] y是一個向量矩陣&#xff1a; y ? [ y 1 y 2 ] \vec{y}\begin{bmatrix}y_1\\y_2\e…

在vue項目使用數據可視化 echarts ,柱狀圖、折線圖、餅狀圖使用示例詳解及屬性詳解

官網地址&#xff1a;Apache ECharts ?一、下載插件并在頁面中引入 npm install echarts --save 頁面導入&#xff1a; import * as echarts from echarts 全局導入&#xff1a; main.js 中&#xff0c;導入并注冊到全局 import echarts from echarts Vue.prototype.$echart…

Clone函數

概述 Clone函數是一種用于復制的計算機函數。在程序編寫中&#xff0c;除了自定義一個拷貝構造函數來實現對象復制外&#xff0c;還可以實現一個clone函數。這需要借助編譯器實現的一個隱藏拷貝構造函數&#xff0c;這樣的做法&#xff0c;更省心。 中文名clone函數外文名clon…

C# 使用FFmpeg.Autogen對byte[]進行編解碼

C# 使用FFmpeg.Autogen對byte[]進行編解碼&#xff0c;參考&#xff1a;https://github.com/vanjoge/CSharpVideoDemo 入口調用類&#xff1a; using System; using System.IO; using System.Drawing; using System.Runtime.InteropServices; using FFmpeg.AutoGen;namespace F…

C++11異步與通信之 packaged_task

概念簡介 packaged_task 用于包裝可調用目標(Callable)為一個對象,如lambda&#xff0c;普通函數&#xff0c;小括號重載等&#xff0c;用于異步調用。 其返回值或所拋異常被存儲于能通過 std::future 對象訪問的共享狀態中&#xff0c;和promise類似。 將函數的調用與函數返…

時序預測 | MATLAB實現EEMD-LSTM、LSTM集合經驗模態分解結合長短期記憶神經網絡時間序列預測對比

時序預測 | MATLAB實現EEMD-LSTM、LSTM集合經驗模態分解結合長短期記憶神經網絡時間序列預測對比 目錄 時序預測 | MATLAB實現EEMD-LSTM、LSTM集合經驗模態分解結合長短期記憶神經網絡時間序列預測對比效果一覽基本介紹模型搭建程序設計參考資料 效果一覽 基本介紹 時序預測 | …

小龜帶你妙寫排序之快速排序

快速排序 一. 快速排序原理二. 題目三. 快速排序的思路分析&#xff08;圖文結合&#xff09;四.代碼 一. 快速排序原理 先從數據序列中選一個元素&#xff0c;并將序列中所有比該元素小的元素都放到它的右邊或左邊&#xff0c;再對左右兩邊分別用同樣的方法處之直到每一個待處…

runtime error: member access within misaligned address(力扣最常見錯誤之一)

runtime error: member access within misaligned address&#xff08;力扣最常見錯誤之一&#xff09; 前言原因和解決辦法總結 前言 最近博主在刷力扣時&#xff0c;明明代碼邏輯都沒問題&#xff0c;但總是報下面這個錯誤&#xff1a; runtime error: member access within…

django實現登錄和登錄的鑒權

1、創建數據庫的管理員表 在models.py 中定義admin表&#xff0c;為了簡單&#xff0c;表里只有用戶名和密碼還有默認加的id 三個字段 from django.db import models# Create your models here.class Admin(models.Model):username models.CharField(verbose_name"用戶…

源碼框架-三勾軟件

javaspringboot微信小程序商城SAAS前后端源碼: 三勾商城是開發友好的微信小程序商城&#xff0c;框架支持SAAS&#xff0c;支持發布 iOS Android 公眾號 H5 各種小程序&#xff08;微信/支付寶/百度/頭條/QQ/釘釘/淘寶&#xff09;等多個平臺&#xff0c;不可多得的二開神器…

訓練用于序列分類任務的 RoBERTa 模型的適配器

介紹 NLP當前的趨勢包括下載和微調具有數百萬甚至數十億參數的預訓練模型。然而,存儲和共享如此大的訓練模型非常耗時、緩慢且昂貴。這些限制阻礙了 RoBERTa 模型開發更多用途和適應性更強的 NLP 技術,該模型可以從多個任務中學習并針對多個任務進行學習;在本文中,我們將重…

Kafka:安裝和配置

producer&#xff1a;發布消息的對象&#xff0c;稱為消息產生者 &#xff08;Kafka topic producer&#xff09; topic&#xff1a;Kafka將消息分門別類&#xff0c;每一個消息稱為一個主題&#xff08;topic&#xff09; consumer&#xff1a;訂閱消息并處理發布消息的對象…

模擬 枚舉

分享牛客算法基礎精選題單題目打卡!!! 目錄 字符串的展開 多項式輸出 機器翻譯 : 鋪地毯 : [NOIP2016]回文日期 字符串的展開 原題鏈接 : 字符串的展開 思路 : 模擬 代碼 : #include<iostream> #include<cstring> #include<algorithm> using na…

Java課題筆記~ ServletContext

單個Servlet的配置對象 web.xml <servlet><servlet-name>FirstServlet</servlet-name><servlet-class>com.ambow.test.FirstServlet</servlet-class><init-param><param-name>charset</param-name><param-value>utf-8&…