UE4 C++ —— 碰撞檢測
簡述 UE4集成了PhysX物理引擎,用來模擬剛體的物理行為,包括常用的碰撞響應和通道響應。
碰撞基礎概念碰撞物件通道 每個碰撞體都會設定一種(Object Responses)碰撞物件通道,碰撞物件通道可以是ue4預設的幾種,也可以新建自定義的碰撞物件通道
新建自定義的碰撞物件通道,點選Project Settings->Collision 在Collision窗口裡,找到Object Channelse項,點選New Object Channelse新建碰撞型別,設定名稱和預設響應型別,這裡新建兩個碰撞物件型別Cube, Sphere
碰撞響應設定
型別 | 詳解 |
NoCollision | 無碰撞響應 |
Query Only(No Physics Collision) | 只會觸發Overlap(重疊)事件,無剛體碰撞響應 |
Physics Only(No Query Collision) | 只有剛體碰撞響應,不觸發Overlap(重疊)事件 |
Collision Enabled(Query and Physics ) | 剛體碰撞響應和Overlap(重疊)事件都可以 |
碰撞響應型別 兩個物體發生碰撞時會產生不同的碰撞響應,Block(碰撞) ,發生Block碰撞響應後,兩個Actor之間會發生阻擋行為,並觸發Hit事件UFUNCTION() void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
UFUNCTION() virtual void OnOverlayEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);UFUNCTION() virtual void OnOverlayEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
碰撞響應
觸發Block條件 (1)兩個物體的碰撞響應都設定為Block (2)其中一個物體必須設為Physics(剛體),勾選Simulate Physics項。 (3)要觸發Hit事件,需開啟Simulate Generates Hit Events.觸發Overlap條件 (1)其中一個物體的碰撞響應為Overlap,任何一個物體的碰撞響應都不能設為Ignore (2)要觸發重疊事件,需開啟Generate Overlap EventsIgnore條件 (1)其中一個物體的碰撞響應為Ignore
碰撞例項應用 新建C++工程,建立兩個Actor,命名為CubeActor和AphereActor,這兩個物體將進行碰撞響應
現在這兩個Actor是空的,我們需要在C++中給他們新增StaticMesh,並進行事件繫結原始碼 CubeActor.h
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CubeActor.generated.h"
UCLASS()
class PROJECTDEMO1_API ACubeActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACubeActor();
UFUNCTION()
virtual void OnOverlayBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
UFUNCTION()
virtual void OnOverlayEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
protected:
//根元件
class USceneComponent* RootScene;
//靜態模型
UPROPERTY(EditAnywhere)
class UStaticMeshComponent* StaticMesh;
};
CubeActor.cpp
#include "CubeActor.h"
// Sets default values
ACubeActor::ACubeActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//例項化根元件
RootScene = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene"));
RootComponent = RootScene;
//建立靜態模型元件
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BaseMesh"));
StaticMesh->SetupAttachment(RootComponent);
StaticMesh->SetCollisionProfileName(FName("CubeProfile"));
//繫結檢測方法到碰撞體
FScriptDelegate OverlayBegin;
OverlayBegin.BindUFunction(this, "OnOverlayBegin");
StaticMesh->OnComponentBeginOverlap.Add(OverlayBegin);
FScriptDelegate OverlayEnd;
OverlayEnd.BindUFunction(this, "OnOverlayEnd");
StaticMesh->OnComponentEndOverlap.Add(OverlayEnd);
FScriptDelegate DelegateHit;
DelegateHit.BindUFunction(this, "OnHit");
StaticMesh->OnComponentHit.Add(DelegateHit);
}
void ACubeActor::OnOverlayBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Yellow, "Cube Begin---------");
}
}
void ACubeActor::OnOverlayEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Yellow, "Cube End---------");
}
}
void ACubeActor::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Yellow, "ACubeActor OnHit---------");
}
}
注:在標頭檔案中我們定義了三個函式,(OnOverlayBegin, OnOverlayEnd, OnHit)分別繫結Overlay進入事件,Overlay離開事件和剛體碰撞事件,這三個函式在事件觸發後將列印語句到螢幕,接著定義了一個根元件和StaticMesh,在建構函式中建立元件和進行事件繫結,另一個AphereActor類的程式碼同上。
C++程式碼寫完後,編譯儲存,開啟編輯器,建立兩個藍圖類,分別繼承於CubeActor和SphereActor,命名為BP_CubeActor和BP_SphereActor。並新增三維模型。
Overlap(重疊)事件 我們想讓BP_CubeActor和BP_SphereActor觸發Overlap(重疊)事件,需要將BP_CubeActor和BP_SphereActor的碰撞物件通道分別設為Cube和Sphere,並把互相的碰撞響應設為Overlap 開啟BP_CubeActor藍圖類,設定它的碰撞屬性 勾選Generate Overlap Events,Collision Presets設定為customize(自定義),Collision Enabled設定為Query Only(No Physics Collision),Object Type設為Cube(前面自定義的碰撞物件通道),Sphere響應方式勾選為Overlap。
開啟BP_SphereActor藍圖類,設定它的碰撞屬性,設定方法相似。不同的是需要把Object Type設為Sphere,Cube響應方式勾選為Overlap。
碰撞屬性配置完成後,例項化這兩個Actor,將他們拖入Level中
開啟關卡藍圖,讓Sphere向Cube移動,觸發Overlap(重疊)事件
編譯執行,不斷按下‘1’鍵,直到Sphere剛接觸到Cube時,就會觸發Overlap Begin事件,隨之呼叫繫結到該事件的函式,列印語句到螢幕。同理,當Sphere離開Cube時,觸發Overlap End事件。
Block(碰撞)事件 接下來我們要讓BP_CubeActor和BP_SphereActor觸發Block(碰撞)事件 開啟BP_CubeActor藍圖類,設定碰撞屬性,將Collision Enabled設定為Physics Only(No Query Collision),Sphere響應方式勾選為Block。
同上,設定BP_SphereActor的碰撞屬性
在兩個Actor例項中啟用Simulate Generates Hit Events事件,並設定為Physics(剛體)
將Sphere拖動到Cube上方
編譯執行,程式開始後Sphere受重力下落,觸發Block事件,呼叫繫結函式,列印語句到螢幕
碰撞預製檔案 除了前面的自定義碰撞屬性,還可以使用碰撞預製檔案來設定碰撞屬性 點選Project Settings->Collision,開啟Collision視窗。在Preset部分,點選New
設定名稱和碰撞屬性
建立兩個碰撞預製檔案,SphereProfile和CubeProfile
在藍圖中指定碰撞預製檔案
也可以在C++程式碼中指定StaticMesh->SetCollisionProfileName(FName("CubeProfile"));