国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

委托與事件

2023-03-15 15:41 作者:獨立游戲人-老雷  | 我要投稿

前言

今天給大家分享一個游戲開發(fā)面試當中基礎(chǔ)又高頻的問題——委托與事件有什么區(qū)別

在這節(jié)分享當中,我將從這些方面為大家剖析這些問題

  • 首先回顧一下委托的基本用法

  • 但僅僅了解委托的基本用法是不夠的,面試過程中,面試官更多的會問委托與設(shè)計模式的關(guān)系,熟悉委托和事件基本用法的同學都知道,兩者在語法和用法層面是非常相似的,那么這兩者究竟有什么區(qū)別呢?

  • 我們在設(shè)計項目架構(gòu)時,應(yīng)當選擇使用委托還是使用事件呢?

  • C#和Unity為了方便我們使用事件,都內(nèi)置了一些泛型事件類型,那么在開發(fā)項目時,我們應(yīng)當使用C#內(nèi)置的事件類型還是unity內(nèi)置的事件類型呢?

  • 在掌握前面四點以后,在面試中可以拿及格分,那么如何達到或者超出面試官對面試者的心理預(yù)期呢?

在委托與事件的進階環(huán)節(jié),我將進一步為大家深入講解委托與事件的本質(zhì)和進階用法

版權(quán)聲明

本文為“優(yōu)夢創(chuàng)客”原創(chuàng)文章,您可以自由轉(zhuǎn)載,但必須加入完整的版權(quán)聲明

更多學習資源請私信我獲?。ㄆ髽I(yè)級性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項目實戰(zhàn)/每周直播/一對一指導)

點贊、關(guān)注、分享可免費獲得配套學習資源

完整視頻請觀看

如何實現(xiàn)攻擊武器切換?


首先通過一個實際問題了解委托能幫我們解決什么問題

假設(shè)要開發(fā)一款游戲,這款游戲中游戲的主角可以使用主武器或者副武器對敵人實施攻擊,當使用主武器時,使用主武器的傷害計算公式計算對敵人造成的傷害,當使用副武器時,使用副武器的傷害計算公式計算對敵人造成的傷害

那么問題來了,如何設(shè)計代碼優(yōu)雅地只寫一行,發(fā)出攻擊指令的代碼就能夠針對當前使用的武器,不管當前使用的是主武器還是副武器,計算武器傷害呢?

要實現(xiàn)這個功能,只要使用委托就夠了

如何定義變量/如何定義委托


要理解如何定義委托,首先需要了解如何定義變量

  • 大家可以看到在左邊定義了一個attack變量,同時還定義了兩個常量,分別代表了主武器和副武器的攻擊力,在如圖所示的Start程序代碼段中,當我把attack的值賦值為主武器攻擊時,attack就能代表主武器的攻擊力,當我復(fù)制為副武器攻擊時,它就代表副武器的攻擊力

類似的,可以定義一個委托

  • 前面講過委托是一個函數(shù)的容器,它可以裝得下任何類型的函數(shù),所以現(xiàn)在定義的委托可以裝下返回值為void,沒有任何參數(shù),大家注意,括號里面是參數(shù)表,參數(shù)表為空,就是沒有任何參數(shù)的一種委托,我給它起個名字叫做MyDelegate

  • 于是就定義一個MyDelegate類型的變量,叫做attack,在Start方法里面,當我把attack復(fù)制為主武器攻擊時,就指向了主武器攻擊的函數(shù),那么它就會運用主武器攻擊函數(shù)里面定義的傷害計算公式,計算對游戲當中敵人造成的傷害

  • 同樣的道理,當我把attack復(fù)制為副武器攻擊時,它就會指向副武器攻擊函數(shù),從而用副武器攻擊的傷害計算公式,計算對敵人造成的傷害

所以,說委托是函數(shù)的容器是有道理的,你可以這樣理解,在左邊的代碼里面,用attack這樣的房間容納了主武器的攻擊力數(shù)值3,或者副武器的攻擊力數(shù)值5

在右邊的代碼里面,用attack這樣的代理,它也相當于是一個房間,這個房間里面容納的不是一個數(shù)字,而是一個函數(shù),它要么是主武器攻擊的函數(shù),要么是副武器攻擊的函數(shù)

當然有同學可能會問,代理是一個變量,變量怎么能容納函數(shù)的呢?這個就要從對計算機的理解說起

  • 其實在計算機當中,每個定義的函數(shù),不管是主武器攻擊還是副武器攻擊,函數(shù)內(nèi)部都有一段程序代碼,這個程序代碼是存儲在內(nèi)存當中的,就像變量在內(nèi)存當中有存儲地址一樣,函數(shù)代表的一段指令也是有存儲地址的

  • 假設(shè)主武器攻擊的存儲地址是16進制的0xAB,是一個16進制地址,而副武器對應(yīng)的存儲地址是0xCD,這是函數(shù)的開始地址,把attack賦值為主武器攻擊,實際上就是讓attack指向0xAB的地址,而如果我把attack復(fù)制為副武器攻擊,那么這時實際上是讓它去指向0xCD的地址

  • 到這里大家應(yīng)該能明白,其實attack作為一個函數(shù)容器,它存儲的就是函數(shù)的入口地址


既然定義了attack委托,可以指向主武器或者副武器攻擊,那我們?nèi)绾伟l(fā)出一條攻擊指令,針對當前使用的武器進行傷害計算呢?

  • 方法很簡單,我們只需要在定義完委托以后,調(diào)用這個委托就可以了,大家可以看到在右半邊的代碼里面,我們在unity的一個Update函數(shù)里面,實時的檢測當前用戶按下的鍵,如果它按下的是空格鍵,這時就調(diào)用attack委托

  • 如果你的attack委托是指向主武器攻擊,它就會調(diào)用主武器攻擊的傷害計算函數(shù),如果它指向的是副武器攻擊,那么它就會調(diào)用副武器攻擊的傷害計算函數(shù)

委托可能為null


在使用委托的時候,新手同學往往會忽視一個問題,委托可能是空值,那么什么情況下它會是空值呢?

  • 比如在前面的程序當中,如果既沒有把attack復(fù)制為主武器攻擊,也沒有復(fù)制為副武器攻擊,假如玩家剛從新手村出生,這時它是赤手空拳的狀態(tài),那么它既不會有主武器,也不會有副武器,這時attack的默認值等于null

  • 如果你像前面一樣直接調(diào)用attack函數(shù),當你一調(diào)用這個函數(shù),C#包括unity的控制臺就會報程序異常,告訴你空委托是不能進行調(diào)用的,所以我們寫程序的時候一定要注意,對于一個委托,一定要先判斷它是否為空,不為空的情況下才能調(diào)用attack


但是如果每一次用委托的時候,都寫一個if判斷,那這個程序看上去會非常的冗長不優(yōu)雅,怎么辦呢?

  • 我們完全可以用另外一種C#新的語法形式,當我去調(diào)用一個委托的時候,如圖所示,可以寫attack(),這是第一種寫法

  • 也可以寫attack.Invoke(),如果沒有參數(shù),就直接寫一對括號,如果在調(diào)用函數(shù)的時候,有一些參數(shù),要把參數(shù)寫在這對括號里面,這是正常的調(diào)用attack委托的兩種方式

  • 前面我們講過了,要判斷attack委托是不是為空,可以在attack和點中間加一個問號,這個問號表達的意思就是if判斷,也就是說如果attack是空值,這個問號就判斷它是不是為空,如果不為空就會執(zhí)行Invoke,如果attack為空就跳過執(zhí)行

所以C#的這個語法糖還是挺有用的,它可以幫助程序更加簡潔,請大家也了解一下這個用法,特別是面試一些新手同學的時候,面試官為了考察新手同學是不是經(jīng)常寫代碼,有項目的經(jīng)驗,或者是經(jīng)常閱讀代碼,就會用這些新的語法堂,語法形式考察同學掌握的知識面和知識的深度

相信大家學到現(xiàn)在應(yīng)該已經(jīng)知道,如何使用代理去切換我們的主武器和副武器攻擊了,下面是一個完整的項目示例


我們設(shè)置了通過輸入數(shù)字1鍵,切換到主武器攻擊,通過數(shù)字2鍵,切換到副武器攻擊,通過按下空格鍵,釋放攻擊技能,大致就是這樣的實現(xiàn)方式

多播委托


現(xiàn)在我們把問題延伸一下,假設(shè)要同時實現(xiàn)主武器和副武器攻擊,用委托還能實現(xiàn)嗎?

  • 答案是:用傳統(tǒng)的委托不可以——但C#在很早很早的標準更新,大概是2.0的時候,對委托進行了改進,就是一個委托能夠指向多個函數(shù),我們稱這種用法叫做多播委托

  • 通過多播委托,可以在程序代碼當中寫+=的運算符,這樣就可以給attack委托增加它所指向的函數(shù),這時只要把主武器攻擊,副武器攻擊都添加到attack以后,當我同樣發(fā)出一個attack調(diào)用的時候,就會同時執(zhí)行主武器和副武器攻擊的函數(shù),我們怎么理解這件事情呢?

  • attack相當于一間房子,這間房子只能住一位客人,現(xiàn)在你可以把attack理解成一棟大樓,這個大樓有很多層樓,每一層樓都可以住一位客人,也就是說attack函數(shù),可以同時存放,同時指向多個函數(shù)的入口地址

其實當大家能夠回答委托的底層原理,也就是指向函數(shù)的入口地址的時候,就已經(jīng)回答到面試問題的60分了,如何能達到90分的狀態(tài)呢?

  • 這時大家就需要進一步的深入理解多播委托是如何實現(xiàn)的,這一部分內(nèi)容會在小白的游戲夢、主程進階之路當中給大家做系統(tǒng)的講解,以及在面試模擬環(huán)節(jié),幫大家做技術(shù)的深挖,使你在面試過程中達到令面試官滿意,甚至超過面試官心理預(yù)期的狀態(tài)

委托與設(shè)計模式


下面一起看一看委托與設(shè)計模式的關(guān)系,運用好設(shè)計模式不僅可以使代碼更優(yōu)雅,也可以使代碼性能更高,并且關(guān)于委托與設(shè)計模式的問題,也是在游戲開發(fā)面試中的重點

當玩家在游戲中死亡時


下面我們從一個具體的問題看起,假設(shè)現(xiàn)在正在開發(fā)的一款游戲,當游戲玩家死亡時,需要執(zhí)行圖上面所列的這些處理

  • 通知輸入系統(tǒng)關(guān)閉游戲的輸入

  • 通知ui系統(tǒng)更新到死亡的UI界面

  • 通知敵人停止攻擊

  • 通知場景重啟到死亡狀態(tài),或者玩家重生的狀態(tài)

如果要實現(xiàn)這個需求,程序怎樣設(shè)計它的效率是比較高的,它的架構(gòu)是比較優(yōu)雅的呢?

  • 我們需要先對需求做一個分析,玩家死亡是一個事件,當事件發(fā)生的時候,有許多對象要處理這個事件,包括輸入對象,UI對象,敵人對象,場景對象,處理的方式對于不同的對象是不一樣的

  • 比如對于輸入對象,應(yīng)該關(guān)閉輸入,對于UI對象,應(yīng)該更新UI界面,對于敵人對象,應(yīng)當停止攻擊,對于場景對象應(yīng)該把場景進行重啟,每個對象如何能得知這個玩家死亡了呢?這是在處理玩家死亡的時候的要點問題,在這里處理方式有三種

解決方法1:每個模塊在Update中檢測


第一種方式是在每一個需要接收玩家死亡事件的模塊里面,每一幀的更新函數(shù),也就是我們所熟知的unity中Update函數(shù)當中,檢測當前玩家是不是發(fā)生死亡

比如輸入模塊可以在Update里面檢測玩家的血值是否小于零,UI模塊,敵人模塊,場景模塊也可以這么做,但這樣做會帶來一個問題,就是性能比較低,為什么這樣做性能會比較低呢?

  • 因為現(xiàn)在輸入模塊是四個,這四個模塊需要檢測血值,如果將來有更多的模塊需要檢測玩家的血值是否小于零,是否死亡了,那是不是要繼續(xù)增加玩家死亡的檢測語句,要知道每條語句的執(zhí)行都是有開銷的

  • 而且本身Update在游戲當中,如果游戲比較流暢的話,以每秒60次的頻率進行執(zhí)行,它本身每一個模塊的開銷就比較大,整個檢測玩家死亡的性能開銷是模塊數(shù)乘以每個模塊里面每秒鐘的檢測次數(shù)

  • 假設(shè)一款游戲比較流暢,每秒鐘有60次的檢測,那這個性能開隨著模塊增加,性能開銷會越來越大,所以第一種方法并不是性能比較好的方式,同時第一種方式會有很多的冗余代碼,因為每個模塊都需要寫檢測代碼,這些代碼是重復(fù)復(fù)制粘貼的

解決方法2:玩家模塊中調(diào)用每個模塊


那么有沒有更好點的辦法呢?于是就想到了第二種方法,不是每個模塊主動檢測玩家的血值,而是玩家模塊在玩家死亡以后,調(diào)用每個模塊的死亡處理函數(shù),這種方式看上去是不是優(yōu)雅一些

在玩家模塊當中Update里面,每一幀都去檢測玩家自身的血值是不是小于零,如果小于零,就向輸入系統(tǒng)發(fā)出玩家死亡的消息,向ui系統(tǒng),敵人系統(tǒng),場景系統(tǒng)也發(fā)出消息,這樣的做法看上去代碼會更加優(yōu)雅一些,并且效率也會更高一些,為什么呢?

  • 原來是每個模塊都要有玩家的血值檢測,它的模塊數(shù)量越多,檢測次數(shù)越多,現(xiàn)在只要集中在一個模塊里面進行檢測,它的性能也提高了,另外代碼看上去也更加簡潔優(yōu)雅

  • 但問題是這樣的模塊,在設(shè)計模式里面是不符合叫做對修改封閉,對增加開放的最基本的原則,也就是所謂的半開半閉原則的

  • 比如現(xiàn)在要增加一個xxx模塊,當增加該模塊的時候,就需要修改玩家.Update的代碼,這樣,玩家模塊的代碼就比較難以維護,需要因為每當增加一個模塊,就要增加死亡處理的代碼(形如:xxx.OnPlayerDeath())

解決方法3:用觀察者模式解決問題


更加優(yōu)雅的方式是第三種解決方案,在設(shè)計模式里面叫做觀察者模式,首先介紹一下觀察者模式

  • 觀察者模式是一種軟件的設(shè)計模式,它不像解決方案一一樣,實時的檢測某一個事件有沒有發(fā)生,而是在事件發(fā)生的時候通知你,但它又不像方法二一樣,當事件發(fā)生的時候,因為模塊的增加去修改代碼,這就是觀察者模式要解決的兩個問題,也是解決方案三希望達到的目標

  • 要實現(xiàn)觀察者模式,過去我們需要編寫很長的程序代碼實現(xiàn)這樣的模式,但是由于C#引入了委托的機制,相當于幫我們實現(xiàn)了觀察者模式很大一部分工作,因此在C#里面實現(xiàn)觀察者模式會更加容易,在這里只需要定義一個所謂的事件

  • 這里的事件只是一個概念,并不是C#語法層面的事件,是用delegate委托的形式定義一個OnGameOver的事件,就是玩家死亡的事件,然后定義一個事件委托變量onGameOver,當玩家的血值小于零的時候,通過事件委托引發(fā)這個事件

  • 因為前面講過這個委托有一種形式叫多播委托,所以并不需要像前面的解決方法二一樣,為每一個要處理玩家死亡事件的模塊調(diào)用方法,而是利用多播委托

  • 相當于多播委托是一個容器,這個容器里面已經(jīng)放了輸入模塊,UI模塊,敵人模塊,場景模塊的事件處理函數(shù),當invoke的時候,一次性就把這些要調(diào)用的這處理函數(shù)調(diào)用完

  • 當然如果有更多的模塊,也不需要在這里增加程序代碼,只需要在新增加的模塊里面訂閱OnGameOver委托就可以了,OnGameOver仍然能夠繼續(xù)調(diào)用到新增加模塊的事件處理的函數(shù)

這就是委托如何幫我們實現(xiàn)觀察者模式,優(yōu)雅的解決前面講的事件處理的問題


在前面的代碼里,我們需要注意一件事情,由于OnGameOver事件是被其他模塊所訪問的,因此如果像剛才寫的代碼那樣,定義一個delegate,把它定義成OnGameOver類型的對象,這時外部的程序模塊是無法訪問OnGameOver的

因為委托是一個變量,既然是PlayerHealth類的一個字段,就需要遵守類的規(guī)則,變量定義或者字段定義的默認情況下,類的字段是private私有的,外部訪問不到,委托也是一樣,因此需要把委托聲明成public,像右邊的代碼寫的這樣,這樣外部就能訂閱到OnGameOver的事件委托了

外部訂閱委托


假設(shè)有一個游戲的控制器,它是外部模塊,可以在游戲控制器開啟的時候,就是所謂OnEnable事件發(fā)生的時候,可以去訂閱PlayerHealth模塊的OnGameOver委托,用+=進行訂閱,當游戲結(jié)束或者游戲退出,禁用了游戲控制器模塊時,可以通過-=符號解除對OnGameOver委托的訂閱

這樣就實現(xiàn)了完整的觀察者模式,在觀察者模式當中有幾個要素

  • 第一個,需要定義一個事件型的委托,我稱之為事件委托

  • 第二個,在程序里面需要引發(fā)事件型的委托

  • 第三個,我們還需要有訂閱者,訂閱者就是GameController,它通過+=訂閱OnGameOver事件

所以對于觀察者模式事件的定義,事件的發(fā)布和事件的訂閱,三者缺一不可,如果在面試的時候,有面試官問什么是觀察者模式,就能達到觀察者模式基本的要點

但是有一個嚴重的問題!


雖然可以訂閱委托,但是有一個嚴重的問題,在進行團隊開發(fā)的時候,這個問題尤其嚴重,委托對象可以用+=進行訂閱,想象一下,現(xiàn)在有三個功能模塊,ABC三個模塊分別是由三個程序員開發(fā)

A程序員開發(fā)的A模塊用+=訂閱了onGameOver事件,B程序員也用+=訂閱了,但是C程序員,他覺得功能模塊里面ongameover的時候處理游戲退出,退出的時候認為游戲已經(jīng)結(jié)束了,于是就寫了onGameOver=null,把委托置為空

對于C程序員來說,他覺得這樣是沒有問題的,因為游戲已經(jīng)結(jié)束了,這個委托不再需要了,但是對于A和B程序員,也許會造成災(zāi)難,為什么呢?

  • 也許A和B程序員在游戲結(jié)束的時候,他倆開發(fā)的兩個模塊需要在游戲結(jié)束的時候做額外的處理

  • 假設(shè)C程序員寫的C模塊優(yōu)先執(zhí)行,由于C程序員已經(jīng)把onGameOver置為空了,再執(zhí)行A和B寫的模塊,這時A和B程序員就會發(fā)現(xiàn),他們雖然訂閱了onGameOver,但是他們倆寫的onGameOver的事件處理程序根本就執(zhí)行不到,在團隊開發(fā)的時候會造成一些程序的意外情況發(fā)生

解決方法:使用事件!


那怎么去避免這個意外情況發(fā)生呢?我們就需要對委托的使用進行約束,怎么約束呢?

  • 因為C#的開發(fā)者也發(fā)現(xiàn)了這個問題,所以他引入了一個所謂的事件機制,我們就可以用事件機制來解決這個問題,如果沒有事件機制,那架構(gòu)師就需要去手動解決這個問題

所以不管是C#語言層面有沒有事件的概念,作為開發(fā)者,要知道事件產(chǎn)生的原因是什么,先了解事件為什么能解決這個問題

  • 事件是一種特殊類型的特殊的多播委托,一般來說,它的工作方式與常規(guī)的委托是相同的,但是委托可以被其他的腳本調(diào)用,而事件(這邊說的事件委托就是事件)只能從自己所在的類當中觸發(fā)

  • 大家看圖中的程序代碼,比如這個程序代碼是前面GameController處理游戲場景的模塊,因為只有玩家模塊能夠能夠引發(fā)玩家死亡事件,所以GameController應(yīng)該是不能夠引發(fā)玩家死亡的,它只能處理玩家死亡

  • 所以在游戲控制GameControl模塊里,當我調(diào)用玩家的onGameOver事件時,必須要把它從委托改成事件,這時你會得到一個報錯的提醒,告訴你the event事件如果把onGameOver定義為事件,只能通過+=或者-=進行訂閱,但你不能在PlayerHealth玩家模塊之外對它進行調(diào)用,這樣就保證了事件調(diào)用的安全性,這也是使用事件的第一點好處

那我們?nèi)绾问褂檬录兀?/p>

事件的定義


比如前面定義的代理類型,寫一個onGameOver前面加Delegate關(guān)鍵字,這是代理也是委托的返回值,因為有些術(shù)語翻譯成委托,有些術(shù)語翻譯成代理,在這兒就不加區(qū)分了

那么如何把代理改成事件呢?

  • 方法很簡單,只需要把原來寫代理的第二行代碼加上event關(guān)鍵字就可以了

事件的本質(zhì)是什么呢?

  • 事件的本質(zhì)其實是對代理的包裝,它限制了引發(fā)代理的范圍只能在定義委托的程序模塊里引發(fā)委托,并且只能在外部模塊,比如GameControl模塊里面進行訂閱,而不能對它進行賦值,如果在這兒寫onGameOverr=null是會報錯的,所以這是使用事件的第二個好處

但是如果要使用一個事件,就必須要提前定義這個事件的委托類型,什么叫委托呢?

  • 說白了,定義委托實際上就是定義委托的訂閱者的規(guī)范,比如onGameOver可以有很多訂閱者,每個訂閱者寫的訂閱函數(shù)都必須是返回值為空,沒有參數(shù)的函數(shù),如果不是這樣,就不符合委托規(guī)則,這樣在程序的編譯階段,C#編譯器會在訂閱委托的時候報錯

  • 事件也是一樣的,如果要針對每個返回值是void,沒有參數(shù)的委托,起個名字定義委托類型太麻煩了,所以C#當中就給了兩種預(yù)定義事件的泛型類型

C#中兩種預(yù)定義的事件泛型


  • 如果是沒有返回值的委托,就直接寫Action,如果有參數(shù)就把參數(shù)寫在泛型的Action的尖括號(尖括號代表泛型)里,寫T1表示第一個參數(shù)的類型,T2表示第二個參數(shù)類型

  • 同理如果定義的事件泛型,定義的個事件委托類型是有返回值的,那就寫Func(表示函數(shù)的意思),第一個參數(shù)是這個函數(shù)的返回值,第二個參數(shù)是這個函數(shù)的第一個參數(shù),第三個類型是這個函數(shù)的第二個參數(shù),以此類推

  • 比如現(xiàn)在同樣寫OnGameOver函數(shù),如果這個函數(shù)在角色死亡的時候要說一句話,可以把要說的這句話在引發(fā)事件的時候通過函數(shù)的參數(shù)傳入,同時需要把事件的類型改成能夠傳參數(shù)的類型,那就直接寫Action(Sting)就可以了

Unity中預(yù)定義的事件類型


同樣unity當中也預(yù)定義了一些事件類型,比如處理玩家的死亡事件,如果對unity的事件類型比較熟悉,就知道可以定義UnityEvent,在unity的屬性面板上面,在PlayerHealth腳本上面可以看到定義的屬性叫On Player Death的事件,如果你寫的是C#的事件,在屬性面板上是看不到的,這就是unity預(yù)定義的事件跟C#的區(qū)別

并且它還有一個最本質(zhì)的區(qū)別,在面試的時候一定要注意,如果你只說unity定義的事件在屬性面板能看到,說明你還沒有理解它的本質(zhì),為什么在屬性面板能看到

  • 因為Unity所有在面板上能看到的屬性是可以序列化的,所以O(shè)n Player Death在UnityEvent最本質(zhì)的區(qū)別是能夠序列化,什么叫能夠序列化?

  • 就是當你在這兒設(shè)置了On Player Death的時間處理函數(shù),比如定義為DisableInput以后,當我把unity關(guān)掉,重新啟動unity以后,仍然可以看到設(shè)置的On Player Death的事件,處理函數(shù)還在,就是設(shè)置的DisableInput在


  • 而如果在這兒像上面一樣定義C#的action,那這時在屬性面板上面看不到onGameOver

  • 當unity重啟以后就算能看到,賦值的結(jié)果也會丟失,那么這個事件是沒有指向任何的處理函數(shù)的

定義自己的UnityEvent

當然也可以定義自己的UnityEvent,比如定義帶有浮點數(shù)參數(shù)的事件,可以從UnityEvent繼承,UnityEvent有好幾個版本,其中有帶一個參數(shù)的泛型版本,可以從UnityEvent,float去繼承

這個float是要填充的泛型參數(shù),表示它帶有一個參數(shù),這個參數(shù)是浮點數(shù)類型的,于是就可以根據(jù)FloatEvent的類型定義一個變量,這個變量叫onPlayerHurt,它可以在屬性面板上看到,可以指定一個參數(shù)

onPlayerHurt在圖上面是指向UpdateHealthBar函數(shù)的,大家注意,因為事件帶一個參數(shù),所以當你定義了一個事件處理程序叫做UpdateHealthBar的時候,這個UpdateHealthBar一定要帶有一個浮點類型的參數(shù)

如果這是一個沒有參數(shù)的UpdateHealthBar,它是不能作為onPlayerHurt事件的處理函數(shù)的

小結(jié)



大家能學到這兒,已經(jīng)達成了面試“委托和事件有什么區(qū)別?”這個問題的60%了,也就是可以拿60分了,現(xiàn)在我們總結(jié)一下,60分的目標里面究竟包括了委托和事件哪些區(qū)別?

  • 首先委托是使用Delegate關(guān)鍵字來進行聲明,而事件是使用Event關(guān)鍵字來證明

  • 第二,如果學過C++,那么你就知道前面講過委托相當于是一棟建筑,這棟建筑里面可以存很多的函數(shù),所以為什么它能存很多函數(shù)呢?

  • 因為委托的本質(zhì)實際上就是函數(shù)的指針數(shù)組,它在運行時保存了一個或者多個方法的引用


  • 當然具體它是怎么樣保存的,這就是你在面試時達成90%,九十分的問題回答,讓面試官對你刮目相看,這就需要進一步學習事件和委托的進階內(nèi)容

  • 而事件實際上是一種基于委托的通知機制,通俗來說,事件是對委托更加安全的包裝,所以委托是獨立的,它不依賴于事件,而事件依賴于委托,沒有委托就無法創(chuàng)建事件

  • 事件最主要的用途是為了防止用戶重置委托,賦值為空,并且防止在委托所在的程序模塊的外部進行調(diào)用,這就是事件比委托更安全的地方,也是為什么事件是對委托的包裝的原因

  • 第三個區(qū)別,如果去了解一下委托的底層原理,那你會知道委托是通過Combine()和Remove()方法實現(xiàn)多播的,而事件是通過AddEventHandler()和RemoveEventHandler()添加事件的處理程序

  • 第四,委托可以作為方法參數(shù)傳遞,這是非常重要的一點區(qū)別,比如寫一個麻將游戲,要比較麻將游戲里面的兩張牌的大小,這種比較規(guī)則是比較特殊的,于是可以自己把一個方法作為比較規(guī)則傳入,那這個方法怎么傳入呢?

  • 可以定義一個委托,把這個委托指向具體的比較的方法作為排序函數(shù)的參數(shù)進行傳入

  • 而事件是不可以的,事件只能作為類的字段成員,但不能作為方法的參數(shù),所以委托的用途其實比事件更加廣泛,事件比委托更加安全

這就是對前面內(nèi)容的總結(jié)

事件與委托進階

在面試的過程中,當然不希望在面試的時候只能拿零分,所以我們通過前面課程的學習,可以拿到面試中及格的表現(xiàn)

那么我們?nèi)绾文玫揭粋€進階的表現(xiàn),讓面試官能夠這個刮目相看,甚至能達到一些面試官都不太了解的內(nèi)容呢?在學習的過程中,如果能注意我講的這些點,因為一面的面試官可能相對工作經(jīng)驗沒有那么豐富,你甚至可以回答一些一面的面試官都不怎么了解的內(nèi)容

這樣對于同學的面試是非常有利的,這其實還牽涉到一些具體的面試技巧,我會在面試模擬環(huán)節(jié),幫大家做具體的指導,如果你想拿到關(guān)于事件與委托面試90分的回答,那么你需要了解

  • 多播委托的原理,它的底層的技術(shù)實現(xiàn),因為我們在二面的時候往往是由一些項目的組長負責人幫我們面試的,所以在二面的時候,面試官會對技術(shù)進行深挖,所以掌握多播委托的原理是非常重要的

  • 我們知道多波委托是一個委托可以指向多個方法,那么我們?nèi)绾稳〉盟蟹椒ǖ姆祷刂的兀恳苍S你沒有深入的使用過多播委托,甚至都不理解講的這個問題是什么意思,那在面試的時候?qū)τ谶@個問題就掛掉了,所以這個問題也是我們需要進階了解的問題

  • 委托除了能夠用在一些同步調(diào)用的環(huán)境下,也可以用在一些異步調(diào)用的環(huán)境下,那么在異步調(diào)用的環(huán)境下,我們?nèi)绾问褂梦心??這是我們的第三個問題

  • 大家知道事件是比委托更加安全的,它是對委托的包裝,那么在C#底層在C#內(nèi)部,它是如何做到只讓事件在內(nèi)部被引發(fā)的呢?

關(guān)于這四個問題,希望大家能夠做深入的思考,也歡迎大家在討論區(qū)留言,我也會給大家一一回復(fù),更進一步的技術(shù)討論大家可以去加文末助教老師alice的聯(lián)系方式,同時我也會在直播間給大家做進一步的技術(shù)分享

另外同學們可能會問如果想達到面試剩下的10%,怎么辦呢?

首先需要有項目實踐,而不僅僅是背一些面試題,這肯定是不夠的,也需要經(jīng)歷完整的面試準備周期,老師會在系統(tǒng)課程,會在面試模擬環(huán)節(jié)里面幫助大家做一些準備

我這還準備了一些20K+的面試題精講,幫助想要高薪入行的同學做好技術(shù)面試的準備工作,同時也會有一些面向在職開發(fā)同學的30K+的面試題精講,也歡迎大家加文末助教老師的聯(lián)系方式,了解相關(guān)的學習內(nèi)容

寫在最后

更多學習資源請私信我獲?。ㄆ髽I(yè)級性能優(yōu)化/熱更新/Shader特效/服務(wù)器/商業(yè)項目實戰(zhàn)/每周直播/一對一指導)

點贊、關(guān)注、分享可免費獲得配套學習資源

完整視頻請觀看



委托與事件的評論 (共 條)

分享到微博請遵守國家法律
广安市| 怀安县| 苗栗县| 阳城县| 滕州市| 新闻| 松江区| 桑日县| 瑞丽市| 华阴市| 富民县| 绥宁县| 巴林左旗| 古丈县| 集安市| 辰溪县| 临湘市| 文登市| 南安市| 桂平市| 分宜县| 南充市| 山西省| 烟台市| 巫溪县| 嘉荫县| 定襄县| 报价| 霍州市| 视频| 密云县| 二手房| 财经| 南皮县| 丹凤县| 孙吴县| 大化| 上思县| 南澳县| 岳普湖县| 崇左市|