Blueprints In-depth - Part 2
Unreal 官方公佈了兩個有關blueprint的深度介紹的影片
Blueprints In-depth - Part 1 | Unreal Fest Europe 2019 | Unreal Engine
https://www.youtube.com/watch?v=j6mskTgL7kU
Part 1
https://yekdniwunrealengine.blogspot.com/2019/06/blueprints-in-depth-part-1.html
Blueprints In-depth - Part 2 | Unreal Fest Europe 2019 | Unreal Engine
https://www.youtube.com/watch?v=0YMS2wnykbc
投影片
https://epicgames.ent.box.com/s/hdv4bye3dezabp4duq8pttsha8kjjlde
這篇文章是摘錄Part 2的一些重點出來~
但是對於開發者來說,如果BP編譯太久會嚴重影響到開發過程
也有可能在使用編輯器時發生記憶體吃太兇的問題
BP編譯時間通常跟以下幾點有相關
1. BP graph內的節點數目
2. 與其他BP有reference,或是有cast其他BP。
3. BP有Circular reference。
BP大小是有上限的,不過無論如何一般的使用情境都應該遠低於上限才對。
如果你不小心撞到BP的上限,代表你對BP理解是有問題的。
BP Macro如同C++的Macro概念一樣,會在呼叫Macro的地方直接展開Macro的內容
也就是說呼叫Macro就跟複製貼上BP節點差不多,使用過多複雜的Macro是會增加BP編譯時間的
BP Function的行為與Macro有很大的不同,不會複製貼上,所以如果把Macro轉為Function的話,
可以有效的降低BP編譯時間。
將複雜的BP分為多個actor,或是多個component,或是child actor,或是以C++改寫,都能有效降低編譯時間。
不過這部份就牽扯到系統設計,要選擇哪一種方法完全就是要看情況而決定,沒有完美的答案。
假設BP_a內有cast到BP_b的節點,那麼在打開BP_a的時候,會先編譯BP_b後才會開始編譯BP_a。
所以一個cast可能就會牽連出冗長複雜的關係,在使用cast的時候務必要注意。
要注意的是即使是拿cast的InValid作條件檢查,也一樣會產生reference,即使你沒有拿cast完的object來使用。
筆者:其實你放一個cast節點然後沒接任何線就會有reference。
所以請認cast節點不要用執行邏輯判斷
除了cast之外,任何reference到其他class的BP節點或是變數也會造成跟cast一樣的結果。
除了會影響編譯時間,cast也會影響到使用editor時使用的記憶體多寡。
Reference很重要,請謹慎的使用cast以及class reference。
以下列出一些範例
1. BP reference 到Pawn class
通常是沒問題的,因為player 的class早就load好,並且會一直存在。
相同的想法,cast到一些主要的class通常也是沒問題的。
2. 小規模的BP Cast到另一個小規模的BP。
通常是沒問題的,因為夠小。
3. 從BP cast到只有變數沒有邏輯的BP
沒問題,因為只有data所以這種BP編譯很快
筆者:這邊的變數不能包含class reference,否則還是會連到其他class。
4. 從一個常用的BP cast到不常用的BP
不妥,如果這個不常用的BP邏輯還很複雜就更不好了。
如果是反過來,不常用的BP cast到常用的BP還可以接受。
5. 系統重要的Class彼此互相cast
從記憶體的觀點來說可以,但是這麼作會造成你只改一個BP class,其他class可能也要重新編譯並存檔。
筆者:這種情況很不好,就是Circular reference了,基本上開發過程要完全避免。
改一個class會觸發其他class要編譯並存檔,這種情況會很難協同合作。
你本來只改class A,卻要同事正在用的class B讓給你存檔。BP又不能merge,這樣影響到他人的工作了。
使用C++ class作為BP之間的橋接。好處是效率,較乾淨的BP節點,
Cast到一個BP的parent class(C++)不會產生BP reference,是好的做法。
Interface也是用來解reference的好方法,其他BP只要reference interface就好,不用reference BP本身。
因為直接檢查actor是不是哪個class也會造成reference。建議可以使用gameplay tag,以查詢tag的方式來作判斷。
筆者:其實cast規範不太有意義,花時間做這個不如用C++ class,因為使用C++ class優點太多。
有需要可以搭配GameplayTags
Initial的結果會根據即時class編譯的順序而有所不同
筆者:只要系統沒有Circular reference這裡面討論的問題自然就消失
這裡沒有建議任何C++/BP的使用比例,每個專案都有各自的特性,這個比例沒有一定。
但是不管怎樣你應該都先從BP開始學習,甚至精通BP。
這邊提到一個點是即使是程式人員也要學BP,因為程式做出來的東西畢竟會給BP的開發人員用。學習BP比較能夠讓彼此沒有代溝。
即使只有很少部分的C++,也可以讓你的專案流程更順,更容易擴展,執行更有效率。
C++效率好,比較容易處理複雜的系統,比較容易處理數學運算式。
有些事情在BP是做不到/很難做到的,例如存檔讀檔,平台相關,特殊硬體等等。
在BP與C++之間找到一個平衡點是專案發展過程中很重要的項目。
BP在迭代開發(Iteration)是有效率的
BP的流程容易理解,有彈性,容易使用。
BP需要用到的時候才讀取
筆者:BP記憶體這點其實不公平,雖然BP要用到的時候才讀取,C++是程式執行就讀取
但是一個BP占的記憶體就可以塞超多C++ class。
建議大多數的BP class都繼承自己寫的C++ class開始,而非繼承引擎內建的class。
哪些情況建議放在C++
1. 會在多個地方被呼叫的函式
2. 每個tick會呼叫的功能,尤其是牽扯到多個actor相關的功能。
3. 複雜,不好維護,容易出bug等功能
4. 明顯日後會延伸,會長期維護的功能
5. 複雜且核心的功能,例如存讀檔,網路功能。
6. 重要的變數
哪些情況建議放在BP
1. 主要是關聯到其他content asset的
2. 簡單直觀的功能
3. 非核心且單獨功能的項目
4. 正在雛型驗證且頻繁修改的功能
5. 放進C++沒有特別好處的功能(不影響效能,擴充性,不太有bug)
C++變數以及pure function可以有效的讓BP變乾淨。
BP可呼叫的C++ Library可以用來被各個不同的BP呼叫且沒有reference問題
即使大部分的功能都在C++,還是建議要提供各種事件讓BP能夠知道,或是修改行為。
C++函式加上修飾字BlueprintImplementableEvent可以讓BP實作事件發生時的行為
如果因為某些情況把BP的連接線斷掉,建議加上註解DOP(因為某些原因把線斷了)
宣告這個斷線是有理由的。
Pure function
好用且乾淨的BP節點,沒有input/output exec節點。
Expose On Spawn
將變數宣告為Expose on spawn可以在生成時直接傳入初始值
Call In Editor
讓這個函式可以在Editor呼叫,實現editor的行為
Expose to Cinematics
讓變數可以在Sequencer內取得。
Delete Unused Variables
可以自動將BP內沒用到的變數刪除。
Show 3D Widget
讓vector可以在editor的viewport內看到。
Deprecate
宣告這個BP即將不被使用。
Bookmarks
可以記錄BP graph的某個地方,方便追BP節點。
String Tables
可以透過.csv檔製作的字串比對表格。不用直接在BP裡面硬寫字串。
對於localization(多國語言)跟開發都有幫助。
變數容器類型Maps/Sets
各種容器特性與使用時機在這邊就不特別說明。
IsValid
用來檢查物件是否合法,確保系統穩定的節點。
未來有機會可能會分享個人對BP/C++在本篇中沒提到的理解~
Blueprints In-depth - Part 1 | Unreal Fest Europe 2019 | Unreal Engine
https://www.youtube.com/watch?v=j6mskTgL7kU
Part 1
https://yekdniwunrealengine.blogspot.com/2019/06/blueprints-in-depth-part-1.html
Blueprints In-depth - Part 2 | Unreal Fest Europe 2019 | Unreal Engine
https://www.youtube.com/watch?v=0YMS2wnykbc
投影片
https://epicgames.ent.box.com/s/hdv4bye3dezabp4duq8pttsha8kjjlde
這篇文章是摘錄Part 2的一些重點出來~
Compilation
BP的編譯時間是不會影響程式實際執行時間的。但是對於開發者來說,如果BP編譯太久會嚴重影響到開發過程
也有可能在使用編輯器時發生記憶體吃太兇的問題
BP編譯時間通常跟以下幾點有相關
1. BP graph內的節點數目
2. 與其他BP有reference,或是有cast其他BP。
3. BP有Circular reference。
BP大小是有上限的,不過無論如何一般的使用情境都應該遠低於上限才對。
如果你不小心撞到BP的上限,代表你對BP理解是有問題的。
BP Macro如同C++的Macro概念一樣,會在呼叫Macro的地方直接展開Macro的內容
也就是說呼叫Macro就跟複製貼上BP節點差不多,使用過多複雜的Macro是會增加BP編譯時間的
BP Function的行為與Macro有很大的不同,不會複製貼上,所以如果把Macro轉為Function的話,
可以有效的降低BP編譯時間。
將複雜的BP分為多個actor,或是多個component,或是child actor,或是以C++改寫,都能有效降低編譯時間。
不過這部份就牽扯到系統設計,要選擇哪一種方法完全就是要看情況而決定,沒有完美的答案。
Casting(型別轉換)
除了BP節點數之外,Cast對於編譯時間的影響是很大的。假設BP_a內有cast到BP_b的節點,那麼在打開BP_a的時候,會先編譯BP_b後才會開始編譯BP_a。
所以一個cast可能就會牽連出冗長複雜的關係,在使用cast的時候務必要注意。
要注意的是即使是拿cast的InValid作條件檢查,也一樣會產生reference,即使你沒有拿cast完的object來使用。
筆者:其實你放一個cast節點然後沒接任何線就會有reference。
所以請認cast節點不要用執行邏輯判斷
除了cast之外,任何reference到其他class的BP節點或是變數也會造成跟cast一樣的結果。
除了會影響編譯時間,cast也會影響到使用editor時使用的記憶體多寡。
Reference很重要,請謹慎的使用cast以及class reference。
以下列出一些範例
1. BP reference 到Pawn class
通常是沒問題的,因為player 的class早就load好,並且會一直存在。
相同的想法,cast到一些主要的class通常也是沒問題的。
2. 小規模的BP Cast到另一個小規模的BP。
通常是沒問題的,因為夠小。
3. 從BP cast到只有變數沒有邏輯的BP
沒問題,因為只有data所以這種BP編譯很快
筆者:這邊的變數不能包含class reference,否則還是會連到其他class。
4. 從一個常用的BP cast到不常用的BP
不妥,如果這個不常用的BP邏輯還很複雜就更不好了。
如果是反過來,不常用的BP cast到常用的BP還可以接受。
5. 系統重要的Class彼此互相cast
從記憶體的觀點來說可以,但是這麼作會造成你只改一個BP class,其他class可能也要重新編譯並存檔。
筆者:這種情況很不好,就是Circular reference了,基本上開發過程要完全避免。
改一個class會觸發其他class要編譯並存檔,這種情況會很難協同合作。
你本來只改class A,卻要同事正在用的class B讓給你存檔。BP又不能merge,這樣影響到他人的工作了。
Casting Tips
可以建立一套cast的規範,哪些class可以cast,哪些不行之類的。使用C++ class作為BP之間的橋接。好處是效率,較乾淨的BP節點,
Cast到一個BP的parent class(C++)不會產生BP reference,是好的做法。
Interface也是用來解reference的好方法,其他BP只要reference interface就好,不用reference BP本身。
因為直接檢查actor是不是哪個class也會造成reference。建議可以使用gameplay tag,以查詢tag的方式來作判斷。
筆者:其實cast規範不太有意義,花時間做這個不如用C++ class,因為使用C++ class優點太多。
小總結cast技巧
使用C++/繼承/Interface,加上正確的觀念來管理reference。有需要可以搭配GameplayTags
BP編譯的Race Condition問題
Race Condition指的是兩個以上的class互相有關係,甚至連initial的值也互相有關係Initial的結果會根據即時class編譯的順序而有所不同
筆者:只要系統沒有Circular reference這裡面討論的問題自然就消失
C++
C++的優點
C++可以輕易的把變數跟函式暴露給BP使用/呼叫。這裡沒有建議任何C++/BP的使用比例,每個專案都有各自的特性,這個比例沒有一定。
但是不管怎樣你應該都先從BP開始學習,甚至精通BP。
這邊提到一個點是即使是程式人員也要學BP,因為程式做出來的東西畢竟會給BP的開發人員用。學習BP比較能夠讓彼此沒有代溝。
即使只有很少部分的C++,也可以讓你的專案流程更順,更容易擴展,執行更有效率。
C++效率好,比較容易處理複雜的系統,比較容易處理數學運算式。
有些事情在BP是做不到/很難做到的,例如存檔讀檔,平台相關,特殊硬體等等。
在BP與C++之間找到一個平衡點是專案發展過程中很重要的項目。
BP的優點
BP非常善於作雛型驗證(Prototyping)BP在迭代開發(Iteration)是有效率的
BP的流程容易理解,有彈性,容易使用。
BP需要用到的時候才讀取
筆者:BP記憶體這點其實不公平,雖然BP要用到的時候才讀取,C++是程式執行就讀取
但是一個BP占的記憶體就可以塞超多C++ class。
C++與BP協同合作
建議大多數的BP class都繼承自己寫的C++ class開始,而非繼承引擎內建的class。
哪些情況建議放在C++
1. 會在多個地方被呼叫的函式
2. 每個tick會呼叫的功能,尤其是牽扯到多個actor相關的功能。
3. 複雜,不好維護,容易出bug等功能
4. 明顯日後會延伸,會長期維護的功能
5. 複雜且核心的功能,例如存讀檔,網路功能。
6. 重要的變數
哪些情況建議放在BP
1. 主要是關聯到其他content asset的
2. 簡單直觀的功能
3. 非核心且單獨功能的項目
4. 正在雛型驗證且頻繁修改的功能
5. 放進C++沒有特別好處的功能(不影響效能,擴充性,不太有bug)
C++變數以及pure function可以有效的讓BP變乾淨。
BP可呼叫的C++ Library可以用來被各個不同的BP呼叫且沒有reference問題
即使大部分的功能都在C++,還是建議要提供各種事件讓BP能夠知道,或是修改行為。
C++函式加上修飾字BlueprintImplementableEvent可以讓BP實作事件發生時的行為
Miscellaneous
下面說明一些有關BP的雜項。如果因為某些情況把BP的連接線斷掉,建議加上註解DOP(因為某些原因把線斷了)
宣告這個斷線是有理由的。
Pure function
好用且乾淨的BP節點,沒有input/output exec節點。
Expose On Spawn
將變數宣告為Expose on spawn可以在生成時直接傳入初始值
Call In Editor
讓這個函式可以在Editor呼叫,實現editor的行為
Expose to Cinematics
讓變數可以在Sequencer內取得。
Delete Unused Variables
可以自動將BP內沒用到的變數刪除。
Show 3D Widget
讓vector可以在editor的viewport內看到。
Deprecate
宣告這個BP即將不被使用。
Bookmarks
可以記錄BP graph的某個地方,方便追BP節點。
String Tables
可以透過.csv檔製作的字串比對表格。不用直接在BP裡面硬寫字串。
對於localization(多國語言)跟開發都有幫助。
變數容器類型Maps/Sets
各種容器特性與使用時機在這邊就不特別說明。
IsValid
用來檢查物件是否合法,確保系統穩定的節點。
總結
以上兩篇就是Unreal官方對於BP的深度說明,個人覺得很多項目都非常的實際好用未來有機會可能會分享個人對BP/C++在本篇中沒提到的理解~
留言
張貼留言