Unity學習記錄【二】

2020年9月18日
DFA算法過濾文本的敏感詞

  • Hashtable 的鍵值對可以是任何類型(均以object類為參數(shù))
  • 相關部門網(wǎng)站上會有敏感詞庫提供
  • 完成XML模板建立后,打開Excel可以自動映射成表格,然后擴展完了之后

2020年9月19日
【事件?語法篇】如何聲明自定義的事件以及事件的完整/簡略聲明格式..

  • 事件是基于委托的,但事件不是委托類型。事件的本質(zhì)是委托字段的一個包裝器。既然是包裝器,那么就會在原有基礎上有更多限制。(在事件的完整聲明中就可以知道為什么了)

  • 為什么說事件是基于委托的?
    1.因為委托可以提供強制類型兼容的語法
    2.因為委托可以存儲方法的引用

  • 事件在對委托的包裝上做出了哪些事?
    1.事件只能使用+=、-=,不能使用= (在委托中使用=符號,叫做Reset Invocation List,重置調(diào)用列表)
    2.事件的調(diào)用(OnXX.Invoke(...))只能在事件擁有者自身的觸發(fā)邏輯中調(diào)用,而委托可以在任意地方調(diào)用。
    *3.事件的簡略聲明格式中可以用==、!=來判斷是否為空,但是完整聲明格式里不行。

  • 事件的一般聲明方式
    一般在使用事件的時候,都是用public event EventHandler OnXX; 來定義的,
    其中EventHanlder這個類型是一個約定,代表所有訂閱OnXX的方法,都要滿足EventHandler的形式。

  • EventHandler的約定是void EventHandler(object sender, EventArgs e);它是一個委托類型。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//1.事件擁有者
//2.事件
//3.事件響應者
//4.事件處理器
//5.訂閱

//1.我(類)要有一個事件(成員)
//2.一群別的類關心、訂閱我的事件(訂閱的時候要符合約定)   custom.OnOrder += waitor.TakeAction;
//3.我的事件發(fā)生了! (一定是由事件擁有者的內(nèi)部邏輯觸發(fā)的)    OnOrder.Invoke(this,e);
//4. 關心的類們被一次性通知到
//5. 被通知到的人,拿著事件參數(shù),做出相應      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)   //在事件的完整聲明中,是不可以通過!=符號來判斷的,這里是個語法糖
        {
            OrderEventArgs e = new OrderEventArgs(coffeeName, coffeeBasePrice, cup);
            //事件觸發(fā)
            OnOrder.Invoke(this, e);
        }
       
    }

    public void PayBill()
    {
        Debug.Log(Name + "一共需要支付" + Bill);
    }
}

//事件響應者
public class Waitor
{

    //事件處理器
    //按照自己的職責、任務做出特定處理
    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 +"點了一杯"+ 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;
}
  • 事件的完整聲明方式(機理)
    因為只在Custom中作了改變,所以只列出了Custom類。 事件的內(nèi)部機理可以和屬性的內(nèi)部機理比對著來理解。
public class Custom
{
    public Custom(string name)
    {
        Name = name;
    } 
    public string Name { get; set; }
    public float Bill { get; set; }
    
    //“事件是基于委托”這句話的核心↓↓↓
    public EventHandler orderEventHandler;  
    //orderEventHandler是一個委托類型的字段,而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日
委托與事件
通過事件來改善腳本通信
本次例子,假設有以下三個類:

  • Player : 會死亡
  • Achievements(成就) :在死亡1000次的時候觸發(fā)成就
  • UserInterface(用戶界面)這三個 : 顯示Player死亡信息

笨辦法:

public class Player{
  void Die(){
    FindObjectOfType<Achievements>().OnPlayerDeath();
    FindObjectOfType<UIInterface>().OnPlayerDeath();
  }
}
public  class Achievements{
  public void OnPlayerDeath(){
  }
}
public  class UserInterface{
  public void OnPlayerDeath(){
  }
}

在這里相當于是Player做了一件事情,就去主動調(diào)用其他類。

  • 這樣做會發(fā)生什么?
    后續(xù)當游戲系統(tǒng)復雜了,Player里頭就會有一堆雜七雜八的引用。讓Player的功能代碼看起來不那么專一。
    也會使得代碼復用性變差,如果想在其他項目復用Player代碼。首先得剔除所有無關引用,因為這些引用壓根不在新項目中。

  • 那怎么做?
    讓Player死亡時觸發(fā)一個事件去通知所有關注它死亡的類。
    因為監(jiān)聽player是否死亡,實際上是其他想知道這個消息的類的職責

  • 因此正確的代碼應該如下:

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; // 取消訂閱
  }
}
  • 另外:關于public event 后面跟的兼容類型,除了.Net給定的EventHandler,還可以用Action / Action<T> / Action<T1,T2> 、Func<ReturnT> / Func<T1,ReturnT>或是自定義的委托類型來約束。
  • 還有在喚醒事件的時候,一定要實現(xiàn)判空。

2020年9月23日
使用事件制作3D自動開關門(附:3D人物移動和旋轉(zhuǎn),out輸出參數(shù),3D搭建使用的快捷鍵..

  • 選中相機,Ctrl+Shift+F 相機角度自動變成Scene界面視角

  • 按住Ctrl拖拽會對其網(wǎng)格。網(wǎng)格與對齊捕捉設置:


    網(wǎng)格與對齊

    每次移動的單位
  • 按住V頂點對齊

  • 在這期視頻中找到了別的想要的,Tween系列插件——LeanTween

Tween 事實上就是一種數(shù)學庫
能夠讓使用者更加方便的處理數(shù)學動畫

  • 在AssetStore中下載免費版的之后,就可以用了。例如:
 LeanTween.moveLocalY( gameObject, to , time);

也可以用鏈式寫法,設置運動過程中的速度曲線。例如:

 LeanTween.moveLocalY( gameObject, 3.0f , 1.0f).setEaseInSine();
速度曲線表格
  • 在OnDisable或者OnDestroy中記得取消訂閱,不然會報錯,而且導致內(nèi)存過大。

  • 代碼中用枚舉類型定義一個字段的話,在Inspect界面會有下拉框。

  • Unity官方免費插件——ProGrids,方便搭建場景

  • Universal Render Pipeline

  • Unity官方免費插件——PostProcessing

2020年9月24日


2020年9月24日

排序、DotTween、LeanTween、十大Array用法、富文本、模板方法

  • 存入數(shù)據(jù)庫的時間,要用國際協(xié)調(diào)時區(qū)DataTime.UtcNow

...我還是從第一集開始看吧
委托第一集


最近在研究NLP,還有浮島星球的策劃,還有大創(chuàng)的一些事情。
女朋友在準備研究生面試,明天就要開始了,默默支持一下,嘿嘿!


2020年9月28日


2020年10月16日
Unity 中制作虛擬搖桿


2020年10月18日


Model: 存數(shù)據(jù),一般都是定義一些數(shù)據(jù)字段(比如:用戶名稱、設備縮放比、貼圖材質(zhì)、也可以有數(shù)據(jù)庫增刪改查操作這樣的方法
View: 存放UI數(shù)據(jù)引用、事件監(jiān)聽
Control:實現(xiàn)業(yè)務邏輯功能,獲取Model的數(shù)據(jù),通知View層更新數(shù)據(jù)


// 以下說的都有點問題↓↓↓
// FIXUnityEvent中沒有封裝UnityAction字段

  • <封裝了UnityAction委托字段的UnityEvent> 和 <C#中以關鍵字形式存在的event的區(qū)別>

UnityEvent中包含AddListener(UnityAction call)方法,Button.onClick就是UnityEvent類型的。
在AddListener中,會將參數(shù)call對應的函數(shù)引用,訂閱到該UnityEvent對象中。

//目前還沒找到AddListener內(nèi)部機理。
// ↑↑↑


依賴倒置原則:高層次的模塊不應該依賴于低層次的模塊,兩者都應該依賴于抽象接口。

題外話:
看到了評論區(qū)的爭辯有點意思:

題外話

我覺得兩個都說的挺對的,有時候我們需要事先預測一個需求的規(guī)模,也不是什么都要循規(guī)蹈矩。小的需求,做一個大的框架,確實要付出一些接口開發(fā)的成本。但是如果做的時候就考慮了后期要擴展這個功能,就需要想清楚了。
還有博主在這篇文章里說的最后一段,也挺有意思:

講了這么多依賴倒置原則的優(yōu)點,我們也來打擊一下大家,在現(xiàn)實世界中確實存在著必須依賴細節(jié)的事物,比如法律,就必須依賴細節(jié)的定義。 “殺人償命”在中國的法律中古今有之,那這里的殺人就是一個抽象的含義,怎么殺,殺什么人,為什么殺人,都沒有定義,只要是殺人就統(tǒng)統(tǒng)得償命,那這就是有問題了,好人殺了壞人,還要陪上自己的一條性命,這是不公正的,從這一點看,我們在實際的項目中使用依賴倒置原則時需要審時度勢,不要抓住一個原則不放,每一個原則的優(yōu)點都是有限度的,并不是放之四海而皆準的真理,所以別為了遵循一個原則而放棄了一個項目的終極目標:投產(chǎn)上線和盈利。作為一個項目經(jīng)理或架構師,應該懂得技術只是實現(xiàn)目的的工具,惹惱了頂頭上司,設計做得再漂亮,代碼寫得再完美,項目做得再符合標準,一旦項目虧本,產(chǎn)品投入大于產(chǎn)出,那整體就是扯淡!你自己也別想混得更好!


2020年10月19日

  • UnityEvent如果要帶參數(shù)的話需要通過泛型的方式——UnityEvent<T0>,但這里有個坑,就是這個泛型的UnityEvent是抽象類,因此需要自己再定義一個類,去繼承它。例如:
public class SelectContentEvent : UnityEvent<string>
 {
    //空
 }

還有一個和UnityEvent不一樣的點——在聲明事件中,需要new。例如:

public SelectContentEvent OnSelectContent = new SelectContentEvent();

2020年10月21日

  • 修改某些Unity組件的值的時候,要注意獲取的對象是引用,還是拷貝。
    例如在Render類中有一個屬性,它在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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容