godot gui_input event處理機(jī)制

在這里記錄并分享一下 godot 的 gui 中 event 是如何被傳遞和處理的 。
簡(jiǎn)單設(shè)置如下圖場(chǎng)景,并使用同一個(gè)腳本用于在鼠標(biāo)左鍵點(diǎn)擊時(shí)捕獲對(duì)應(yīng)信息。

事件處理函數(shù)
godot主要有三種事件處理函數(shù) input(), gui_input(), unhandled_input()
并且會(huì)依次按照 input() -> gui_input() -> unhandled_input() 的順序執(zhí)行, 即所有對(duì)象執(zhí)行完 input() 后才會(huì)調(diào)用 gui_input(),所有對(duì)象 gui_input() 判定結(jié)束后再調(diào)用 unhandled_input()。
==在事件處理代碼中使用 accept_event() 會(huì)強(qiáng)制停止事件繼續(xù)傳遞。==
注意:gui_input() 方法是 Control 對(duì)象的方法,而 input() 和 unhandled_input() 都是 Node 對(duì)象的方法。(Control 繼承自 Node)。
邏輯上其他 Node 對(duì)象雖然沒(méi)有g(shù)ui_input() 方法,但用 input()方法可以攔截傳往 Control 的事件(通過(guò)accept_event())進(jìn)而阻止 gui_input() 的調(diào)用,
所以官方推薦在非 Control 節(jié)點(diǎn)中使用 unhandled_input() 而非 input()方法。
1. input()
反向遍歷所有節(jié)點(diǎn)。
測(cè)試:在空白處點(diǎn)擊鼠標(biāo)查看 Input 函數(shù)的執(zhí)行結(jié)果
# 打印出來(lái)的結(jié)果Input : P4-Blue
Input : P3-Green
Input : P2-Red
Input : P1-White
Input : Root

可以看到事件是從節(jié)點(diǎn)樹(shù)的根部依次向上傳遞的,P4 -> P3 -> P2 -> P1 -> Root 。
==gui_input() 和 unhandled_input() 的執(zhí)行順序也是如此。==
2. gui_input()
gui_input() 就開(kāi)始變的稍微復(fù)雜了。
不像input() ,并不是所有對(duì)象都會(huì)調(diào)用 gui_input()。
是否調(diào)用 gui_input() 由 mouse_filter 屬性決定的,并且 觸發(fā)事件時(shí) 鼠標(biāo)位置必須在對(duì)象范圍內(nèi)部 ( ’觸發(fā)事件時(shí)‘ 這個(gè)前提很重要,因?yàn)槭髽?biāo)不在區(qū)域內(nèi)也有可能調(diào)用 gui_input(),下面會(huì)講到 )。

mouse_filter 有三個(gè)值分別為:
Stop: 事件在當(dāng)前節(jié)點(diǎn)調(diào)用 gui_input() 后停止繼續(xù)傳遞。
Pass: 當(dāng)事件可以傳遞到當(dāng)前對(duì)象,調(diào)用 gui_input() 之后再將事件上傳給父級(jí)處理。
注意:這里是直接傳給父級(jí),在事件被處理前會(huì)一層一層向上傳直到節(jié)點(diǎn)樹(shù)的 Root 對(duì)象
Ignore: 無(wú)視當(dāng)前對(duì)象,gui_input()不會(huì)被調(diào)用。
個(gè)人感覺(jué)這里面 Pass 最容易翻車,通過(guò)測(cè)試來(lái)說(shuō)明。
測(cè)試:藍(lán)色(P4) mouse_filter 改成 Pass, 其余全部改成Stop, 點(diǎn)擊藍(lán)色(P4)和白色(P1)相疊加的區(qū)域(下圖中的紅色叉位置),事件是怎么傳遞的呢?

# 打印出來(lái)的結(jié)果Input : P4-Blue
Input : P3-Green
Input : P2-Red
Input : P1-White
Input : Root
?gui_input : P4-Blue ?mouse_filter: Pass
?gui_input : P3-Green ?mouse_filter: Stop
在我一開(kāi)始的想法里既然藍(lán)色Pass了那應(yīng)該是白色接受這個(gè)事件,但Pass的作用不是穿透對(duì)象而是在調(diào)用 gui_input() 后直接把事件傳遞給父級(jí)(P3 綠色)判定。
父級(jí)是Stop所以調(diào)用父級(jí)的gui_input后直接停止傳遞。
如果我把父級(jí)(P3 綠色)也改成Pass呢?答案是顯而易見(jiàn)的,P4 藍(lán)色 -> P3 綠色 -> Root ,事件最終轉(zhuǎn)交給Root。
當(dāng)事件沒(méi)有被任何 gui_input() 使用時(shí)事件開(kāi)始傳遞到 unhandled_input () 中。
注意: Clip Contents會(huì)影響事件的捕獲。

3. unhandled_input
unhandled_input() 就非常簡(jiǎn)單了。只有事件沒(méi)有被任何 input() 或者 gui_input() 消費(fèi)(accept_event() 或者在 gui_input() 中被 stop),unhandled_input()才會(huì)開(kāi)始執(zhí)行 。
如有錯(cuò)誤或者更多有用的內(nèi)容,歡迎其他朋友補(bǔ)充指正~