發表文章

目前顯示的是 2020的文章

UE4 Navigation Mesh 心得

圖片
UE4的Navigation Mesh 如果照著網路上的教學做,大概都可以建的出來。 A.I.角色也都能夠在上面正常行走。 不過應用稍微有點變化的時候就會碰上一些問題,在這邊先介紹過去遇過的項目 名詞與縮寫說明 NavMesh: Navigation Mesh NBV: Navigation Bounds Volume,用來定義navigation mesh的範圍。 P-Level: Persistent Level。 主地圖。 Sublevel: 放置於主地圖下的子地圖。 如何調整NavMesh的大小 雖然一般都會調整NBV的scale,不過並不建議這麼做。 Volume類型的個人都建議調整Brush內的大小,不要改Actor的scale。 NavMesh到底存在哪邊? NavMesh實際上存在於有NBV的場景的umap內。 不是場景的BuiltData,也不一定是主地圖。 舉例來說 主地圖    (1個NBV)     sublevel1 (0個NBV) sublevel2 (0個NBV) sublevel3 (2個NBV) 當Build完NavMesh之後,主地圖與sublevel3都需要存檔。 我可以在Build的時候排除sublevel嗎? 可以,在Build之前把sublevel設隱藏的話,就可以排除掉,如下圖所示 sublevel隱藏的時候Build Path,就不會排除方塊(圖1.)。 sublevel顯示的時候Build Path,會排除方塊(圖2.)。 圖1. 隱藏Sublevel build path 圖2. Sublevel1內的方塊被考慮進去並視為不可行走。  有Nav Mesh刪不掉 有的時候會看到場景裡面有不該存在的Nav Mesh,而且不管怎麼重Build都刪不掉。 我找到了重現步驟如下: 1. 開啟一個新的Level File->NewLevel->Default 2. 放置Nav Mesh Bounds Volume (NBV) 於場景內,並與地板有交疊。 3. Build->Build Paths (或是引擎自己會auto build navigation) 4. 確認Nav Mesh有出現 5. 直接刪除步驟2的NBV 6. Build->Build Paths (或是引擎自己會auto b

Editor內Blueprint中斷點沒有觸發

最近在做功能的時候遇到了有趣的問題。 其實以前就偶爾有遇到但是沒有認真找原因,因為發生的機會其實很低。 這次很幸運的找到問題的原因,所以分享一下 問題發生的現象 在解決問題之前,先描述問題的定義 在BP下中斷點 無論如何都不會停下來 但是在中斷點前或後面的節點下PrintString確定會印,功能也都正常 就只是斷點不會停 如果這個BP是從C++呼叫的話 C++的斷點是會停的。 問題的原因 追查發現ScriptCore.cpp 在執行BP的breakpoint 之前 會檢查現在是不是在GameThread 如果有在Game Thread才會觸發中斷點 剛好我這次的功能是從muti-threading的animation事件過來的 CallStack直接看到有Update_AnyThread的字眼 所以下次如果再遇到類似的現象 可能要想一下是不是因為multi threading造成的~ 相關程式碼 ScriptCore.cpp FBlueprintCoreDelegates::ThrowScriptException裡面的 if (IsInGameThread()) {     OnScriptException.Broadcast(ActiveObject, StackFrame, Info); }

根據不同平台調整Static mesh的LOD

圖片
通常開發跨平台遊戲的時候,會想要針對Static Mesh做LOD區隔。 而UE4提供好用的Minimal LOD功能,讓開發者不用特別寫程式碼,就可以根據不同平台調整LOD參數。Minimal LOD的參數是可以每個static mesh設定的,設定的地方可以在Static Mesh的編輯器內找到。如圖所示 例如說Windows的Minimal LOD設為0,Android跟iOS設為1。 這樣的話在實際執行的時候,Android跟iOS平台只會看到1以後的LOD mesh,可以有效的控制場景總面數。 還有另一個參數r.StaticMeshLODDistanceScale可以控制LOD切換的距離。 數字越大代表會越早切換到低階層的LOD。 這個參數也可以針對平台做設定,不過是影響全域的變數,所以要在Device Profile的頁面設定。記得要Save as Default才會存檔。 舉例來說 r.StaticMeshLODDistanceScale=2.0 然後LOD1的screen size設為0.3的話 代表在這個平台0.3*2的距離就會切換成LOD1了。 不過使用LODDistanceScale有個小缺點,就是在編輯的時候預設都是使用r.StaticMeshLODDistanceScale=1.0。要把場景調整到1.0跟2.0外觀看起來不錯的狀態,是需要很多人工檢查的。 上面提到的兩個參數可以控制Minimal LOD,不過這兩個參數都是執行的時候,告訴系統該顯示哪一層LOD。 在打包的過程還是都會把全部的LOD都包進去,影響最後打包的容量。 如果想要避免比Minimal LOD更精細的LOD也被打包進平台內。我們需要在打包的平台把Device Profile參數 r.StaticMesh.StripMinLodDataDuringCooking設為1。 或是使用文字編輯器打開 [Project Path]/Config/DefaultDeviceProfiles.ini 把以下區段 [Windows DeviceProfile] DeviceType=Windows BaseProfileName= 改為 [Windows DeviceProfile] DeviceType=Windows BaseProfileName= +CVars=r.Static

UE4 除錯技巧分享 (二)

圖片
上一篇介紹了兩個除錯小技巧 這一篇會比較著重在中斷點的部份。 技巧分享 這篇的複雜度稍高,而且技巧互相有關連,建議按照順序看。 環境 先稍微介紹一下本篇的環境。 開發平台的部分是Windows + Visual Studio 2017; 引擎是UE4.23。 照理說引擎版本沒什麼差,不過為了保險還是提一下。 從BP中斷點找出完整的Call Stack 在使用編輯器的時候,我們常常會使用BP中斷點來追查執行順序,如同C++的中斷點一樣。 但是如果這個事件是從C++來的話,在BlueprintDebugger是無法得知的,如下圖所示。 其實我們是有辦法知道的,在BP中斷點停住的狀態下,回去Visual Studio,假設UE4 process已經是attach的狀態,按Debug->BreakAll (如圖),這時候就可以看到Call Stack了。 通常CallStack分頁會看到一大串,好像很嚇人,這時候不要慌不要著急,看到Slate那種的都略過一直往下捲。慢慢的看你應該會找到認識的函式,如下圖所示。 以這張圖為例子,就可以知道BP的Tick是從C++的Actor::Tick內呼叫ReceiveTick來的。 有時候你會看到CallStack極短,長的像這樣: 這是因為斷點剛好停在別的Thread,這時候只要去Visual Studio的Debug->Windows->Threads將Thread分頁叫出,然後跳到MainThread就可以了。 從C++中斷點找出BP呼叫的來源 前一個技巧是BP斷點想知道從哪個C++呼叫進來的。這個技巧是要說明如何從C++斷點找出是哪個BP呼叫來的。這個技巧特別重要,因為就算是Packaged Game也可以抓出BP來源。 假設我現在中斷點停在C++的程式碼,有兩種方法可以試 方法1.  到Visual Studio的Watch視窗內輸入 {,,UE4Editor-Core}::PrintScriptCallstack() 或是 ::PrintScriptCallstack() Debug Editor的話則是輸入 {,,UE4Editor-Core-Win64-Debug}::PrintScriptCallstack()  然後去Visual Studio的Output視窗就會看到印出來的BP Call Stac

UE4 除錯技巧分享 (一)

圖片
俗話說的好 給他魚吃不如教他釣魚 今天要分享幾個我平常在用的技巧 心理建設 如果你是有程式背景,但是正在用blueprint(BP)開發。 那我會建議你要先幫自己做好心裡建設。 你在用的是開發原始碼的引擎, 遇到問題時應該儘量往引擎內部追, 不要馬上就找繞過(workaround)的方法或求救。 那樣作你很快就會想放棄,因為無法進步,遇到問題無法自救。 硬體設備 雖說是技巧心得,理論上要跟硬體無關,但是這個真的要講一下。 想追code一定要準備好2個螢幕以上,至少一個螢幕是UE4 Editor,另一個是Visual Studio。 單螢幕的話光是切換視窗就亂掉了。 技巧分享 這裡面的技巧應該比較零散,所以可以跳著看。 不寫Code就直接顯示變數值在螢幕上 如果問我只能寫一條的話,我一定選這一條。 這個是我第一常用的技巧了,大部分我們想到要得知某一個值,就是跑去Actor或是Component的Tick裡面下PrintString,這樣資訊就會顯示在畫面上。如下圖。 可是有的時候bug是機率出現的,好不容易bug發生了,想看某個值是否異常,但是當下卻沒有埋PrintString,難道只能放棄了嗎? 其實沒有,引擎提供了強大的console command "DisplayAll",讓我們可以直接拿到變數值並顯示於螢幕。如圖。 DisplayAll的使用方法是: DisplayAll [ClassName] [PropertyName] 大小寫無分別,所以可以不管大小寫。 ClassName的部份,可分為C++與BP class兩種。 如果你要追查的class是C++ class,那麼直接輸入C++的名稱就好, 但是要去除第一個字。例如 AActor應該輸入Actor 想知道movement移動速度的最大值可下 displayall charactermovementcomponent maxwalkspeed 如果你要追查的class是BP,那麼你要輸入[BP的名稱_C], 舉例來說 有一個BP名稱為BP_CodeTraceActor 裡面有一個變數是value 那麼要輸入的是 DisplayAll BP_CodeTraceActor_c value PropertyName的部份,只要這個變數有被定義為UPROPERTY,就可以拿到值。BP所有的

UE4 GameplayAbilityTask介紹

圖片
簡介 本篇介紹的是UE4引擎的Gameplay Ability System(GAS)中的AbilityTask系列。 不知道什麼是GAS的話可以參考先前的文章 GameplayAbilities System介紹 (一) https://yekdniwue.blogspot.com/2018/08/gameplayabilities-sytem.html GameplayAbilities System介紹 (二) https://yekdniwue.blogspot.com/2018/09/gameplayabilities-system.html UE4 GameplayAbilitySystem - GameplayEffect & GameplayCue 如何設定參數 https://yekdniwue.blogspot.com/2019/06/GameplayEffectAndCue.html Gameplay AbilityTask介紹 AbilityTask建立了大量的範例,作為示範,很多ASC內部的系統與其他系統的溝通都做在AbilityTask內。 而AbilityTask則是要在Gameplay Ability內串流程的時候使用,AbilityTask節點不會出現在一般的Blueprint(BP)內 所以當了解完如何使用ASC,如何創造一個GameplayAbility,以及GameplayEffect後。 應該先試著了解GameplayTask,可以對ASC能夠做到的事情,如何做事情有更深刻的了解。 以下是引擎提供的Tasks,這些都可以在 Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilities\Private\Abilities\Tasks\ 裡面找到 RootMotion ApplyRootMotion_Base ApplyRootMotionConstantForce ApplyRootMotionJumpForce

在多人遊戲環境變更角色移動速度 (二)

圖片
簡介 在前一篇我已經介紹一個完整的範例,說明如何製作一個支援網路的功能,如何做測試,跟如何驗證這個做好的功能在網路延遲的環境是否能正常運作。 前一個做法確定是不行的,玩家會感到畫面不流暢,因此本篇要介紹如何正確地修改移動相關的功能,讓Server端能夠信任Client發送的指令,避免Server頻繁的矯正Client的位置。 這篇其實會比較偏向程式碼實作,敘述會少很多。簡單來說就是看code比較快啦。 當初是從CharacterMovementComponent的Crouch挖出來的。 所以如果想要自己試試看的話,可以去挖出引擎有關Crouch的程式來看。 跟之前一樣,裡面的程式碼都是我經過精簡過了,多餘的實作項目我盡可能的都沒列在裡面,所以最好還是按照順序看完,以免出錯。 再繼續往下看之前,請確認以下的詞你都知道是什麼意思: 1. Replicated Property 2. ROLE Authority 3. ROLE Simulated Proxy 4. ROLE AutonomousProxy 礙於篇幅的關係,這邊不會多做介紹。如果有不熟悉的項目,請先前往 https://docs.unrealengine.com/en-US/Gameplay/Networking/Actors/Roles/index.html 惡補一下。 為角色新增移動模式 要製作這種由玩家的操作改變移動速度的作法,其實要用到的是MovementMode的切換。也就是製作一個新的MovementModeStrafe,然後玩家按鍵的時候進到這個MovementMode,放開的時候回到預設的MovementMode。 為了達到這個目的,我們總共需要新增兩個C++ class,以及一個BP class,所以就是5個檔案。 1. CustomCharacter 2. CustomMoveComponent 3. BP_CustomCharacter 而移動速度的改變,核心做法是override GetMaxSpeed,如果角色正在Strafe狀態,MaxSpeed就回傳 Super::GetMaxSpeed()*strafeSpeedRatio CustomCharacter實作 大致上要實作的項目 CustomCharacter要能接受玩家的輸入,所以跟之前的作法一樣,要開出Strafe以及U

在多人遊戲環境變更角色移動速度 (一)

圖片
簡介 在還沒有任何網路延遲處理的經驗下,很容易做出遇到延遲就會產生問題的功能。 例如說做一個緩速功能,只要遇到網路發生延遲,玩家就會感受到拉回。 在過去的專案有幸遇到前輩指教,在UE4做了一點驗證,本篇算是學習的成果。 本系列我將會以一個實際的UE4 4.23案例做說明。 要實作的功能是: 玩家按下某一個鍵後,會進入移動射擊狀態(假設名字定義為Strafe),放開按鍵後離開移動射擊狀態(UnStrafe)。Strafe時,移動速度會減慢一半,UnStrafe後移動速度回到正常。 然後以新手的角度實作,接著提到如何模擬網路延遲,驗證新手的實作方法有問題,以及問題在哪邊。 再來就是提出正確的解法。這個解法需要以C++繼承UE4內建的CharacterMovementComponent,並複寫部分函式。這樣的做法伺服器端就會接受玩家的指令,如同玩家送出的移動一樣,不會造成拉回。 本系列目標是能夠介紹一系列的流程,包含如何開發移動減速功能,如何驗證網路延遲,結束於改善網路延遲移動的問題。 讀者可能需要知道什麼是RPC,文章前面提的部份是BP專案就能做到。後面要改善移動的時候才需要C++專案,有需求的人可以參考部份就好。 本篇不會提到改善網路延遲移動的做法,該作法會放到下一篇。 新手做法(以RPC) 本節會介紹我當初在錯誤的觀念做出來的做法以及結果。雖然可能有人會想說為什麼要介紹錯誤的觀念?主要是我認為並非所有人有網路基礎。所以有必要先用比較淺顯易懂的方式介紹這個需求的功能,把基礎建設先解釋完。然後接下來我只要專注在介紹修正錯誤的部份,避免本篇文章的閱讀難度一開始就過高。 首先在玩家的PlayerCharacter要新增按鈕接收的事件,在這邊我用input action strafe定義了輸入事件strafe,觸發的話就進入strafe,放開事件就離開strafe。 在多人連線的架構,直覺的作法就是client收到按鍵事件後,玩家角色端先套用Strafe處理,然後透過reliable RPC發送事件給server。server收到事件後作一樣的處理。 所以我們要新增兩個事件,一個是PerformStrafe 根據現在事件是Strafe還是UnStrafe,作移動速度的變更,如圖所示。 另一個則是Client,通知Server的reliable RPC 事件,命名為Server

Build Static Navigation Mesh with Commandlet in World Composition

圖片
簡介 先前有提到因為地圖被細切成很多張的關係,想要使用static nav mesh有幾個困難處要解決: 1. 地圖範圍很大的時候,是沒辦法一次載入所有地圖,只按一次build path就完成的。 不僅會執行很久,也會遇到build path失敗的情況。失敗會有警告訊息並且有部分nav mesh不完整。 2. 如果想要每張地圖各別計算,要在編輯器內重複的讀取子地圖,build path,子地圖存檔,卸載子地圖。 這樣的流程其實更適合用自動化來做。 這是本系列的最後一篇 目前一共有以下幾篇為系列的文章 1. Import RealWorld Landscape to UE4 https://yekdniwue.blogspot.com/2020/06/import-realworld-landscape-toue4.html 2. 了解Landscape的組成元件 https://yekdniwue.blogspot.com/2020/07/landscape.html 3. Generate Navigation Mesh with World Composition https://yekdniwue.blogspot.com/2020/07/GenNavMesh1.html 4. Build Static Navigation Mesh in World Composition https://yekdniwue.blogspot.com/2020/07/AutoBuildNavMesh.html 名詞與縮寫說明 在開始之前,先介紹一些本篇文章會用到的名詞或是縮寫。 NBV: Navigation Bounds Volume,用來定義navigation mesh的範圍。 P-Level: Persistent Level。在本篇指的是在World Composition模式下的主地圖。 Sublevel: 在本篇指的是在World Composition模式下的各個子地圖,可能是透過tiled height map匯入進來的。 前置準備 要能夠執行期間讀取/卸載存在子地圖的靜態nav mesh資料,需要以下步驟。 我試過很多方法,下面的步驟缺一不可。這些步驟都是在開啟P-Level的模式下運作。 1. 放置一個NBV在P-Level中,可以不需要跟任何東西交集

Generate Navigation Mesh with World Composition

圖片
簡介 使用先前提供的做法,把現實世界的地形檔匯入UE4之後, 畫面表現正常了,地圖也會根據設定的streaming distance運作。 下一個目標就是讓AI角色能在這塊地形正常的跨區域移動。 但是我很快就遇到兩個問題 1. 在play in editor遇到新的地圖載入的時候卡頓。 2. Navigation mesh要build 超久 首先是我在play in editor內,只要遇到地圖檔讀取就會造成卡頓, 但是我的地圖檔除了地形跟navigation mesh之外沒有放置其他的物件。 再來就是在build navigation mesh的時候超級慢,Build一張要5分鐘以上。 並且會伴隨很多的warning。 我做了不少的實驗想要嘗試改善這些問題,但是最後都是失敗的。例如: 降低地形複雜度 一開始我有嘗試用Flatten tool把地形輾平,也沒有加快Build path的速度。 代表地形的複雜度不影響build path以及loading的速度(或是差異不夠大)。 維持分割地圖數,降低height map解析度 將每一張tiled height map解析度輸出的時候從2017*2017降為505*505, 沒有差很多,但是地形大小不一樣了,不符合我的實驗。 效能改善的基本重點,當然是希望輸入輸出儘可能一樣,改了就不對了。 維持總解析度幾乎一致,分割地圖數變多。 例如原來是一張大地圖檔輸出成4*4張tiled map(2017*2017)。 改為一張大地圖檔輸出成9*9張tiled map(505*505)。 可想而知,每一張地圖都變小了,應該可以有效增加解析度, 但是原來只要build 16個level的navigation mesh。 現在變成要build 81次... 手動操作一兩張地圖測試後,確定是可以降低讀取時間。 不過以人工來說過於費時。需要靠程式批次處理。 因為navigaion mesh存在各個子地圖會增加地圖檔大小,有可能讀取卡頓問題也跟資源變大有關。 最後發現UE4提供不少產生navigation mesh的用法,於是研究一下各種方法的優缺點,或許可以解決讀取問題。 這是本系列的第三篇 目前一共有以下幾篇為系列的文章 1. Import RealWorld Landscape to UE4 https://yekdniwue.blo

了解Landscape的組成元件

圖片
簡介 官方文件連結 https://docs.unrealengine.com/en-US/Engine/Landscape/TechnicalGuide/index.html#recommendedlandscapesizes 一開始接觸Landscape,對裡面的各個名詞以及擁有各式各樣的數目感到非常的陌生。 就算看文件還是有很多細節是不懂的 後來跟同事一起研究,想到一些測試方法,我後續測出一些結果與結論,在本篇說明一下。 這是本系列的第二篇 目前一共有以下幾篇為系列的文章 1. Import RealWorld Landscape to UE4 https://yekdniwue.blogspot.com/2020/06/import-realworld-landscape-toue4.html 2. 了解Landscape的組成元件 https://yekdniwue.blogspot.com/2020/07/landscape.html 3. Generate Navigation Mesh with World Composition https://yekdniwue.blogspot.com/2020/07/GenNavMesh1.html 4. Build Static Navigation Mesh in World Composition https://yekdniwue.blogspot.com/2020/07/AutoBuildNavMesh.html 組成結構與了解 有關Landscape的組成結構,Level裡面可以放置Landscape,一個Landscape有一到多個components。 每一個component又可以決定要細切2*2個section或不細切兩種。一個Section又由多個Quads所組成。 最後一個Quad就是兩個三角片,為3D最基礎的繪製單位。 數量限制規範 一個Landscape的Component數目是有規範的,範圍是1~1024個,並且要是2的冪次方。 一個Component的Section數目如同前面所提,只有1*1與2*2兩種。 一個Section的Quad數目最少是7*7,最大到255*255。 不同參數下的Draw call 一個Component 2個draw calls,然後一個compon