UPBGE - Blender 游戲引擎繼承者

UPBGE 游戲開(kāi)發(fā)系列教程:
#????UPBGE?- Blender 游戲引擎繼承者
## ???UPBGE?Python?Scripting?
## ?? Logic Nodes (源代碼分析)
## ?? Script Lifecycle (源代碼分析)
## ?? UPBGE Python API (源代碼分析)
UPBGE 作為 Bledner BGE 引擎的繼承者,直接基于 Blender 源代碼開(kāi)發(fā),集成度更高。Armory3D 開(kāi)發(fā)團(tuán)隊(duì)自從 ArmoryPaint 工具獲 EPIC Games 大獎(jiǎng)后,重心似乎也偏向它了:
簡(jiǎn)而言之:
1. Armory3D 基于 Haxe 語(yǔ)言和 Kha 底層 HAL 硬件抽象層實(shí)現(xiàn)跨平臺(tái)!
2. UPBGE 與 Blender 一體,Python 加邏輯節(jié)點(diǎn)編程,所見(jiàn)即所得,Grease Pencil,支持的!
源文檔:https://github.com/Jeangowhy/opendocs/blob/main/upbge.md
Armory3D 使用 Armory2D + Zui 制作用戶界面。UPBGE 有 Game GUI (bgui) 模塊,需要另行安裝。UPBGE + Blender 完全融合根本不需要這樣的工具,直接使用場(chǎng)景建模、蠟筆繪畫都是可以直接使用的工具,再有 UPBGE 提供的邏輯節(jié)點(diǎn)編程工具。或者直接使用 Python 組件擴(kuò)展,甚至是 C/C++ 開(kāi)發(fā)擴(kuò)展庫(kù)。
UPBGE 開(kāi)發(fā)中有些不太便利的功能,就是看一個(gè)腳本組件卻無(wú)法直接了解到它會(huì)被掛載到哪個(gè)對(duì)象上。通過(guò) Game object 屬性面板中查看腳本組件時(shí),只能看到組件名稱,如果組件命名不規(guī)范,那么也可能找不到相應(yīng)的腳本,因?yàn)椴荒苤苯有薷幕蚓庉?。所以,腳本起名就是個(gè)考驗(yàn),不要讓自己在場(chǎng)景中迷失。如果腳本有更新,那么還需要在已經(jīng)掛載的對(duì)象上刷新腳本內(nèi)容,否則依然使用舊的代碼實(shí)現(xiàn)的功能,即使重新打開(kāi)工程也一樣不會(huì)自動(dòng)更新。
下載安裝 UPBGE 并運(yùn)行,``Edit -> Preferences -> Add-ons`` 啟用以下以下插件:
#. Game Engine: `Logic Nodes` 邏輯節(jié)點(diǎn)編輯器。
#. Game Engine: `Easy Online` 多人連網(wǎng)游戲插件。
#. Improt-Export: `Save As Game Engine Runtime` 游戲項(xiàng)目導(dǎo)出。
導(dǎo)出獨(dú)立程序:File --> Export --> Save As Game Engine Runtime
`Easy Online` 會(huì)向腳本編輯器復(fù)制兩個(gè)腳本 serevr.py 和 client.py,以及一個(gè)說(shuō)明文檔。
注意:在 UPBGE 程序崩潰后,插件可能被自動(dòng)禁用,這會(huì)導(dǎo)致邏輯節(jié)點(diǎn)出現(xiàn) Undefined 的節(jié)點(diǎn)和插槽。
UPBGE 有三大編程工具,選擇 Blender 場(chǎng)景中的對(duì)象就可以添加這些設(shè)置:
1. Logic Bricks 邏輯磚,如其名,提供了一套現(xiàn)成的邏輯供調(diào)用,邏輯磚有三類,依次連接起來(lái)使用:
? ? 1. **傳感器** 用來(lái)接收硬件輸入、或抽象信號(hào)產(chǎn)生游戲控制流。 sensors/index.rst
? ? 2. **控制器** 用來(lái)做邏輯判定,滿足邏輯條件就調(diào)用執(zhí)行器節(jié)點(diǎn)。 controllers/index.rst
? ? 3. **執(zhí)行器** 通過(guò)控制器觸發(fā)執(zhí)行特定的操作,比如移動(dòng)幾何體。 actuators/index.rst
2. Logic Nodes 邏輯節(jié)點(diǎn)編程工具。
3. Python Components 編寫腳本組件擴(kuò)展游戲引擎中的邏輯,**args** 參數(shù)列表添加面板選項(xiàng)。
這三塊內(nèi)容可以互相轉(zhuǎn)換,或者相互調(diào)用,除了 Logic Bricks 本身完全是導(dǎo)出 C++ 的接口內(nèi)容,Logic Nodes 是完全 Python 腳本實(shí)現(xiàn)的功能,而腳本組件則是基于 Blender Python API 環(huán)境下的腳本開(kāi)發(fā),當(dāng)然它們使用的類型基本上都是導(dǎo)出到腳本環(huán)境的由 UPBGE 源代碼定義的類型。
除了這三塊內(nèi)容,還狀態(tài)數(shù)據(jù)和游戲?qū)傩詳?shù)據(jù),Game Properites 是保存全局?jǐn)?shù)據(jù)的一種方式,可以在以下位置添加:
1. `Logic Bricks - Sibar - Properties -> Game Properites`
2. `Logic Nodes - Sibar - Dashboard -> Game Properites`
3. `Game Object Properties -> Game Properites`

游戲?qū)ο螅?strong>Game objects,或者是 C/C++ 定義的 `KX_GameObject` 類型是整個(gè)游戲引擎的核心,UPBGE 游戲編程構(gòu)架將圍繞**游戲?qū)ο?/strong>**開(kāi)展,場(chǎng)景中的幾何體在腳本中就是`KX_GameObject` 類型,相機(jī)就是它的派生類型 `KX_GameObject` 類型等等,在開(kāi)始深入引擎內(nèi)部之間,非常有必要對(duì)引擎的類型系統(tǒng)的設(shè)計(jì)有一個(gè)大概的印象。場(chǎng)景對(duì)象使用 objects 屬性引用場(chǎng)景中所有的游戲?qū)ο?,游戲?qū)ο笞鳛橐粋€(gè)核心類型,它提供了大量 API 用于操作對(duì)象,如幾何體變換、移動(dòng)、旋轉(zhuǎn)等,物理引擎方法等等。游戲?qū)ο笠粋€(gè)主要功能是作為數(shù)據(jù)結(jié)構(gòu)類型,記錄游戲中的各種物體的狀態(tài)屬性,這一功能將始終與以上三大編程工具相結(jié)合。
UPBGE 編程環(huán)境中常用對(duì)象類型層次結(jié)構(gòu)示意圖,后續(xù)內(nèi)容中再深入:
Logic Nodes 編輯器中側(cè)欄面板 Globals 中可以添加全局?jǐn)?shù)據(jù)字典,`Add Global Category` 即是添加一個(gè)字典用于存儲(chǔ)數(shù)據(jù),配合 `Value -> Globals` 節(jié)點(diǎn)使用,`Python -> Dictonary` 字典節(jié)點(diǎn)可以設(shè)置數(shù)據(jù)值,使用 `Init Empty` 還直接在節(jié)點(diǎn)中創(chuàng)建字典對(duì)象。
配合渲染器屬性面板激活 `Game Debug -> Debug Properties` 可以在游戲窗口左上角顯示屬性數(shù)據(jù)。
游戲?qū)傩詳?shù)據(jù)使用 5 類數(shù)據(jù):
1. `Timer` 計(jì)時(shí)器對(duì)象存在時(shí)長(zhǎng),模擬時(shí)間(或幀時(shí)間),不是實(shí)際時(shí)間,幀率相同時(shí)兩個(gè)時(shí)間才是相等。
2. `Float` 浮點(diǎn)數(shù)據(jù),范圍在 -10000.000 到 10000.000。
3. `Integer` 保存整數(shù),范圍在 -10000 到 10000,用于計(jì)算彈藥等不需要小數(shù)的物品。
4. `String` 保存 128 個(gè)字符。
5. `Boolean` 保存``TRUE`` 和 ``FALSE`` 兩個(gè)值。

有以下兩種基本使用方式,通過(guò) `GameObject["propname"]` 字典對(duì)象獲取數(shù)據(jù):
1. the `Property Sensor` (/manual/logic/sensors/types/property)
2. the `Property Actuator` (/manual/logic/actuators/types/property>
游戲中可以存在多個(gè) `GameObject` 數(shù)據(jù)對(duì)象,在對(duì)應(yīng)對(duì)象屬性面板中設(shè)置。
`Game Object Properties -> Game Properites`
游戲中的每個(gè) `GameObject` 可以存儲(chǔ)控邏輯組件的集合(Logic Bricks),可以組合邏輯塊來(lái)執(zhí)行用戶定義的動(dòng)作,這些動(dòng)作決定游戲模擬的進(jìn)度。

邏輯節(jié)點(diǎn) `Logic Nodes` 是 Blender 內(nèi)建的一套可以視化節(jié)點(diǎn)編排系統(tǒng),Armory3D 和 UPBGE 都基于這套系統(tǒng)開(kāi)發(fā)了邏輯節(jié)點(diǎn)編程工具,UnrealEngine 藍(lán)圖 Blueprints 是同類可視化編程工具。邏輯節(jié)點(diǎn)樹(shù)設(shè)計(jì)好后,必需掛載到場(chǎng)景中的對(duì)象上運(yùn)行,Logic Nodes 編輯器側(cè)欄面板也可以進(jìn)行設(shè)置:`Administration -> Apply to Selected`,`Apply As` 指定掛載方式,點(diǎn)它擊切換方式,Logic Bricks 或 Python Component。
邏輯節(jié)點(diǎn)編程的基本思想是:控制流(事件)串連數(shù)據(jù)流節(jié)點(diǎn),事件節(jié)點(diǎn)提供程序運(yùn)行邏輯關(guān)系的組織信息,數(shù)據(jù)節(jié)點(diǎn)提供了相關(guān)環(huán)節(jié)的數(shù)據(jù)讀寫功能。編譯時(shí),會(huì)在工程 `bgelogic` 目錄下生成 Python 實(shí)現(xiàn)腳本。
事件流或控制流決定了節(jié)點(diǎn)在什么條件下可以被執(zhí)行,所有節(jié)點(diǎn)的 `Condition` 條件輸入端口都可以接收控制流或事件流,也可以勾選激活端口,條件就設(shè)置為 True。
按以下幾個(gè)個(gè)節(jié)點(diǎn)說(shuō)明邏輯節(jié)點(diǎn)的基本使用流程:
1. On Init `GE_OnInit` 游戲運(yùn)行初始化時(shí),無(wú)條件地執(zhí)行此事件。
2. On Update `ConditionOnUpdate` 持續(xù)觸發(fā)執(zhí)行。
3. On Next Tick `OnNextFrame` 將輸入的觸發(fā)條件延后一幀再觸發(fā)。
4. Once `ConditionOnce` 單次觸發(fā),啟用 `Repeat` 并達(dá)到延時(shí)復(fù)位時(shí)間即可以繼承輸入條件。
5. Print `ActionPrint` 打印信息到控制臺(tái),可以不連接控制流,勾選激活 `Condition` 端口即可。

UPBGE 和 Armory3D 的邏輯節(jié)點(diǎn)編程是兩種不同的實(shí)現(xiàn)思維,后者有通過(guò)節(jié)點(diǎn)完成控制流連接關(guān)系的調(diào)用,前者則是集中在節(jié)點(diǎn)樹(shù)上執(zhí)行求值方法來(lái)實(shí)現(xiàn)整個(gè)邏輯的執(zhí)行,即是 LogicNetwork 的 `evaluate()`。也是因?yàn)檫@樣,邏輯樹(shù)類形的求值方法變顯得更復(fù)雜,遠(yuǎn)不及 Armory3D 邏輯節(jié)點(diǎn)樹(shù)簡(jiǎn)潔明了。
求值函數(shù)需要對(duì)評(píng)估整個(gè)邏輯樹(shù)掛載的節(jié)點(diǎn),即各種 Cell 類型,其執(zhí)行條件是否滿足,是否要執(zhí)行它,調(diào)用它的求值方法以準(zhǔn)備好狀態(tài)數(shù)據(jù),可潛在的下游節(jié)點(diǎn)使用。也因?yàn)檫@種實(shí)現(xiàn)思路,`ActionPrint` 這樣的邏輯節(jié)點(diǎn)就不需要連接控制流,直接激活 `condition` 端口就表示其滿足執(zhí)行條件。
如果有需要,可以直接向 UPGBGE 腳本源代碼中添加調(diào)試代碼以了解背后到底發(fā)生了什么。比如,在某個(gè)節(jié)點(diǎn)的配置方法中添加調(diào)試代碼,查看一樣當(dāng)前邏輯樹(shù)的類型以及所有者(GameObject)的類型信息:
邏輯節(jié)點(diǎn)編輯器中編輯的就是邏輯樹(shù) Logic Tree,邏輯節(jié)點(diǎn)的連接關(guān)系構(gòu)建整棵邏輯樹(shù)。樹(shù)的結(jié)構(gòu)可以嵌套執(zhí)行,`Logic - Trees - Execute Logic Tree` 添加節(jié)點(diǎn),并指定要執(zhí)行的邏輯樹(shù)。邏輯樹(shù)也是節(jié)點(diǎn)組,它們沒(méi)有本質(zhì)區(qū)別,可以在側(cè)欄面板中將當(dāng)前選中的節(jié)點(diǎn)打包為新的節(jié)點(diǎn)樹(shù):
`Sidebar -> Dashboard -> Tree Prefabs and Substress -> Pack Into New Tree`
面板中提供了一個(gè) WASD 4 鍵運(yùn)行的節(jié)點(diǎn)預(yù)置,Tree Prefabs,點(diǎn)擊 `4 Key Movement` 即可以自動(dòng)按預(yù)置的節(jié)點(diǎn)連接添加到編輯器中。在其預(yù)置文件中可以查看所用節(jié)點(diǎn)信息,這些預(yù)置節(jié)點(diǎn)就是寫好固定的功能,例如 WASD 四個(gè)節(jié)點(diǎn)是 `NLKeyPressedCondition`,按什么鍵盤都寫好了,不能修改,除非是添加新的 `Key Down` 節(jié)點(diǎn)替換它們:
Blender 提供的節(jié)點(diǎn)編輯器最基礎(chǔ)的兩個(gè)組件就是:
1. `bpy.types.NodeSocket` 節(jié)點(diǎn)插槽基類;
2. `bpy.types.Node` 節(jié)點(diǎn)基類;
UPBGE 邏輯節(jié)點(diǎn)實(shí)現(xiàn)插件,bge_netlogic 插件代碼主要分成四塊:
- **uplogic** 邏輯節(jié)點(diǎn)運(yùn)行時(shí)的實(shí)現(xiàn)。
- **basicnodes** 邏輯節(jié)點(diǎn)編輯器中節(jié)點(diǎn) UI 的實(shí)現(xiàn),最終子類屬于 bpy.types.Node 或 NodeSocket。
- **nodeutils** 節(jié)點(diǎn)編輯器中的節(jié)點(diǎn)分類目錄,使用了 `nodeitems_utils` 插件模塊。
- **ops** 包括代碼生成器,操作組件,bpy.types.Operator,對(duì)應(yīng)邏輯節(jié)點(diǎn)編輯器中的按鈕等 UI。
UI 實(shí)現(xiàn)與運(yùn)行時(shí)實(shí)現(xiàn),有此基本類型的對(duì)應(yīng)關(guān)系:
1. ParameterCell -> NLConditionNode -> 參數(shù)化節(jié)點(diǎn);
2. ActionCell? ? -> NLActionNode? ? -> 動(dòng)作節(jié)點(diǎn);
3. ConditionCell -> NLParameterNode -> 條件節(jié)點(diǎn);
除了按在 3D View 按下快捷鍵 `P` 運(yùn)行游戲,還可以在渲染器屬性面板運(yùn)行,并自動(dòng)生成邏輯節(jié)點(diǎn)代碼:
`Render -> Game Resolution -> Embedded Game` or `Standalone Game`
Logic Nodes 編輯器側(cè)欄面板也可以操作邏輯節(jié)點(diǎn)代碼生成:`Administration -> Compile All`,或者點(diǎn)擊 `Apply to Selected` 將邏輯節(jié)點(diǎn)樹(shù)掛載到當(dāng)前選中對(duì)象上,`Apply As` 指定掛載方式,可以是 Logic Bricks 或 Python Component,點(diǎn)擊切換方式。如果是掛載為腳本組件,就生成相應(yīng)腳本模塊,模塊名稱使用節(jié)點(diǎn)樹(shù)名稱并且前綴 `LN_` 以表示邏輯節(jié)點(diǎn)樹(shù)生成的腳本組件,Blender 腳本編輯器的列表中可以查看。每個(gè)邏輯節(jié)點(diǎn)樹(shù)掛載為腳本組件,對(duì)應(yīng)創(chuàng)建一個(gè)和節(jié)點(diǎn)樹(shù)同名的類型定義,比如 `NodeTree`,并且繼承自 `bge.types.KX_PythonComponent`。
兩種掛載方式設(shè)置方式不一樣,腳本組件方式掛載的邏輯樹(shù),腳本組件面板提供 `Only Run At Startup` 選項(xiàng),要勾選它才表示在游戲開(kāi)始時(shí)執(zhí)行邏輯樹(shù)?;蛘呤褂?`Execution Condition`,指定一個(gè)邏輯條件,它就是一個(gè)字符串,相當(dāng)于是邏輯樹(shù)的 condition 條件輸入端口。但是它需要經(jīng)過(guò)一次映射轉(zhuǎn)換,即讀取 self.objcet 對(duì)應(yīng)字段的值使用執(zhí)行條件,參考 bgelogic 目錄下的生成代碼:
注意,因?yàn)樽鳛槟_本組件掛載,所以 self 指的就是 `KX_PythonComponent` 實(shí)例,object 即是腳本組件的所有者,也就是組件所掛載的那個(gè)游戲?qū)ο?,也就是?chǎng)景中的對(duì)象。
注意,在 Apply As Logic Bricks 模式下編譯才會(huì)生成外部腳本模塊,如果是 Component 模式則會(huì)內(nèi)嵌在 Blender 文件,使用自帶的腳本編輯器查看。
工程 `bgelogic` 目錄下生成代碼中的邏輯節(jié)點(diǎn)樹(shù)并不是一個(gè)具體的類型,它只是一個(gè) Python 腳本文件,也是 Python 的腳本模塊,這個(gè)模塊中定義了:
1. 一個(gè) `_initialize(owner)` 初始化函數(shù);
2. 一個(gè) `pulse_network(controller)` 控制器觸發(fā)函數(shù);
Logic Bricks 操作上和 Logic Nodes 基本沒(méi)多大差別,都是節(jié)點(diǎn)之間的連接。
比如,`Keyboard` 和 `Always` 兩個(gè)傳感器連接到一個(gè) `And` 控制器,用來(lái)觸發(fā)一個(gè) `Motion` 執(zhí)行器,以實(shí)現(xiàn)對(duì)象的移動(dòng)、旋轉(zhuǎn)等等。盡管 `Always` 是執(zhí)行活動(dòng)中,但是因?yàn)?`And` 邏輯需要兩個(gè)傳感器都活動(dòng)時(shí)才會(huì)執(zhí)行,所以只有在按下鍵盤動(dòng)作配合才能執(zhí)行后續(xù)邏輯塊,換成 `Or` 則不需要鍵盤。
`Always` 作為一種持續(xù)激活狀態(tài)的傳感器,它沒(méi)其它額外的選項(xiàng),只繼承了 `SCA_ISensor` 類型中定義的最基本的傳感器設(shè)置,如下:
https://upbge.org/docs/latest/manual/_images/logic-sensors-common-options.pngUPBGE-Docs\source\manual\logic\introduction.rst
UPBGE-Docs\source\manual\logic\properties.rst
UPBGE-Docs\source\manual\logic\states.rst
UPBGE-Docs\source\manual\logic\sensors\introduction.rst

1. **Pulse True Level** 正值脈沖模式,激活時(shí)輸出的 `True` 狀態(tài)才會(huì)發(fā)送給控制器;
2. **Pulse False Level** 負(fù)值脈沖模式,激活時(shí)輸出的 `False` 狀態(tài)才會(huì)發(fā)送給控制器;
3. **Skipped Ticks** 指定跳過(guò)多少個(gè)脈沖周期,0 表示不跳過(guò)任何脈沖,有信號(hào)就傳遞給控制器;
4. **Level** 觸發(fā)模式:邏輯塊內(nèi)置狀態(tài)機(jī)的狀態(tài)改變時(shí)觸發(fā)連接的控制器;
5. **Tap** 觸發(fā)模式:在一幀后將傳感器的狀態(tài)更改為 negative 狀態(tài),即使傳感器求值為 positive。
6. **Invert** 反轉(zhuǎn)輸出的狀,`True` 和 `False` 反轉(zhuǎn)為 `False` 和 `True` 輸出;
傳感器默認(rèn)是 True 脈沖,比如,`Always` 激活 **Pulse True Level** 模式時(shí)就可以驅(qū)動(dòng)控制器,如果激活 **Invert** 反轉(zhuǎn)輸出,那么就需要激活 **Pulse False Level** 才能驅(qū)動(dòng)控制器。
其中的 **Level** 和 **Tap** 是兩種互斥的模式或者都不激活,是不同的控制器觸發(fā)邏輯。Level,也是狀態(tài)數(shù)據(jù)的一種,當(dāng)狀態(tài)改變另一種狀態(tài),negative 與 positive,對(duì)應(yīng)兩種相反的狀態(tài),就如 True 與 False 對(duì)應(yīng)。而 Tap 可以理解為滴水龍頭,水滴未滴落的狀態(tài)就是 positive,水滴掉落對(duì)應(yīng) negative,所以 Tap 模式下,狀態(tài)總是在一幀后變?yōu)?negative。
Logic Ticks 和游戲運(yùn)行的幀率等同,每幀就是一個(gè)邏輯時(shí)間周期,Skipped 多少邏輯周期,邏輯塊就跳過(guò)相應(yīng)的觸發(fā)機(jī)會(huì)。
以一個(gè) `Keyboard` 傳感器為例,在以上功能都不激活的情況下,按下按鍵、和釋放按鍵,對(duì)應(yīng)的是兩個(gè)觸發(fā)控制器的機(jī)會(huì),也就是控制器相應(yīng)功能被執(zhí)行,這種狀態(tài)和激活了 Level 模式相同,因?yàn)殒I盤狀態(tài)改變就觸發(fā)連接的控制器。Tap 模式激活后,那么鍵盤的釋放動(dòng)作就被忽略,釋放對(duì)應(yīng) negative 狀態(tài)。
如果只激活 **Pulse False Level** 負(fù)值脈沖模式,那么鍵盤沒(méi)有按鍵時(shí)就會(huì)觸發(fā)控制器執(zhí)行,并且會(huì)持續(xù)觸發(fā),因?yàn)榇藭r(shí)鍵盤一直牌 negative 狀態(tài),控下按鈕反而會(huì)停止觸發(fā)。如果配合 Tap 模式,那么就只會(huì)在按下按鈕時(shí)觸發(fā)。
如果只激活 **Pulse True Level** 正值脈沖模式,那么鍵盤按下時(shí)就會(huì)一直觸發(fā)控制器執(zhí)行,直到釋放按鍵。如果配合 Tap 模式,那么觸發(fā)會(huì)更快速,因?yàn)?Tap 增加了觸發(fā)脈沖。Pulse False Level 配合 Tap 模式的表現(xiàn)就完全不同。
Logic Bricks 編輯器界面分為三列,分別是:Sensors,Controllers、Actuators。每一列默認(rèn)都有現(xiàn)行,首行設(shè)置 Logic Bricks 顯示過(guò)濾條件,第二行設(shè)置邏輯磚的顯示狀態(tài):
- **Sel** 顯示選中對(duì)象的上設(shè)置的 Logic Bricks;
- **Act** 顯示選中對(duì)象的上設(shè)置的 Logic Bricks;
- **Link** 顯示左右兩側(cè)有連接線的 Logic Bricks;
- **State** 顯示連著處于活動(dòng)狀態(tài)的 Logic Bricks;
第一行彈出菜單相等點(diǎn)擊邏輯磚左側(cè)的箭頭圖標(biāo),用于展開(kāi)、收起面板:
1. Show Objects 顯示當(dāng)前欄的 Logic Bricks 對(duì)象;
2. Hide Objects 隱藏當(dāng)前欄的 Logic Bricks 對(duì)象,只顯示場(chǎng)景對(duì)象對(duì)應(yīng)的一個(gè)基本狀態(tài)位設(shè)置;
3. Show Sensors/Controllers/Actuators 顯示當(dāng)前欄的 Logic Bricks 對(duì)象上的具體設(shè)置;
4. Hide Sensors/Controllers/Actuators 隱藏當(dāng)前欄的 Logic Bricks 對(duì)象上的具體設(shè)置;
游戲中所有對(duì)象都有狀態(tài)信息,比如走動(dòng)、站立、攻擊等等,控制器邏輯磚面板中最基本的也是控制器的兩種基本狀態(tài)的數(shù)據(jù)面板 State Panel,可見(jiàn)性控制那個(gè)通道的控制器可見(jiàn)、有效:
- **Visible States** 提供 30 個(gè)狀態(tài)位,設(shè)置 Controller 可見(jiàn)或不可見(jiàn),游戲中是否生效;
- **Initial States** 提供 30 個(gè)狀態(tài)位設(shè)置,激活其中的狀態(tài)作為游戲開(kāi)始的狀態(tài);
亮灰色方塊表示不在活動(dòng)狀態(tài),亮藍(lán)色表示活動(dòng)狀態(tài),Active,點(diǎn)擊 `All` 按鈕激活所有 30 個(gè)狀態(tài)位。按住 `Shift` 拖動(dòng)可以快速切換相應(yīng)位置的狀態(tài)。方塊內(nèi)有圓點(diǎn),表示此狀態(tài)數(shù)據(jù)掛載了 Logic Bricks,激活這個(gè)狀態(tài)位就可以顯示這些控制器。通過(guò) **Controller visible at** 列表修改控制器所在通道??刂破髯鳛?`EXP_Value` 的子類型,當(dāng)然也繼承它的 name 屬性,控制器類型列表左側(cè)的文本框設(shè)置。
激活 i 信息圖標(biāo),并且打開(kāi)調(diào)試屬性選項(xiàng)就可以在游戲運(yùn)行時(shí),在左上角顯示狀態(tài)信息。
`Render properties --> Game Debug panel --> Debug Properties checkbox`
要在相應(yīng)欄添加 Logic Bricks,點(diǎn)擊相應(yīng)的 Add Sensors、Add Controller 或 Add Actuator。
鼠標(biāo)在兩個(gè)邏輯磚的插槽 Link socket 之間拖動(dòng)完成兩個(gè) Logic Bricks 的連接。要切開(kāi)連接:按 `CTRL-RMB` 在連線上劃過(guò),切斷連線。要?jiǎng)h除邏輯磚,點(diǎn)擊其右上角的 X 圖標(biāo)。也可以臨時(shí)切換啟用狀態(tài)(Active),或者執(zhí)行優(yōu)先級(jí)(Priority),還可以在多個(gè)邏輯磚之間調(diào)整先后執(zhí)行順序。
側(cè)欄屬性面板 *Add Game Property*? 可以向游戲引擎添加屬性定義保存相關(guān)數(shù)據(jù)。
`Properties` (manual/logic/properties).
側(cè)欄面板 *Python Components* 區(qū)域用來(lái)添加腳本擴(kuò)展組件,`Register Component` 或者`Create Component`,這是 UPBGE 主要的編程手段。這是與邏輯節(jié)點(diǎn)、邏輯磚相互獨(dú)立的模塊,可以將腳本模塊掛載到模型對(duì)象上。
see `Python Components` (manual/python_components/introduction).
打開(kāi) Blender 腳本編輯器,可以從 `Templates - Python Component templates` 菜單找到腳本組件模板,以供學(xué)習(xí)。
邏輯控制器除了常用的邏輯運(yùn)算外,還可以使用兩個(gè)特別的控制器,表達(dá)式和腳本模塊:

1. **And**? 邏輯與運(yùn)算,輸入條件同時(shí)為 `True` 時(shí)才執(zhí)行 **Actuator**。
2. **Or**? ?邏輯或運(yùn)算,輸入條件只要有一個(gè)為 `True` 就運(yùn)行 **Actuator**。
3. **Nand** 與非邏輯運(yùn)算,Not And,輸入條件只要有一個(gè)不為 `True` 就執(zhí)行 **Actuator**。
4. **Nor**? 或非邏輯運(yùn)算,Not Or,輸入條件全部為 `True` 才執(zhí)行 **Actuator**。
5. **Xor**? 異或邏輯運(yùn)算⊕,eXclusive Or,當(dāng)輸入兩條件相反時(shí)就執(zhí)行 **Actuator**。
6. **Xnor** 同或邏輯運(yùn)算,eXclusive Not Or,當(dāng)輸入兩條件相同時(shí)就執(zhí)行 **Actuator**。
7. **Expression** 只有在表達(dá)式求值結(jié)果為 `True` 時(shí)才執(zhí)行 **Actuator**。
8. **Python** 就執(zhí)行 **Actuator**。
UPBGE-Docs\source\manual\logic\controllers\types\python.rstUPBGE-Docs\source\manual\logic\controllers\types\expression.rst
https://www.howtogeek.com/wp-content/uploads/csit/2021/05/22e2d43d.png
How Logic Gates Work: OR, AND, XOR, NOR, NAND, XNOR, and NOT
求值表達(dá)式中可以使用變量、常量以及各種運(yùn)算符號(hào),還可以使用 sensors 名稱和 Game Properties 設(shè)置的屬性數(shù)據(jù)。比如 `3 > 2` (True) 或者 `1 AND 0` (False)。假設(shè)設(shè)置 Game Properties? `coins` 屬性數(shù)據(jù)為數(shù)值 30。同時(shí)又有一個(gè)傳感器名稱為 `Key_Inserted`,其值為 `True`,那么可以使用以下這樣的表達(dá)式:
使用 **Python** 控制器就可以加載腳本模塊,Python 腳本就是一個(gè)模塊,它可以和 .blend 保存在同級(jí)目錄中,或者子目錄中,也可以使用 Blender 內(nèi)嵌的腳本。比如同級(jí)目錄有scripts/myscript.py 腳本定義了以下這樣一個(gè)函數(shù),那么就可以使用腳本控制器加載:`scripts.myscript.reload_me`,這個(gè)點(diǎn)路徑中,目錄可以稱之為包 package,腳本文件稱為模塊 module,函數(shù)或類型稱為導(dǎo)入的符號(hào)。控制器中導(dǎo)入的腳本,調(diào)用其函數(shù)時(shí),會(huì)將當(dāng)前的控制器作為參數(shù)傳入。
導(dǎo)入外部腳本時(shí),可以使用多級(jí)目錄,但是在 Game Components 面板中創(chuàng)建腳本組件時(shí)就只能使用模塊名加符號(hào)名的組合形式。即使指定多級(jí)點(diǎn)路徑,UPBGE 也只會(huì)按前面兩部分創(chuàng)建相應(yīng)的模塊和腳本組件類型。
UPBGE-Docs\source\blends\Python_Scripting\001_reloadme\reload.py
如果使用 Script 模式,將使用 Blender 內(nèi)嵌腳本,這時(shí),整個(gè)腳本用作控制器來(lái)執(zhí)行,而不是其中的函數(shù)。這種執(zhí)行方式下,需要借助 bge 模塊出的各種功能與場(chǎng)景中的各種對(duì)象交互。使用全局函數(shù) `globals()` 可以獲取當(dāng)前模塊的全局符號(hào)表,通過(guò)返回的字典數(shù)據(jù)來(lái)觀察屬性是否存在。也可以使用內(nèi)置函數(shù) `dir()` 來(lái)打印對(duì)象的成員信息字典,使用 `type()` 獲取類型信息。UPBGE 引擎的類型信息都在 `bge.types` 命名空間下,為了直接使用這些類型避免輸入點(diǎn)路徑,可以導(dǎo)入它們。
以下代碼,假設(shè)邏輯塊中已經(jīng)給控制器連接了 Random 傳感器和 Mouse 執(zhí)行器等等,那么就可以使用腳本控制器來(lái)獲取這些相連接的邏輯塊對(duì)象。未連接到控制器的邏輯塊對(duì)象不會(huì)記錄在 sensors 或 actuators 集合中。注意,使用下標(biāo)訪問(wèn) `sens['Random']` 在對(duì)象不存在時(shí)引發(fā)異常,而使用 `hasattr()` 方法不能判斷集合中的元素,只能用于判斷屬性,應(yīng)該使用 `get()` 查詢集合: