- 計(jì)劃:
【腳本通信】
【委托】
【UI游戲界面-上下頁切換】
【單例模式】
【任務(wù)系統(tǒng)】
【對話系統(tǒng)】
【ScriptableObject實(shí)現(xiàn)技能樹】
【三種拖拽方法】
【異步場景加載】
【代碼整理 Inspector 里顯示的腳本變量整理】
2020年9月18日
DFA算法過濾文本的敏感詞
- Hashtable 的鍵值對可以是任何類型(均以object類為參數(shù))
- 相關(guān)部門網(wǎng)站上會有敏感詞庫提供
- 完成XML模板建立后,打開Excel可以自動映射成表格,然后擴(kuò)展完了之后
2020年9月19日
【事件?語法篇】如何聲明自定義的事件以及事件的完整/簡略聲明格式..
事件是基于委托的,但事件不是委托類型。事件的本質(zhì)是委托字段的一個(gè)包裝器。既然是包裝器,那么就會在原有基礎(chǔ)上有更多限制。(在事件的完整聲明中就可以知道為什么了)
為什么說事件是基于委托的?
1.因?yàn)槲锌梢蕴峁?strong>強(qiáng)制類型兼容的語法
2.因?yàn)槲锌梢?strong>存儲方法的引用事件在對委托的包裝上做出了哪些事?
1.事件只能使用+=、-=,不能使用= (在委托中使用=符號,叫做Reset Invocation List,重置調(diào)用列表)
2.事件的調(diào)用(OnXX.Invoke(...))只能在事件擁有者自身的觸發(fā)邏輯中調(diào)用,而委托可以在任意地方調(diào)用。
*3.事件的簡略聲明格式中可以用==、!=來判斷是否為空,但是完整聲明格式里不行。事件的一般聲明方式
一般在使用事件的時(shí)候,都是用public event EventHandler OnXX; 來定義的,
其中EventHanlder這個(gè)類型是一個(gè)約定,代表所有訂閱OnXX的方法,都要滿足EventHandler的形式。EventHandler的約定是void EventHandler(object sender, EventArgs e);它是一個(gè)委托類型。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//1.事件擁有者
//2.事件
//3.事件響應(yīng)者
//4.事件處理器
//5.訂閱
//1.我(類)要有一個(gè)事件(成員)
//2.一群別的類關(guān)心、訂閱我的事件(訂閱的時(shí)候要符合約定) custom.OnOrder += waitor.TakeAction;
//3.我的事件發(fā)生了! (一定是由事件擁有者的內(nèi)部邏輯觸發(fā)的) OnOrder.Invoke(this,e);
//4. 關(guān)心的類們被一次性通知到
//5. 被通知到的人,拿著事件參數(shù),做出相應(yīng) TakeAction(object _sender, EventArgs _e)
public class EventExample_Pro : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Custom custom = new Custom("Jimmy");
Waitor waitor = new Waitor();
//訂閱
custom.OnOrder += waitor.TakeAction;
custom.Order("抹茶星冰樂",25,"大杯");
custom.Order("焦糖瑪奇朵", 28, "超大杯");
custom.PayBill();
}
}
//事件擁有者
public class Custom
{
public Custom(string name)
{
Name = name;
}
public string Name { get; set; }
public float Bill { get; set; }
public event EventHandler OnOrder;
public void Order(string coffeeName, float coffeeBasePrice, string cup)
{
if (OnOrder != null) //在事件的完整聲明中,是不可以通過!=符號來判斷的,這里是個(gè)語法糖
{
OrderEventArgs e = new OrderEventArgs(coffeeName, coffeeBasePrice, cup);
//事件觸發(fā)
OnOrder.Invoke(this, e);
}
}
public void PayBill()
{
Debug.Log(Name + "一共需要支付" + Bill);
}
}
//事件響應(yīng)者
public class Waitor
{
//事件處理器
//按照自己的職責(zé)、任務(wù)做出特定處理
internal void TakeAction(object _sender, EventArgs _e)
{
Custom custom = _sender as Custom;
OrderEventArgs e = _e as OrderEventArgs;
float bill = 0;
switch (e.CoffeeCup)
{
case "中杯":
bill = e.CoffeeBasePrice;
break;
case "大杯":
bill = e.CoffeeBasePrice + 3;
break;
case "超大杯":
bill = e.CoffeeBasePrice + 6;
break;
default:
Debug.Log("只能在中杯、大杯、超大杯里挑選");
break;
}
custom.Bill += bill;
Debug.Log(custom.Name +"點(diǎn)了一杯"+ e.CoffeeName+",需要支付" + bill);
}
}
//事件消息
public class OrderEventArgs : EventArgs
{
public OrderEventArgs(string name, float basePrice, string cup)
{
CoffeeName = name;
CoffeeBasePrice = basePrice;
CoffeeCup = cup;
}
public string CoffeeName;
public float CoffeeBasePrice;
public string CoffeeCup;
}
-
事件的完整聲明方式(機(jī)理)
因?yàn)橹辉贑ustom中作了改變,所以只列出了Custom類。 事件的內(nèi)部機(jī)理可以和屬性的內(nèi)部機(jī)理比對著來理解。
public class Custom
{
public Custom(string name)
{
Name = name;
}
public string Name { get; set; }
public float Bill { get; set; }
//“事件是基于委托”這句話的核心↓↓↓
public EventHandler orderEventHandler;
//orderEventHandler是一個(gè)委托類型的字段,而OnOrder事件是它的包裝器
//OnOrder是依賴于orderEventHandler的
public event EventHandler OnOrder
{
add
{
orderEventHandler += value;
}
remove
{
orderEventHandler -= value;
}
}
public void Order(string coffeeName, float coffeeBasePrice, string cup)
{
if (orderEventHandler != null)
{
OrderEventArgs e = new OrderEventArgs(coffeeName, coffeeBasePrice, cup);
//事件觸發(fā)
//完整聲明中,只能通過事件內(nèi)部的委托字段來執(zhí)行
orderEventHandler(this, e);
}
}
public void PayBill()
{
Debug.Log(Name + "一共需要支付" + Bill);
}
}
- 另外EventHandler、Sender、EventArgs 都可以派生。
2020年9月20日
委托與事件
通過事件來改善腳本通信
本次例子,假設(shè)有以下三個(gè)類:
- Player : 會死亡
- Achievements(成就) :在死亡1000次的時(shí)候觸發(fā)成就
- UserInterface(用戶界面)這三個(gè) : 顯示Player死亡信息
笨辦法:
public class Player{
void Die(){
FindObjectOfType<Achievements>().OnPlayerDeath();
FindObjectOfType<UIInterface>().OnPlayerDeath();
}
}
public class Achievements{
public void OnPlayerDeath(){
}
}
public class UserInterface{
public void OnPlayerDeath(){
}
}
在這里相當(dāng)于是Player做了一件事情,就去主動調(diào)用其他類。
這樣做會發(fā)生什么?
后續(xù)當(dāng)游戲系統(tǒng)復(fù)雜了,Player里頭就會有一堆雜七雜八的引用。讓Player的功能代碼看起來不那么專一。
也會使得代碼復(fù)用性變差,如果想在其他項(xiàng)目復(fù)用Player代碼。首先得剔除所有無關(guān)引用,因?yàn)檫@些引用壓根不在新項(xiàng)目中。那怎么做?
讓Player死亡時(shí)觸發(fā)一個(gè)事件去通知所有關(guān)注它死亡的類。
因?yàn)?strong>監(jiān)聽player是否死亡,實(shí)際上是其他想知道這個(gè)消息的類的職責(zé)因此正確的代碼應(yīng)該如下:
public class Player{
public event Action deathEvent; //通過事件來通知其他類
void Die(){
if( deathEvent != null){
deathEvent(); //或者deathEvent.Invoke();
}
}
public class Achievements{
void Start(){
FindObjectOfType<Player>().deathEvent += OnPlayerDeath; // 訂閱
}
public void OnPlayerDeath(){
// TODO Something ...
// ....
FindObjectOfType<Player>().deathEvent -= OnPlayerDeath; // 記得取消訂閱
}
}
public class UserInterface{
void Start(){
FindObjectOfType<Player>().deathEvent += OnPlayerDeath; // 訂閱
}
public void OnPlayerDeath(){
// TODO Something ...
// ....
FindObjectOfType<Player>().deathEvent -= OnPlayerDeath; // 取消訂閱
}
}
- 另外:關(guān)于public event 后面跟的兼容類型,除了.Net給定的EventHandler,還可以用Action / Action<T> / Action<T1,T2> 、Func<ReturnT> / Func<T1,ReturnT>或是自定義的委托類型來約束。
- 還有在喚醒事件的時(shí)候,一定要實(shí)現(xiàn)判空。
2020年9月23日
使用事件制作3D自動開關(guān)門(附:3D人物移動和旋轉(zhuǎn),out輸出參數(shù),3D搭建使用的快捷鍵..
選中相機(jī),Ctrl+Shift+F 相機(jī)角度自動變成Scene界面視角
-
按住Ctrl拖拽會對其網(wǎng)格。網(wǎng)格與對齊捕捉設(shè)置:
網(wǎng)格與對齊
每次移動的單位 按住V頂點(diǎn)對齊
在這期視頻中找到了別的想要的,Tween系列插件——LeanTween
Tween 事實(shí)上就是一種數(shù)學(xué)庫
能夠讓使用者更加方便的處理數(shù)學(xué)動畫
- 在AssetStore中下載免費(fèi)版的之后,就可以用了。例如:
LeanTween.moveLocalY( gameObject, to , time);
也可以用鏈?zhǔn)綄懛?,設(shè)置運(yùn)動過程中的速度曲線。例如:
LeanTween.moveLocalY( gameObject, 3.0f , 1.0f).setEaseInSine();

在OnDisable或者OnDestroy中記得取消訂閱,不然會報(bào)錯,而且導(dǎo)致內(nèi)存過大。
代碼中用枚舉類型定義一個(gè)字段的話,在Inspect界面會有下拉框。
Unity官方免費(fèi)插件——ProGrids,方便搭建場景
Universal Render Pipeline
2020年9月24日
-
資源商城的FBX Exporter可以把Unity中的模型導(dǎo)出成.FBX格式文件(在上面視頻中的28:10有教程)
插件預(yù)覽
2020年9月24日
排序、DotTween、LeanTween、十大Array用法、富文本、模板方法
- 存入數(shù)據(jù)庫的時(shí)間,要用國際協(xié)調(diào)時(shí)區(qū)DataTime.UtcNow
...我還是從第一集開始看吧
委托第一集
最近在研究NLP,還有浮島星球的策劃,還有大創(chuàng)的一些事情。
女朋友在準(zhǔn)備研究生面試,明天就要開始了,默默支持一下,嘿嘿!
2020年9月28日
- 以下兩篇,我就大概地看了下,停留在了解層面
游戲設(shè)計(jì)模式--Unity事件隊(duì)列
使用DoTween在Unity中制作隊(duì)列(Sequence)動畫
2020年10月16日
Unity 中制作虛擬搖桿
2020年10月18日
Unity官方社區(qū)中的Issue Tracker Bug記錄都在里頭,可以去查查有沒有解決方案。
Unity UI事件管理系統(tǒng)設(shè)計(jì),看不懂TAT..
-
Unity MVC簡要說明 這里面提到了一個(gè)給初學(xué)者了解MVC的插件 :
Code Control | Easy MVC for Unity
Unity MVC初學(xué)者插件
- 【Unity3D】在Unity3d中如何使用MVC框架 較為具體地說了MVC,也給了例子,但我只看懂了 一到四節(jié),五感覺例子還是太簡單了,我沒咋有更具體的概念。
Model: 存數(shù)據(jù),一般都是定義一些數(shù)據(jù)字段(比如:用戶名稱、設(shè)備縮放比、貼圖材質(zhì)、也可以有數(shù)據(jù)庫增刪改查操作這樣的方法
View: 存放UI數(shù)據(jù)引用、事件監(jiān)聽
Control:實(shí)現(xiàn)業(yè)務(wù)邏輯功能,獲取Model的數(shù)據(jù),通知View層更新數(shù)據(jù)
// 以下說的都有點(diǎn)問題↓↓↓
// FIX : UnityEvent中沒有封裝UnityAction字段
- <封裝了UnityAction委托字段的UnityEvent> 和 <C#中以關(guān)鍵字形式存在的event的區(qū)別>
UnityEvent中包含
AddListener(UnityAction call)方法,Button.onClick就是UnityEvent類型的。
在AddListener中,會將參數(shù)call對應(yīng)的函數(shù)引用,訂閱到該UnityEvent對象中。
//目前還沒找到AddListener內(nèi)部機(jī)理。
// ↑↑↑
依賴倒置原則:高層次的模塊不應(yīng)該依賴于低層次的模塊,兩者都應(yīng)該依賴于抽象接口。
題外話:
看到了評論區(qū)的爭辯有點(diǎn)意思:

我覺得兩個(gè)都說的挺對的,有時(shí)候我們需要事先預(yù)測一個(gè)需求的規(guī)模,也不是什么都要循規(guī)蹈矩。小的需求,做一個(gè)大的框架,確實(shí)要付出一些接口開發(fā)的成本。但是如果做的時(shí)候就考慮了后期要擴(kuò)展這個(gè)功能,就需要想清楚了。
還有博主在這篇文章里說的最后一段,也挺有意思:
講了這么多依賴倒置原則的優(yōu)點(diǎn),我們也來打擊一下大家,在現(xiàn)實(shí)世界中確實(shí)存在著必須依賴細(xì)節(jié)的事物,比如法律,就必須依賴細(xì)節(jié)的定義。 “殺人償命”在中國的法律中古今有之,那這里的殺人就是一個(gè)抽象的含義,怎么殺,殺什么人,為什么殺人,都沒有定義,只要是殺人就統(tǒng)統(tǒng)得償命,那這就是有問題了,好人殺了壞人,還要陪上自己的一條性命,這是不公正的,從這一點(diǎn)看,我們在實(shí)際的項(xiàng)目中使用依賴倒置原則時(shí)需要審時(shí)度勢,不要抓住一個(gè)原則不放,每一個(gè)原則的優(yōu)點(diǎn)都是有限度的,并不是放之四海而皆準(zhǔn)的真理,所以別為了遵循一個(gè)原則而放棄了一個(gè)項(xiàng)目的終極目標(biāo):投產(chǎn)上線和盈利。作為一個(gè)項(xiàng)目經(jīng)理或架構(gòu)師,應(yīng)該懂得技術(shù)只是實(shí)現(xiàn)目的的工具,惹惱了頂頭上司,設(shè)計(jì)做得再漂亮,代碼寫得再完美,項(xiàng)目做得再符合標(biāo)準(zhǔn),一旦項(xiàng)目虧本,產(chǎn)品投入大于產(chǎn)出,那整體就是扯淡!你自己也別想混得更好!
2020年10月19日
- UnityEvent如果要帶參數(shù)的話需要通過泛型的方式——UnityEvent<T0>,但這里有個(gè)坑,就是這個(gè)泛型的UnityEvent是抽象類,因此需要自己再定義一個(gè)類,去繼承它。例如:
public class SelectContentEvent : UnityEvent<string>
{
//空
}
還有一個(gè)和UnityEvent不一樣的點(diǎn)——在聲明事件中,需要new。例如:
public SelectContentEvent OnSelectContent = new SelectContentEvent();
2020年10月21日
- 修改某些Unity組件的值的時(shí)候,要注意獲取的對象是引用,還是拷貝。
例如在Render類中有一個(gè)屬性,它在get方法中做了處理,返回的是materials數(shù)組的一份拷貝。
public Material[] materials { get; set; }
- 在Render組件的API中有如下說明:
Render.materials:
Note that like all arrays returned by Unity, this returns a copy of materials array. If you want to change some materials in it, get the value, change an entry and set materials back.
- Unity封裝的類里頭,如果包含的屬性是數(shù)組,都會返回一份拷貝。如果需要修改數(shù)組中的元素,只能通過改變數(shù)組的入口地址(為數(shù)組整體賦值)。
Unity Connect不做了
Hi JimmyZou,
Today we’re announcing that on February 4, 2021, Unity Connect, our dedicated talent and sharing marketplace, will shut down. We’re proud of the community that rallied around Connect and we are inspired by the great sharing and discovery that came from it.
We want to make this transition as smooth as possible for everyone who uses Connect. If you are an active user on the platform, click here to learn more about the alternatives that will be provided for some Connect features. If you would like to download any part of your profile, please feel free to do so before we delete your information on February 4, 2021.
Unity Connect就業(yè)信息網(wǎng)頁:
https://connect.unity.com/jobs



