1. 程式人生 > >UE4 C++ —— 碰撞檢測

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);

Overlap(重疊) ,發生Overlap碰撞響應後,會觸發Generate Overlap Events事件

UFUNCTION() virtual void OnOverlayEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);UFUNCTION() virtual void OnOverlayEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

Ignore(忽略),兩個Actor忽略碰撞響應

碰撞響應

觸發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"));