一个需求 分身功能 分身与角色自己不发生碰撞 但是与其他角色发生碰撞
因为不同的角色都是使用相同的碰撞通道 这就需要实现指定分身与自己不发生碰撞
参考 https://answers.unrealengine.com/questions/543433/view.html
直接上主要代码
WorldSetting.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/WorldSettings.h"
#include "MyWorldSettings.generated.h"
USTRUCT()
struct FIgnorePair
{
GENERATED_USTRUCT_BODY()
public:
TWeakObjectPtr<USceneComponent> obj1;
TWeakObjectPtr<USceneComponent> obj2;
bool operator ==(const FIgnorePair& V)
{
return obj1->GetUniqueID() == V.obj1->GetUniqueID() || obj2->GetUniqueID() == V.obj2->GetUniqueID();
}
};
/**
*
*/
UCLASS()
class TESTCAR_API AMyWorldSettings : public AWorldSettings
{
GENERATED_BODY()
public:
AMyWorldSettings(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
public:
private:
TArray<FIgnorePair> ignoreComponents;
public:
const TArray<FIgnorePair>& GetIgnoreComponents();
void IgnoreBetween(USceneComponent* a, USceneComponent* b);
bool RemoveIgnoreBetween(USceneComponent* a, USceneComponent* b);
};
WorldSetting.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyWorldSettings.h"
#include "Engine/World.h"
#include "Physics/PhysicsFiltering.h"
#include "MyPlayerController.h"
//定义物理过滤函数
static PxFilterFlags PhysXSimFilterShaderPortal(PxFilterObjectAttributes attributes0, PxFilterData filterData0,
PxFilterObjectAttributes attributes1, PxFilterData filterData1,
PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{
AMyWorldSettings* settings = nullptr;
if (AMyPlayerController::currentWorld && AMyPlayerController::currentWorld->GetWorldSettings())
{
settings = Cast<AMyWorldSettings>(AMyPlayerController::currentWorld->GetWorldSettings());
}
if (settings != nullptr)
{
const auto& ignoreComponents = settings->GetIgnoreComponents();
for (int i = 0; i < ignoreComponents.Num(); ++i)
{
const auto& pair = ignoreComponents[i];
if (pair.obj1.IsValid() && pair.obj2.IsValid())
{
if ((pair.obj1->GetUniqueID() == filterData0.word2 && pair.obj2->GetUniqueID() == filterData1.word2) ||
(pair.obj2->GetUniqueID() == filterData0.word2 && pair.obj1->GetUniqueID() == filterData1.word2))
{
return PxFilterFlag::eKILL;
}
}
}
}
//原有的方法
bool k0 = PxFilterObjectIsKinematic(attributes0);
bool k1 = PxFilterObjectIsKinematic(attributes1);
PxU32 FilterFlags0 = (filterData0.word3 & 0xFFFFFF);
PxU32 FilterFlags1 = (filterData1.word3 & 0xFFFFFF);
if (k0 && k1)
{
//Ignore kinematic kinematic pairs unless they are explicitly requested
if (!(FilterFlags0&EPDF_KinematicKinematicPairs) && !(FilterFlags1&EPDF_KinematicKinematicPairs))
{
return PxFilterFlag::eSUPPRESS; //NOTE: Waiting on physx fix for refiltering on aggregates. For now use supress which automatically tests when changes to simulation happen
}
}
bool s0 = PxGetFilterObjectType(attributes0) == PxFilterObjectType::eRIGID_STATIC;
bool s1 = PxGetFilterObjectType(attributes1) == PxFilterObjectType::eRIGID_STATIC;
//ignore static-kinematic (this assumes that statics can't be flagged as kinematics)
// should return eSUPPRESS here instead eKILL so that kinematics vs statics will still be considered once kinematics become dynamic (dying ragdoll case)
if ((k0 || k1) && (s0 || s1))
{
return PxFilterFlag::eSUPPRESS;
}
// if these bodies are from the same component, use the disable table to see if we should disable collision. This case should only happen for things like skeletalmesh and destruction. The table is only created for skeletal mesh components at the moment
#if !WITH_APEIRON && !PHYSICS_INTERFACE_LLIMMEDIATE
if (filterData0.word2 == filterData1.word2)
{
check(constantBlockSize == sizeof(FPhysSceneShaderInfo));
const FPhysSceneShaderInfo* PhysSceneShaderInfo = (const FPhysSceneShaderInfo*)constantBlock;
check(PhysSceneShaderInfo);
FPhysScene * PhysScene = PhysSceneShaderInfo->PhysScene;
check(PhysScene);
const TMap<uint32, TMap<FRigidBodyIndexPair, bool> *> & CollisionDisableTableLookup = PhysScene->GetCollisionDisableTableLookup();
TMap<FRigidBodyIndexPair, bool>* const * DisableTablePtrPtr = CollisionDisableTableLookup.Find(filterData1.word2);
if (DisableTablePtrPtr) //Since collision table is deferred during sub-stepping it's possible that we won't get the collision disable table until the next frame
{
TMap<FRigidBodyIndexPair, bool>* DisableTablePtr = *DisableTablePtrPtr;
FRigidBodyIndexPair BodyPair(filterData0.word0, filterData1.word0); // body indexes are stored in word 0
if (DisableTablePtr->Find(BodyPair))
{
return PxFilterFlag::eKILL;
}
}
}
#endif
// Find out which channels the objects are in
ECollisionChannel Channel0 = GetCollisionChannel(filterData0.word3);
ECollisionChannel Channel1 = GetCollisionChannel(filterData1.word3);
// see if 0/1 would like to block the other
PxU32 BlockFlagTo1 = (ECC_TO_BITFIELD(Channel1) & filterData0.word1);
PxU32 BlockFlagTo0 = (ECC_TO_BITFIELD(Channel0) & filterData1.word1);
bool bDoesWantToBlock = (BlockFlagTo1 && BlockFlagTo0);
// if don't want to block, suppress
if (!bDoesWantToBlock)
{
return PxFilterFlag::eSUPPRESS;
}
pairFlags = PxPairFlag::eCONTACT_DEFAULT;
//todo enabling CCD objects against everything else for now
if (!(k0 && k1) && ((FilterFlags0&EPDF_CCD) || (FilterFlags1&EPDF_CCD)))
{
pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT | PxPairFlag::eSOLVE_CONTACT;
}
if ((FilterFlags0&EPDF_ContactNotify) || (FilterFlags1&EPDF_ContactNotify))
{
pairFlags |= (PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_PERSISTS | PxPairFlag::eNOTIFY_CONTACT_POINTS);
}
if ((FilterFlags0&EPDF_ModifyContacts) || (FilterFlags1&EPDF_ModifyContacts))
{
pairFlags |= (PxPairFlag::eMODIFY_CONTACTS);
}
return PxFilterFlags();
}
AMyWorldSettings::AMyWorldSettings(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
GSimulationFilterShader = PhysXSimFilterShaderPortal;
}
const TArray<FIgnorePair>& AMyWorldSettings::GetIgnoreComponents()
{
// TODO: insert return statement here
return ignoreComponents;
}
void AMyWorldSettings::IgnoreBetween(USceneComponent* a, USceneComponent* b)
{
FIgnorePair ComponentPair;
ComponentPair.obj1 = a;
ComponentPair.obj2 = b;
ignoreComponents.Add(ComponentPair);
}
bool AMyWorldSettings::RemoveIgnoreBetween(USceneComponent* a, USceneComponent* b)
{
for (auto ComponentPair : ignoreComponents)
{
if (ComponentPair.obj1->GetUniqueID() == a->GetUniqueID() ||
ComponentPair.obj2->GetUniqueID() == b->GetUniqueID())
{
ignoreComponents.Remove(ComponentPair);
return true;
}
}
return false;
}
最后 测试工程链接