執筆バージョン: Unreal Engine 4.21
|
こんにちは。アシスタントエンジニアの小倉です。
今回は、PhysicsCollisionHandlerを用いた物体の衝突の取り扱いについて紹介します。
PhysicsCollisionHandlerとは
PhysicsCollisionHandlerは、UE4における物理を用いた全ての衝突を検出し、独自の衝突後挙動を作成するためのクラスです。
UE4での物理による衝突は、OnActorHitやOnActorを用いる方法がよく使われます。この方法では、衝突後の挙動はActor側に実装することになりますが、PhysicsCollisionHandlerでは衝突時の情報(衝突したAcotrのペアや衝突の強さなど)を用いてPhysicsCollisionHandlerに対して実装を行います。
基本的にはOnAcotrHitなどを使っても同じことが実現できますが、PhysicsCollisionHandlerを使うと、既存のActorに衝突の挙動を追加するなども可能になります。
PhysicsCollisionHandlerを作成する
まず、C++でPhysicsCollisionHandlerを作成します。ここでは、クラス名をMyPhysicsCollisionHandlerとしました。
#include “CoreMinimal.h”
#include “Engine/EngineTypes.h”
#include “PhysicsEngine/PhysicsCollisionHandler.h”
#include “MyPhysicsCollisionHandler.generated.h”
USTRUCT(BlueprintType)
struct FMyRigidBodyContactInfo
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
FVector ContactPosition;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
FVector ContactNormal;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
float ContactPenetration;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
class UPhysicalMaterial* PhysMaterial0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
class UPhysicalMaterial* PhysMaterial1;
};
USTRUCT(BlueprintType)
struct FMyCollisionImpactData
{
GENERATED_BODY()
/** all the contact points in the collision*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
TArray ContactInfos;
/** the total impulse applied as the two objects push against each other*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
FVector TotalNormalImpulse;
/** the total counterimpulse applied of the two objects sliding against each other*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = PhysicsCollisionHandlerTest)
FVector TotalFrictionImpulse;
};
UCLASS()
class BLOGTEST421_API UMyPhysicsCollisionHandler : public UPhysicsCollisionHandler
{
GENERATED_BODY()
public:
/** Gives game-specific ability to handle and filter all physics collisions in one place. This is a good place to play sounds and spawn effects, as it does not require special object-specific code. */
virtual void HandlePhysicsCollisions_AssumesLocked(TArray& PendingCollisionNotifies) override;
UFUNCTION(BlueprintImplementableEvent, Category = PhysicsCollisionHandlerTest)
void HandlePhysicsCollisionPair(class AActor* actor0, class AActor* actor1, FMyCollisionImpactData contactInfo);
};
|
#include "MyPhysicsCollisionHandler.h" |
void UMyPhysicsCollisionHandler::HandlePhysicsCollisions_AssumesLocked(TArray& PendingCollisionNotifies)
{
for (const auto& notify : PendingCollisionNotifies)
{
AActor* actor0 = notify.Info0.Actor.Get();
AActor* actor1 = notify.Info1.Actor.Get();
FCollisionImpactData impactData = notify.RigidCollisionData;
TArray myContactInfos;
for (auto info : impactData.ContactInfos)
{
FMyRigidBodyContactInfo myContactInfo;
myContactInfo.ContactNormal = info.ContactNormal;
myContactInfo.ContactPenetration = info.ContactPenetration;
myContactInfo.ContactPosition = info.ContactPosition;
myContactInfo.PhysMaterial0 = info.PhysMaterial[0];
myContactInfo.PhysMaterial1 = info.PhysMaterial[1];
myContactInfos.Add(myContactInfo);
}
FMyCollisionImpactData myImpactData;
myImpactData.ContactInfos = myContactInfos;
myImpactData.TotalFrictionImpulse = impactData.TotalFrictionImpulse;
myImpactData.TotalNormalImpulse = impactData.TotalNormalImpulse;
HandlePhysicsCollisionPair(actor0, actor1, myImpactData);
}
}
次に、MyPhysicsCollisionHandlerを継承したBlueprintを作成します。ここでは、クラス名をBP_MyPhysicsCollisionHandlerとしました。
作成したBlueprintにHandlePhysicsCollisionPairを以下のように実装しました。

HandlePhysicsCollisionPairは、衝突したActorのペアに対して呼び出されるイベントです。
上記の実装では、衝撃の強さが指定したしきい値より大きいとき、衝突位置に爆発のパーティクルをスポーンします。
最後に、作成したBP_MyPhysicsCollisionHandlerをプロジェクトに設定します。
[Edit][Project Settings…]を順に選択して、[General Settings][Physics Collision Handler Class]に、BP_MyPhysicsCollisionHandlerを設定します。

物体の衝突を行うレベルを作成する
レベル上にSphereを配置し、Simulate PhysicsとSimulation Generates Hit Eventsにチェックを入れます。

Simulateでゲームを開始すると、次のようになります。
PhysicsCollisionHandlerに実装した通りの挙動を行っていることが確認できました。