最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

TomLooman_ActionRoguelike_第三章玩法與物理碰撞

2023-08-09 18:30 作者:別叫我小紅  | 我要投稿

該專欄用于保存對(duì)TomLooman的ActionRoguelike項(xiàng)目的學(xué)習(xí)筆記,學(xué)習(xí)過程中的思考與記錄不一定準(zhǔn)確。


教程參考:https://github.com/tomlooman/ActionRoguelike

基于UE5.0的項(xiàng)目實(shí)現(xiàn):https://github.com/CarolBaggins2023/TomLooman_ActionRoguelike_Tutorial

2023_07_25

輸入和旋轉(zhuǎn),魔法攻擊


旋轉(zhuǎn)的部分內(nèi)容在2023_07_24中提及。

?

如上設(shè)置,在編輯器內(nèi)啟動(dòng)游戲后不需要先點(diǎn)擊一下鼠標(biāo)才能操作。

?

如上設(shè)置,每次打開編輯器后不再是默認(rèn)的level,而是上次關(guān)閉前的level。

?

創(chuàng)建SMagicProjectile類

頭文件與Scharacter類類似,但SMagic類繼承自Actor而不是Character,這也意味著我們不能控制它(只有Pawn以及Pawn的子類例如Character才能控制)。

且注意#include "SMagicProjectile.generated.h"要最后引入。

?

與ASMagic類相似,類名前有ACTIONROGUELIKE_API宏,將這個(gè)Sprojectile類從ACTIONROGUELIKE中暴露出去,能被其他模塊調(diào)用。

因?yàn)槭怯螒蛐灶悾夷茉谑澜缰猩?,所以類名有前綴A。

同樣有GENERATED_BODY()生成代碼模板,減少我們的工作量。

?

與ASCharacter一樣有BeginPlay和Tick,但沒有SetupPlayerInputComponent,因?yàn)锳SMagicProjectile只是Actor,而不是Pawn,所以無法被控制,只能按照某種規(guī)則運(yùn)行。

?

?

ASMagicProjectile頭文件中新增的三個(gè)Component。

?

?

USphereComponent和SCharacter里使用的CapsuleComponent類似,都是處理運(yùn)動(dòng)與碰撞的,但是形狀不同。

但是在ASCHaracter中看不到顯式的碰撞組件成員,可能是在GENERATED_BODY()中生成的。

?

在源文件中我們對(duì)碰撞組件進(jìn)行了默認(rèn)實(shí)例化(CreateDefaultSubobject<組件所屬的類名>("組件在UE編輯器中顯示的名字")),并設(shè)置了我們自定義的碰撞(后續(xù)有相關(guān)內(nèi)容),還將其設(shè)置為該Actor的RootComponent。

?

UProjectileMovementComponent(拋體組件)能夠?qū)崿F(xiàn)拋體運(yùn)動(dòng),反彈效果,拋物曲線等功能,它繼承自UMovementComponent。

它會(huì)在每個(gè)tick更新另一個(gè)組件的位置(這里可能就是碰撞組件)。如果被更新的組件開啟了模擬物理,則只有非零的初始速度(方向向量和大?。?duì)后續(xù)軌跡有影響,因?yàn)樵诔跏紩r(shí)刻后,后續(xù)運(yùn)動(dòng)由物理模擬接管。

?

在源文件中我們對(duì)其進(jìn)行默認(rèn)實(shí)例化。

InitialSpeed設(shè)置初始速度。

bRotationFollowsVelocity為true,則拋體組件的rotation在每個(gè)frame隨著速度方向更新。(bool變量前綴為b)

bInitialVelocityInLocalSpace為true,則拋體組件的初始速度向量是相對(duì)于局部空間的,而不是相對(duì)于世界空間的。若該bool變量為false,則Projectile始終向坐標(biāo)系內(nèi)的一個(gè)方向運(yùn)動(dòng),不考慮我們的Character和Controller。

?

UParticleSystemComponent負(fù)責(zé)CPU端的粒子數(shù)據(jù)和更新邏輯,是一個(gè)SceneComponent,帶有位置信息,這意味著這個(gè)Component可以被掛到任意Actor身上。

這里我們只簡(jiǎn)單地進(jìn)行默認(rèn)實(shí)例化,并attach到碰撞組件上。

對(duì)UParticleSystemComponent類型的對(duì)象,我們可以在藍(lán)圖子類中設(shè)置其粒子效果。

?

在Scharacter.cpp中的void ASCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)內(nèi)添加

,并在ProjectSetting里添加。

實(shí)現(xiàn)將一個(gè)外部輸入綁定到一個(gè)動(dòng)作,再將一個(gè)動(dòng)作綁定到一個(gè)成員函數(shù)。

BindAction()和BindAxis()的區(qū)別總結(jié)如下:

執(zhí)行時(shí)機(jī):BindAction() 綁定的函數(shù)會(huì)在輸入事件發(fā)生時(shí)執(zhí)行,如按鍵按下或抬起時(shí)執(zhí)行一次;BindAxis() 綁定的函數(shù)每幀都會(huì)執(zhí)行;

作用原理:BindAction() 用來監(jiān)聽外設(shè)是否到達(dá)某個(gè)狀態(tài),如某個(gè)按鍵被按下或者抬起;BindAxis() 監(jiān)聽的是外設(shè)狀態(tài)的變化量;

函數(shù)參數(shù):BindAction() 綁定的函數(shù)無參數(shù);BindAxis() 綁定的函數(shù)有一個(gè)參數(shù),該參數(shù)就是外設(shè)狀態(tài)的變化量;

對(duì)按鍵的處理:當(dāng)按鍵被按下或者抬起時(shí),BindAction() 綁定的函數(shù)就會(huì)被觸發(fā);BindAxis() 綁定的函數(shù)會(huì)每幀都執(zhí)行,但在按鍵被按下時(shí)收到的參數(shù)是 Scale(Axis Mapping 時(shí)設(shè)定的系數(shù)),在抬起時(shí)收到的參數(shù)是0。

?

ActionBind的函數(shù)接口和我們的調(diào)用如下

template<class UserClass>
FInputActionBinding& BindAction( const FName ActionName, const EInputEvent KeyEvent, UserClass* Object, typename FInputActionHandlerSignature::TMethodPtr< UserClass > Func )

調(diào)用為

PlayerInputComponent->BindAction("PrimaryAttack", IE_Pressed, this, &ASCharacter::PrimaryAttack);

ActionName是我們?cè)赑rojectSetting設(shè)置的動(dòng)作名稱("PrimaryAttack"),KeyEvent是與該動(dòng)作綁定的事件(例如按下、松開、雙擊)(IE_Pressed是枚舉類型變量EInputEvent中的一個(gè)枚舉成員的key,如下圖),Object是函數(shù)作用的對(duì)象?(這里涉及到UE的委托機(jī)制),F(xiàn)unc是與事件綁定的函數(shù)的指針(我們自定義的成員函數(shù)ASCharacter::PrimaryAttack)。

?

對(duì)ASCharacter::PrimaryAttack我們聲明與實(shí)現(xiàn)如下,

public:

從后往前解釋。我們實(shí)際上要生成一個(gè)Projectile然后才能把它發(fā)射出去,在世界中生成Actor使用GetWorld()->SpawnActor<類的類型>。

SpawnActor的函數(shù)接口如下,

template< class T >
T* SpawnActor(UClass* Class, FTransform const& Transform,const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters())

SpawnActor用于從給定的參數(shù)Transform和SpawnParameters生成Class類的Actor。

?

在調(diào)用SpawnActor時(shí)我們要傳入要spawn的對(duì)象的類名,這里我們先在頭文件中聲明一個(gè)變量,然后在藍(lán)圖類中將該變量綁定到我們的ASMagicProjectile類。

UPROPERTY(EditAnywhere)這個(gè)說明符使該屬性公開給編輯器并且可編輯。

TSubclassOf<類的類名>是提供UClass類型安全性的模板類。模板類告知編輯器的屬性窗口,只顯示派生自<>內(nèi)類的類(在這里就是指顯式派生自AActor的類)。同時(shí),這個(gè)參數(shù)在代碼中也只接受派生自<>內(nèi)類的類。

這樣一來,上面SpawnActor函數(shù)在世界中Spawn的都是AAactor的子類。

?

FVector,F(xiàn)Transform,F(xiàn)ActorSpawnParameters等F開頭的類名說明它們是純C++類,可以用new來產(chǎn)生新對(duì)象。

另外前綴為U的可以用NewObject函數(shù)來產(chǎn)生對(duì)象,前綴為A可以用SpawnActor函數(shù)來產(chǎn)生對(duì)象(就是上面的GetWorld()->SpawnActor<AActor>)。

?

FTransform是個(gè)結(jié)構(gòu)體,包含一個(gè) Translation 矢量,一個(gè) Rotation 四元數(shù),和一個(gè)Scale3D 矢量(分別對(duì)應(yīng)位置translation,旋轉(zhuǎn)rotation和縮放scale),可以用以下代碼創(chuàng)建一個(gè)FTransform對(duì)象。


FRotator是上面提過的旋轉(zhuǎn)類,是個(gè)三維向量結(jié)構(gòu)體,封裝roll,yaw,pitch。FVector存儲(chǔ)三個(gè)T泛型的變量。

我們的代碼中只用了Rotation和Location初始化FTransform。

GetControlRotation()之前提過,返回Pawn的Controller的Rotation。GetActorLocation()返回Actor(這里是我們的Character)的Location。

?

FActorSpawnParameters是傳遞給SpawnActor的可選參數(shù)類的類型。

其中,F(xiàn)actorSpawnParameters::SpawnCollisionHandlingOverride是控制生成點(diǎn)(Spawn的位置)沖突的變量。

ESpawnActorCollisionHandlingMethod中定義了解決Spawn生成點(diǎn)沖突的可用策略,其中的AlwaysSpawn表示Actor總會(huì)Spawn在我們想要的位置,忽視Collision。

?

按照以下代碼,我們的ASMagicProjectile類的Actor會(huì)Spawn在Character的碰撞體的中心,但我們實(shí)際上想要讓Actor生成在Character的手上,因此做出修改。

唯一的不同是我們把GetActorLocation()換成RightHandLocation(),兩者都是Fvector。

GetMesh()返回指向MeshComponent的指針,GetSocketLocation(Socket名稱)得到指定名稱的Socket的位置。

?

添加Socket

首先,我們的Character有一個(gè)Skeleton(骨架),這個(gè)Skeleton是由許多bones(骨頭)組成的,我們可以在某塊bones上添加Socket。

雙擊Mesh組件的SkeletalMesh后,選擇Skeleton

左側(cè)顯式Character的bones和sockets,可以看到兩者的標(biāo)志不同。這里角色的右手上已經(jīng)有了一個(gè)名為“Muzzle_01”的socket,所以我們可以在C++中直接調(diào)用。因此,我們獲得RightHandLocation時(shí)傳入GetSocketLocation的參數(shù)是"Muzzle_01"(編輯器中的目標(biāo)socket的名字)。

?

現(xiàn)在我們能正確地從ASCharacter實(shí)例的手部Spawn出ASMagicProjectile實(shí)例,但是Spawn出的Projectile會(huì)穿過我們放置在世界中的StaticMesh物體,不會(huì)發(fā)生碰撞,所以我們需要對(duì)ASMagicProjectile類的collision做出修改。

我們有三種方法修改Collision。

1、可以在藍(lán)圖子類中選擇碰撞組件然后修改Collision。

2、可以在ASMagicProjectile的構(gòu)造函數(shù)中修改碰撞組件的屬性

this->SphereComp->SetCollisionObjectType(ECC_WorldDynamic);
this->SphereComp->SetCollisionResponseToAllChannels(ECR_Ignore);
this->SphereComp->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);

SetCollisionObjectType設(shè)置該組件自身的碰撞屬性(這里設(shè)置為ECC_WorldDynamic),SetCollisionResponseToAllChannels

設(shè)置該組件對(duì)所有通道的碰撞屬性(這里設(shè)置為全部忽略ECR_Ignore),SetCollisionResponseToChannel

設(shè)置該組件對(duì)某個(gè)通道的碰撞屬性(這里將該組件對(duì)ECC_Pawn的碰撞屬性設(shè)置為ECR_Overlap)。

3、可以直接在ProjectSetting里創(chuàng)建一個(gè)Collision的Profile,然后在具體組件的Collision中應(yīng)用(該方法可在多個(gè)組件中復(fù)用)

要應(yīng)用上面創(chuàng)建的Profile,在C++中和在藍(lán)圖子類中都可以。但要注意的,C++中的設(shè)置類似于默認(rèn)項(xiàng),所以如果又在藍(lán)圖子類進(jìn)行了修改,那么C++和藍(lán)圖子類中的Collision屬性可能不同。

this->SphereComp->SetCollisionProfileName("Projectile");

需要注意的是,只有發(fā)生碰撞的雙方都認(rèn)為對(duì)方是Block的對(duì)象,才會(huì)發(fā)生Block(需要雙向奔赴)。例如,在A的Collision屬性中B是要被Block的,但在B的Collision屬性中A是被Ignore的,那么A和B實(shí)際不會(huì)發(fā)生碰撞,只有在B的Collision屬性中A也是被Block的,A與B之間的碰撞才會(huì)發(fā)生。

且最終結(jié)果會(huì)是雙方Collision屬性中更輕的那個(gè),例如block和overlap則是overlap,overlap和ignore則是ignore。如下圖,player會(huì)被wall阻擋,因?yàn)槎邔?duì)對(duì)方的預(yù)設(shè)都是block。但不會(huì)被shrub阻擋:雖然player對(duì)worldStatic的預(yù)設(shè)是block,但shrub對(duì)pawn的預(yù)設(shè)是overlap,所以取了較輕的overlap判定。

UE中的Collision屬性包括ignore、overlap和block。Block下會(huì)發(fā)生阻擋(兩人見面時(shí)停下),ignore和overlap下都不會(huì)阻擋(兩人擦肩而過)。Ignore和overlap的區(qū)別在于,overlap會(huì)出發(fā)overlap事件(兩人都知道與對(duì)方擦肩而過),ignore則不會(huì)觸發(fā)時(shí)間(兩人根本沒看見對(duì)方)。

?

實(shí)現(xiàn)ASMagicProjectile與WorldStatic碰撞效果后(否則魔法飛彈會(huì)直接穿過白色方塊)


SimulatePhysics

若為true,則該對(duì)象會(huì)模擬物理行為,比如被推動(dòng)、從高處落下、拋物運(yùn)動(dòng)等,同時(shí)對(duì)象Transform的Mobility屬性應(yīng)設(shè)置為movable。若為false,則該對(duì)象會(huì)固定在原地或按指示移動(dòng)。


要實(shí)現(xiàn)物理模擬,對(duì)SkeletalMeshComponent,需要設(shè)置物理資產(chǎn)。對(duì)StaticMeshComponent,需要設(shè)置碰撞。


?

Actor的Mobility屬性主要應(yīng)用于StaticMesh和Light,包括三種狀態(tài)Static、Stationary和Movable。

Mobility為Static的Actor無法進(jìn)行任何的移動(dòng)或改變。

Mobility為Stationary的Actor可以改變,但不能移動(dòng)。

Mobility為Movable的Actor可以進(jìn)行任何的添加、移動(dòng)和改變。

?

?

2023_07_28

Assignment 1:爆炸桶,跳躍

?

首先創(chuàng)建C++類。因?yàn)楸ㄍ安恍枰籆ontrol,所以不需要繼承Pawn及其子類,繼承Actor就足夠。以下是頭文件中聲明的爆炸桶組件的成員變量,以及源文件構(gòu)造函數(shù)中對(duì)成員變量的實(shí)例化和設(shè)置。

?

這里聲明組件的方式與之前有所不同,比較在Scharacter中聲明攝像機(jī)組件,與這里聲明網(wǎng)格組件,

兩者都是指針,但聲明CameraComp時(shí)用的是C++的原始指針,聲明MeshComp時(shí)用的是TObjectPtr類。TObjectPtr類模板可用于替換原始指針,用法與其它類模板相同,為TObjectPtr<類名>。

?

在實(shí)例化MeshComp時(shí),除了默認(rèn)實(shí)例化和將其作為RootComponent,我們還開啟了MeshComp的物理模擬。

需要注意的是,我們?cè)谒{(lán)圖中對(duì)物理模擬打鉤后,Component的CollisionPresets會(huì)自動(dòng)變成PhysicsActor。但是當(dāng)我們?cè)贑++中執(zhí)行SetSimulatePhysics(true)后,Component的CollisionPresets的變化需要顯式地進(jìn)行,否則不會(huì)變化。在這里會(huì)保持WorldDynamic,因?yàn)槲覀兊腟MagicProjectile對(duì)WorldDynamic的Collision是Overlap的,所以兩者無法發(fā)生正確的碰撞。

ForceComp所屬的URadialForceComponent類(徑向力組件)會(huì)向徑向方向?qū)hysics和Destructible類別的Object施加力。

在實(shí)例化ForceComp時(shí),我們?cè)O(shè)置了該徑向力的范圍和強(qiáng)度。

其中有一個(gè)bImpulseVelChangeBool類型變量,若為true,則該組件發(fā)出的徑向力忽視Object的重量,否則Object重量越重,徑向力對(duì)Object的影響越小。

ForceComp->AddCollisionChannelToAffect(ECC_WorldDynamic)和SMagicProjectile中使用過的SphereComp->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap)類似,都是對(duì)某個(gè)通道設(shè)置某種碰撞屬性。

可通過ForceComp->SetAutoActivate()函數(shù)設(shè)置該組件的徑向力是否自動(dòng)開啟,若為true,則徑向力從該組件所依附的對(duì)象被創(chuàng)造時(shí)就存在(但是試驗(yàn)中沒有效果)。因?yàn)槲覀冃枰米訌椉せ钸@個(gè)徑向力來模擬爆炸效果,所以設(shè)置為false。

?

在頭文件中我們重載了Actor類的PostInitializeComponents函數(shù),該函數(shù)是實(shí)例化Actor時(shí)的一環(huán),

我們?cè)谠次募袑?duì)該函數(shù)的定義如下

Super::PostInitializeComponents();執(zhí)行父類(Actor類)的同名函數(shù)。

OnComponentHit組件將會(huì)在擊中或被擊中時(shí)觸發(fā)。

這里的AddDynamic涉及UE的委托機(jī)制,作用大致是將SexplosiveBarrel對(duì)象與函數(shù)ASExplosiveBarrel::OnActorHit綁定,當(dāng)觸發(fā)一些事件時(shí)激活(運(yùn)行)函數(shù)ASExplosiveBarrel::OnActorHit。???

?

BindAction進(jìn)行兩個(gè)綁定:將外部輸入綁定到事件(ProjectSetting中完成),將事件綁定到函數(shù)(C++,SetupPlayerInputComponent成員函數(shù)中完成)。

因?yàn)锳Character自帶跳躍函數(shù),所以實(shí)現(xiàn)較為簡(jiǎn)單。

如果把IE_Pressed換成IE_Release,角色就會(huì)在松開空格后起跳,而不是在按下空格時(shí)起跳(可以實(shí)現(xiàn)類似蓄力跳的效果)。


TomLooman_ActionRoguelike_第三章玩法與物理碰撞的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
弥渡县| 兰考县| 儋州市| 比如县| 绵竹市| 安庆市| 竹溪县| 海晏县| 凭祥市| 延川县| 石泉县| 腾冲县| 耒阳市| 炉霍县| 措勤县| 北海市| 报价| 黄大仙区| 泰兴市| 固始县| 清水河县| 松原市| 怀化市| 岳普湖县| 荔浦县| 松桃| 淅川县| 铜山县| 班戈县| 宜兰市| 南靖县| 桑日县| 宜章县| 六枝特区| 故城县| 和平县| 吉木萨尔县| 孝感市| 家居| 灌阳县| 大连市|