UE4 只与指定的Actor发生碰撞

一个需求 分身功能 分身与角色自己不发生碰撞 但是与其他角色发生碰撞

因为不同的角色都是使用相同的碰撞通道 这就需要实现指定分身与自己不发生碰撞

参考 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;
}

 

最后 测试工程链接

https://download.csdn.net/download/maxiaosheng521/11177614

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值