事件(Event)
- 事件是C#饋贈我們的禮物,是將委託的多播功能進行封裝後的工具類型。
這句話怎麼理解呢?其實事件本質上是一種多播的委託,
什麼是事件?
- 一個對象在完成某個工作後,或者發生了某種操作後,需要通知其他對象,從而做出反應;發送出去的通知就是事件。
案例1:火箭發射-火箭飛了
當你按下這個按鈕之後,一按,這個火箭就開始起飛,是吧,那「按下按鈕」這件事呢,就是從而構成了一個實踐,對吧。
案例2:玩家AOE技能攻擊-敵人減血
比如說,在遊戲當中,你看中間的這樣一個玩家,他會釋放一種技能叫做AOE,AOE就是這個大範圍的廣範圍的攻擊,他這麼一打,是不是周邊的這些敵人都受到了他的攻擊啊,這種技能呢,可以理解成一種實踐。
怎麼說呢,你看,中間的玩家圍了一圈的敵人要攻擊玩家,這個時候呢,你搞一個AOE技能,然後呢,向所有的敵人發送了一個事件說:「哈哈,你在我們攻擊範圍之內,所以說呢,我要揍你了。」
這些敵人呢,收到「你要揍我」這個事件之後,好吧,我要幹嘛呢?集體減血啊,你看,啪啪啪都減了100血。
那玩家執行了AOE這樣一個技能操作之後,然後呢,向這些敵人所發送的這些消息啊,可以稱之為「事件 Event」。
AOE 技能如果不使用事件,應該怎麼寫呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
class Enemy {
private int blood = 100; //血量
public void MinusBlood(int attack) {
blood -= attack;
}
}
class Player {
public void DoAOE(Enemy[] enemies) {
foreach(Enemy e in enemies) {
e.MinusBlood(10);
}
}
}
這樣的寫法會有什麼樣的問題:
- 當
Enemy中的MinusBlood()更改了名字,Player的程式碼也需要隨之更改。
這種情況下,我們就稱之為二者耦合了,
Player耦合於Enemy,當Enemy被改變了,Player就被迫於要更改,這樣的設計其實是不好的。
Player類中,顯式調用了Enemy類的方法,則Player的程式碼依賴Enemy類,構成了耦合關係。
我們的目標是「解耦合」,讓玩家不再依賴於敵人,要怎麼實現呢?
AOE技能如何能夠「解耦合」呢?
Enemy 敵人
1
2
3
4
5
6
class Enemy {
private int blood = 100;
public void MinusBlood(int attack) {
blood -= attack;
}
}
Player 玩家
1
2
3
4
5
6
7
8
9
10
class Player {
public delegate void OnAttackDelegate(int attack);
public OnAttackDelegate OnAttack = null;
......(一堆屬性)
public void DoAOE() {
if(OnAttack != null) {
OnAttack(10);
}
}
}
- Player 類裡面聲明了一個委託的方法類型,看這個類型是怎樣的呢?它要求這樣一個方法是傳入一個
int類型的數值,返回的是一個void,就是沒有返回值。而這一類方法我們把它統稱為OnAttackDelegate。 - 隨後呢,咱們聲明了一個
OnAttackDelegate類型的委託對象/物件叫做OnAttack,然後一開始等於null。 - 之後呢,咱們
DoAOE()這個方法是這麼來寫的:如果OnAttack不等於null,就是咱們這個OnAttack委託,如果說已經被設置了一些委託進去了,那裡面已經有一個,或是多個方法被委託到他們這個OnAttack裡面了,那這個時候它就不是null了,那麼咱們就可以直接調用OnAttack這樣的委託,然後呢,把這個攻擊的數值傳進去。
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//玩家
Player player = new Player();
//敵人
Enemy e0 = new Enemy();
Enemy e1 = new Enemy();
Enemy e2 = new Enemy();
//委託的多播
//三個敵人物件的MinusBlood都被收錄到OnAttack委託裡
player.OnAttack += e0.MinusBlood;
player.OnAttack += e1.MinusBlood;
player.OnAttack += e2.MinusBlood;
//使用AOE技能
player.DoAOE();
實作
需求:
- Player Class: 能夠釋放AOE範圍攻擊技能,讓波及到的敵人統一減血10滴
- Enemy Class: 能夠對外提供減血的方法函數,供外界調用
耦合版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
namespace SeniorEvent
{
//需求:
// 1 Player Class: 能夠釋放AOE範圍攻擊技能,讓波及到的敵人統一減血10滴
// 2 Enemy Class: 能夠對外提供減血的方法函數,供外界調用
class Enemy {
private int blood = 100;
public void MinusBlood(int attack) {
blood -= attack;
}
}
//耦合版本
class Player {
public void DoAOE(Enemy[] enemies) {
foreach (Enemy e in enemies) {
e.MinusBlood(10);
}
}
}
internal class Program
{
static void Main(string[] args)
{
Player player = new Player();
Enemy e0 = new Enemy();
Enemy e1 = new Enemy();
Enemy e2 = new Enemy();
Enemy[] enemies = { e0, e1, e2 };
player.DoAOE(enemies);
}
}
}
使用委託解耦合
在 Player 當中聲明委託類型,將需要調用的減血方法,在Player 類別外設給內部的委託
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
namespace SeniorEvent
{
//需求:
// 1 Player Class: 能夠釋放AOE範圍攻擊技能,讓波及到的敵人統一減血10滴
// 2 Enemy Class: 能夠對外提供減血的方法函數,供外界調用
//敵人
class Enemy {
private int blood = 100;
public void MinusBlood(int attack) {
Console.WriteLine("好疼,我是Enemy");
blood -= attack;
}
}
//非玩家角色
class NPC {
private int blood = 100;
public void BeAttacked(int attack) {
Console.WriteLine("好疼,我是NPC");
blood -= attack;
}
}
//使用委託解耦合
//在 Player 當中聲明委託類型,將需要調用的減血方法,在 Player 類別外設給內部的委託
class Player
{
//聲明委託,用來規定減血的方法 應該符合怎麼樣的 方法簽名
public delegate void OnAttackDelegate(int attack);
//聲明OnAttackDelegate類型的委託
public OnAttackDelegate OnAttack = null;
public void DoAOE() {
if (OnAttack != null) {
OnAttack(10);
}
}
}
internal class Program
{
static void Main(string[] args)
{
Player player = new Player();
Enemy e0 = new Enemy();
Enemy e1 = new Enemy();
Enemy e2 = new Enemy();
NPC npc = new NPC();
//player.OnAttack 是 Player內部甩出外界的一個委託
player.OnAttack += e0.MinusBlood;
player.OnAttack += e1.MinusBlood;
player.OnAttack += e2.MinusBlood;
player.OnAttack += npc.BeAttacked;
player.DoAOE();
Console.Read();
}
}
}
- 玩家
Player就不再依賴敵人Enemy,還可以跨種族的攻擊。 player.OnAttack是Player內部甩出外界的一個「委託」,這個player要去攻擊別人的時候,會去調用這個OnAttack這個委託。- 於是乎,我可以把受到這個
player攻擊的方法,把它加入到這個OnAttack裡面,這個含義
命名規則 「On什麼什麼東西」
比如說,Player這個類別裡面發生一些事情,發生事情之後,他要去做一些事,例如耍一些技能,他就需要去向外界做出一些通知,對吧。
所以說,這一類的「委託方法」,或者說這個「回調方法」,我們一般都叫「On什麼什麼東西」。
比如說,OnAttack其實是可以翻譯成:「在我攻擊的時候」,對吧。還有OnClick,這個是一般按鈕都會有的一個委託方法,那它翻譯過來就是,「在我被點擊的時候」。
放在專案裡面:
OnClick就是:在我被點擊的時候所調用的方法。OnAttack在我被攻擊的時候所調用的方法集合。
1
2
3
4
//OnAttack在我被攻擊的時候所調用的方法集合
public OnAttackDelegate OnAttack = null;
//OnClick在我被點擊的時候所調用的方法
public OnClickDelegate OnClick = null;
發散思維
假設我攻擊敵人後,敵人發動被動技能-背刺,就是,你打我,我背上有穿上背刺穿甲,你這個拳打到我身上,我扎到你了,是不是你也得掉血啊。
也就是說,誰攻擊了我,那麼,攻擊我的那個人呢,也需要掉血啊, 這就是「背刺功能」。
你看,這個Player Class做了一個AOE技能,然後去調用了每一個MinusBlood()的方法,然後調用到這裡MinusBlood,敵人要先減血,因為敵人被 player 揍了嘛。
那如果敵人要發動被動技能-背刺,那應該怎麼去給player減血呢?你看,在MinusBlood()這個方法的整個作用域的範圍之內,並沒有拿到是誰在功擊我這樣一個對象。
如果說,你能傳進來一個參數就好了,比如傳進一個player這個參數,我就知道是這個傢伙,他攻擊了我這麼多的點數,然後我就可以直接去攻擊這個player了,對吧,可惜,它並沒有這個東西。
所以說呢,咱們的想想辦法了,如何能夠在這樣一個多播的調用當中,來告訴那些被調用的方法,到底是誰在攻擊他們。
##
委託類型 再加上 object o 參數
加上 object o 參數,也就是說,咱們這個 OnAttack()方法在調用的時候,第一個參數需要傳一個object類型的對象/物件進去。
object是一切class的父類型
1
2
//這個委託的方法必須是void,需要傳入兩個參數
public delegate void OnAttackDelegate(object o, int attack);
這樣,我是不是可以把我當前這個誰調用 AOE的玩家對象給他傳進去呀。
那誰調用這個 AOE呀,是不是this,我們是不是可以用this這個關鍵字,當player調用內部的AOE(),用this就可以表示當前這個player對象了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//使用委託解耦合
//在 Player 當中聲明委託類型,將需要調用的減血方法,在 Player 類別外設給內部的委託
class Player
{
//聲明委託,用來規定減血的方法 應該符合怎麼樣的 方法簽名
public delegate void OnAttackDelegate(object o, int attack); //加上object參數
//聲明OnAttackDelegate類型的委託
public OnAttackDelegate OnAttack = null;
public void DoAOE() {
if (OnAttack != null) {
OnAttack(this,10); //this表示當前這個player玩家
}
}
}
OnAttack(this,10);
- 第一個參數是
object類型,我們要傳進去的,其實是當前的這個玩家對象/物件,可以用this - 第二個參數
attack攻擊數值
這時候,還得再思考一個問題,當我定義委託方法加上一個object參數後,下面加入委託中的所有方法,都需要加上object參數。
1
2
3
4
//Enemy
public void MinusBlood(object o, int attack) { ... }
//NPC
public void BeAttacked(object o, int attack) { ... }
再思考一下
再思考一下,就是說,咱們的玩家在做AOE群攻的時候,可能不光只是讓Enemy們去掉血,有可能還會帶毒,「帶毒」什麼意思,就是我釋放了一個AOE技能,你被我打到了,打到了之後,首先你會扣他十滴血,然後呢,我就跑了,在跑的過程當中,你們這些被我打過的這些敵人們,每隔一秒鐘都可能會被我毒傷,掉一滴血,這樣子。
所以說,我們在DoAOE技能,咱們需要給化再傳一個參數進去,傳什麼參數呢?傳是否中毒。
好,我們這事啊從 Enemy開始說起:先加上一個參數poisoned
1
public void MinusBlood(object o, int attack, bool poisoned) { ... }
想一想,這樣是相當於改變了這個方法的參數列表,我這裡的參數列表一變,你想想,下面是不是直接又要報錯了呀。
為什麼呀,因為我這委託只提供兩個參數:object、attack,對吧,那怎麼辦咧?再修改一次…
因為咱們加了一個效果,或者說策劃他想了一個歪歪點子,這個AOE其實是可以讓這個周圍的敵人中毒的,你看,能不能怎麼改一下呀,改好後呢,又一個需求呃,是否進入「眩暈狀態」,那是不是又要再加一個參數,定義委託、委託方法和所有的被加人委託的方法,是不是又要再加一個參數。
因為 delegate加了一個參數,所有對應的方法,又得加參數,對吧,所以,我們有沒有什麼招,能夠去解決這個問題呢?或者讓這個問題變得簡單一點呢?
問題:委託方法的參數太多,且會經常變動
- 問題:委託方法,需要攜帶的參數太多了,參數還會經常變動
- 方法:將所有的參數都包含到一個
class裡面
將所有的參數都給他封裝到一個叫做EventArgs類裡面
EventArgs、Player class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class EventArgs //事件參數們
{
public int attack = 10; //攻擊減血量
public bool poisoned = false; //中毒
}
//使用委託解耦合
//在 Player 當中聲明委託類型,將需要調用的減血方法,在 Player 類別外設給內部的委託
class Player
{
//聲明委託,用來規定減血的方法 應該符合怎麼樣的 方法簽名
public delegate void OnAttackDelegate(object o, EventArgs args);
//聲明OnAttackDelegate類型的委託
public OnAttackDelegate OnAttack = null;
public void DoAOE()
{
if (OnAttack != null)
{
EventArgs args = new EventArgs();
args.attack = 10;
args.poisoned = true;
OnAttack(this, args);
}
}
public void Shout()
{
Console.WriteLine("玩家很痛!");
}
}
Enemy class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//敵人
class Enemy
{
private int blood = 100;
public void MinusBlood(object o, EventArgs args)
{
Console.WriteLine("好疼,我是Enemy");
blood -= args.attack; //減血
//判斷是否中毒
if (args.poisoned)
{
Console.WriteLine("Enemy中毒了");
}
//我發動被動功能 背刺
Player player = (Player)o;
player.Shout();
}
}
NPC class
1
2
3
4
5
6
7
8
9
10
//非玩家角色
class NPC
{
private int blood = 100;
public void BeAttacked(object o, EventArgs args)
{
Console.WriteLine("好疼,我是NPC");
blood -= args.attack;
}
}
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
namespace SeniorEvent
{
//需求:
// 1 Player Class: 能夠釋放AOE範圍攻擊技能,讓波及到的敵人統一減血10滴
// 2 Enemy Class: 能夠對外提供減血的方法函數,供外界調用
//問題:委託方法,需要攜帶的參數太多了,參數還會經常變動
//方法:將所有的參數都包含到一個class裡面
class EventArgs //事件參數們
{
public int attack = 10; //攻擊減血量
public bool poisoned = false; //中毒
public bool headache = false; //眩暈
}
//敵人
class Enemy
{
private int blood = 100;
public void MinusBlood(object o, EventArgs args)
{
Console.WriteLine("好疼,我是Enemy");
blood -= args.attack; //減血
//判斷是否中毒
if (args.poisoned) {
Console.WriteLine("Enemy中毒了");
}
//判斷是否眩暈
if (args.headache) {
Console.WriteLine("Enemy眩暈了");
}
//我發動被動功能 背刺
Player player = (Player)o;
player.Shout();
}
}
//非玩家角色
class NPC
{
private int blood = 100;
public void BeAttacked(object o, EventArgs args)
{
Console.WriteLine("好疼,我是NPC");
blood -= args.attack;
}
}
//使用委託解耦合
//在 Player 當中聲明委託類型,將需要調用的減血方法,在 Player 類別外設給內部的委託
class Player
{
//聲明委託,用來規定減血的方法 應該符合怎麼樣的 方法簽名
public delegate void OnAttackDelegate(object o, EventArgs args);
//聲明OnAttackDelegate類型的委託
public OnAttackDelegate OnAttack = null;
public void DoAOE()
{
if (OnAttack != null)
{
EventArgs args = new EventArgs();
args.attack = 10;
args.poisoned = true;
args.headache = true;
OnAttack(this, args);
}
}
public void Shout()
{
Console.WriteLine("玩家很痛!");
}
}
internal class Program
{
static void Main(string[] args)
{
Player player = new Player();
Enemy e0 = new Enemy();
Enemy e1 = new Enemy();
Enemy e2 = new Enemy();
NPC npc = new NPC();
player.OnAttack += e0.MinusBlood;
player.OnAttack += e1.MinusBlood;
player.OnAttack += e2.MinusBlood;
player.OnAttack += npc.BeAttacked;
player.DoAOE();
Console.Read();
}
}
}
AOE技能如何能夠解耦合呢?
- 在
Player做了一次折分:- 在裡面做了一個
delegate委託OnAttackDelegate - 然後做了一個委託對象/物件叫做
OnAttack - 然後將一大堆方法都加到了
OnAttack裡面了
- 在裡面做了一個
- 隨後提了需求:
Enmey希望知道誰攻擊他Enmey希望知道一些額外數據(是否中毒/眩暈等)
- 所以對整個架構做了一個改變:
- 首先呢,咱們定義了一個叫做做
EventArgs的class - 在這裡面,咱們將這個受害者,他所想知道的一切信息,都給他封裝到了這個
EventArgs裡面
- 首先呢,咱們定義了一個叫做做
- 其次吧,咱們將
Player施暴者,他裡面的這個OnAttackDelegate做了改變:- 讓他能夠向外傳導一個
object, 而且向外傳導一個EventArgs對象。 - 在這裡面,
object其實就是他自己,將這個施暴者或者攻擊者自己給放進去OnAttack(this, args) - 然後
args的話,在這裡new了一個EventArgs,將本次攻擊相關的一些參數,都填寫到了args裡面,把args傳出去。
- 讓他能夠向外傳導一個
- 隨後咱們在這個接收端
Enemy裡面:- 咱們
MinusBlood()是接收一個object、接受一個EventArgs - 然後根據咱們接收到的這個攻擊者是誰,攻擊參數是怎樣的,可以在這裡面做各式各樣的邏輯判斷
- 咱們
EventHandler 真正的偷懶(工程師進步的階梯)
1
2
3
4
class Player {
public delegate void OnAttackDelegate(object o, EventArgs e);
public OnAttackDelegate OnAttack = null;
}
我們不是定義一個委託叫做OnAttackDelegate,他裡面傳了一個 object,這個object就是,誰發出了這個事件,比如說,Player發出了攻擊,那他就是事件的一個發出者,然後發出者是不是還攜帶了一個叫EvnetArgs的這樣一個參數包,然後,我們再用 OnAttackDelegate 定義了一個OnAttack這樣的委託對象/物件,對吧。
事件專用委託定義 EventHandler
C# 為我們寫好了事件專用委託定義
其實C#已經為我們在全局層面上定義好了這樣的委託類型
1
2
3
//sender: 誰發出這個事件
//EventArgs: 微軟為我們寫了的參數包
public delegate void EventHander(object? sender, EventArgs e);
既然微軟都幫我們寫好了EventArgs參數包,我們直接拿來用不就完事了呀,我還需要再去聲明一個 xxx delegate 類型嗎,不需要了。
我直接用微軟定義好的EventHandler這樣的委託類型,直接聲明一個委託對象/物件Onattack不就完事了嗎
1
2
3
class Player {
public EventHandler Onattack = null;
}
進一步思考事件:
事件對應的委託,「不應該」被類別外界調用,只能由某個操作觸發
OnAttack()裡有很多的方法,必須使用技能才會觸發的。如果哪天某個程式員在外界調了一下OnAttack(),周圍的怪物都減血了,那這就奇怪了,玩家跑一跑,這周圍的這個怪物都減血了,太神奇了,是不是開外掛了。
那真正意義上應該怎麼做呢?
我們應該在外界調用 DoAOE(),由DoAOE()內部去調用OnAttack()才對。
- 第一個思考點:類內部應該有個事件,而這個事件他所對應的委託,不應該被類外部調用的,只能由某個操作觸發
事件對應的委託,「不應該」被類外界直接賦值,只能夠通過 +、-增減委託方法
1
2
Player player = new Player();
player.OnAttack += 某方法
事件委託 event
- 為了能夠滿足兩個條件:
- 事件對應的委託,「不應該」被類外界調用,只能由某個操作觸發
- 事件對應的委託,「不應該」被類外界直接賦值,只能夠通過
+、-增減委託方法
1
2
3
class Player {
public event EventHandler OnAttack = null;
}
event關鍵字,讓委託升級了,變成了「事件委託」。
Event事件規則- 加
event關鍵字修飾的委託,只能夠定義在某個類內 - 加
event關鍵字修飾的委託,只能夠被當前類別方法觸發執行,類外不可觸發執行 - 加
event關鍵字修飾的委託,只能通過+、-增減委託方法,不可賦值
- 加
程式碼練習 event, EventHandler
- 事件(Event關鍵字)
event修飾了一個委託,其實是給這個委託升級了,給他加了兩個規則:
- 只能被類內調用執行
- 只能通過
+=、-+方式去加減所蘊含的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
* Event(事件)
* 1 event修飾的委託,只能在類內調用執行,類外不可調用的
* 2 event修飾的委託,不能直接賦值,只能通過+、-增減其中蘊含的方法
*/
namespace EventTest
{
class Player {
//定義Player內部會被觸發的事件委託
public event EventHandler OnAttack = null;
public void DoAOE() {
if (OnAttack != null) {
OnAttack(this, EventArgs.Empty);
}
}
}
class Enemy {
//定義可以被加到OnAttack委託當中的方法
public void AttackMe(object sender, EventArgs e) {
Console.WriteLine("我被攻擊了!");
}
}
internal class Program
{
static void Main(string[] args)
{
Player player = new Player();
Enemy enemy = new Enemy();
//沒有加上event關鍵字,會有兩種錯誤寫法
//1.在類外直接調用event修飾的委託,是禁止的
//player.OnAttack(new object(), EventArgs.Empty);//錯誤寫法1
//2.直接賦值是禁止的
//EventHandler handler = new EventHandler(enemy.AttackMe);
//player.OnAttack = handler;//錯誤寫法: 直接賦值
//handler(new object(), EventArgs.Empty); //錯誤寫法: 類外直接調用
player.OnAttack += enemy.AttackMe;
player.DoAOE();
Console.Read();
}
}
}
總結
事件中的角色
事件運行流程,需要先定義一個事件,然後呢,每一個需要去訂閱該事件的對象,你也得有一些處理的方式,當事件觸發之後,會連加連拖帶口的給你全部都送過來了,把這些相關的參數、時間對象,就扔到咱們的每一個訂閱者的處理方法裡面,你們各自去處理吧,愛怎麼做就怎麼做,我也不管你,我就告訴你,我觸發了這個事件了。
咱們有「玩家」、「敵人」兩個class,他們兩個也會被new成兩個對象/物件:
- 玩家:稱為「事件源對象」
Event Source。因為是玩家發了AOE技能才迫使OnAttack這種事件發生的,所以說,人家他是「事件源」。 - 敵人:叫做「響應對象」或者是「訂閱者對象」
Event Subscriber,就好像你訂報紙一樣,交上報錢報紙來了,就給你送過來了,沒有報紙沒不會送過來了。 - 事件(
event)-OnAttack:然後玩家有一個OnAttack,這個OnAttack是被event所修飾的,所以他就叫做「事件(event)」。 - 事件處理方法(
EventHandler):然後敵人有一個AttackMe()方法,它是被加到了OnAttack這個委託裡面,所以AttackMe()又稱為叫做「事件處理的方法」。 - 也就是說,當
OnAttack這個事件觸發的時候,他會調用每一個敵人的AttackMe()這樣的方法去處理這個事件,所以他叫做「事件處理方法」。 +=訂閱該事件(Subscribe): 我們用這樣的「事件處理方法」去訂閱了OnAttack這樣的事件,其實呢,通過的是一個+=這樣的符號,將AttackMe()加到了OnAttack這個委託裡面。- 所以,換句話說,咱們的敵人呀,通過
AttackMe()這樣的事件處理方式,訂閱了OnAttack這樣的事件。 - 事件觸發:接下來,當
OnAttack被觸發的時候,什麼叫做「被觸發」呀?就是玩家DoAOE()的時候呀,發使用AOE技能DoAOE()啦,然後就會直接觸發OnAttack這樣的事件。 - 這個事件觸發之後,就會調用
AttackMe()這樣的事件處理方法。 - 然後在事件觸發的過程當中,需要傳導參數,我們傳導了兩個參數:「事件源對象
object o」、「事件參數EventArgs e」給到了AttackMe()這樣的方法。- 事件源對象
object o:在AttackMe()方法裡面,他得知道誰攻擊了我,所以就是object o - 事件參數
EventArgs e:然後通過EventArgs事件包,傳一些參數過去。
- 事件源對象












