physx中判断actor是否会发生碰撞

一、物理碰撞模拟方法

通过模拟一个真实的碰撞,但是不体现碰撞的特性,通过回调的方式来获取到对应的actor的指针来判断是否碰撞,但是要忽略掉当前的碰撞。

  1. 设置分类

    const PxFilterData collisionGroupIgnore(0, 0, 0, 1); // 分类自己怎么定义都可以
    
  2. 设置形状shape中的分类,方便在filtershape函数中做过滤

    PxRigidDynamic* createIgnoreDynamic(const PxTransform& t, const PxGeometry& geometry, const PxVec3& velocity = PxVec3(0))
    {
    	PxRigidDynamic* dynamic = PxCreateDynamic(*gPhysics, t, geometry, *gMaterial, 10.0f);
    
    	dynamic->userData = new int;
    
    	int shapeNb = dynamic->getNbShapes();
    	cout << "shapeNb:" << shapeNb << endl;
    	PxShape * shape = nullptr;
    	dynamic->getShapes(&shape, 1);
    	if (shape) {
    		cout << "shape is not null" << endl;
    		// 设置shape的FilterData,用在filtershape做匹配
    		shape->setSimulationFilterData(collisionGroupIgnore); 
    	}
    	else {
    		cout << "shape is null" << endl;
    	}
    		
    	memcpy(dynamic->userData, &userid, sizeof(int));
    	userid++;
    	
    	// 场景中添加零件
    	gScene->addActor(*dynamic);
    	return dynamic;
    }
    
    
    
    
  3. 设置filterShader的回调,从此处可以获取到碰撞的actor,返回值设置PxFilterFlag::eKILL即可放弃此次碰撞。

    class ContactFilterCallback : public PxSimulationFilterCallback {
    
    
    public:
    	virtual PxFilterFlags pairFound(
            PxU32 pairID, 
            PxFilterObjectAttributes attributes0, 
            PxFilterData filterData0, 
    		const PxActor* a0, 
            const PxShape* s0, 
    		PxFilterObjectAttributes attributes1, 
            PxFilterData filterData1, 
    		const PxActor* a1, 
            const PxShape* s1, 
            PxPairFlags& pairFlags) override
    	{
    		cout << "pairFound !!!!!!!!!" << endl;
    		cout << "pairFound actor0:" << *(int *)(a0->userData) << " actor1:" << *(int *)(a1->userData) << endl;
    		//return PxFilterFlag::eKILL; // 将该碰撞事件丢弃,此时就没有碰撞效果了
    		return PxFilterFlag::eSUPPRESS; // 对象的边界体积重叠,或者直到其中一个碰撞对象的过滤相关数据发生更改,就忽略该碰撞对
    	}
    
    
    	virtual void pairLost(PxU32 pairID, PxFilterObjectAttributes attributes0, PxFilterData filterData0, PxFilterObjectAttributes attributes1, PxFilterData filterData1, bool objectRemoved) override
    	{
    		
    	}
    
    
    	virtual bool statusChange(PxU32& pairID, PxPairFlags& pairFlags, PxFilterFlags& filterFlags) override
    	{
    		return false;
    	}
    
    };
    
    
    ContactFilterCallback gContactFilterCallback;
    
    
  4. 设置场景过滤条件函数

    在场景配置中设置过滤函数:sceneDesc.filterShader = filterShader;

    static PxFilterFlags filterShader(
    	PxFilterObjectAttributes attributes0,
    	PxFilterData filterData0,
    	PxFilterObjectAttributes attributes1,
    	PxFilterData filterData1,
    	PxPairFlags& pairFlags,
    	const void* constantBlock,
    	PxU32 constantBlockSize)
    {
    	// 默认对所有为过滤的碰撞产生默认回调
    	pairFlags	= PxPairFlag::eCONTACT_DEFAULT;
    	pairFlags  |= PxPairFlag::eNOTIFY_TOUCH_FOUND;	// 普通的触碰,调用回调
    	if (filterData0 == collisionGroupIgnore || filterData1 == collisionGroupIgnore)
    	{
    		cout << "filterShader this is ignore shape" << endl;
    		return PxFilterFlag::eCALLBACK; // 调用filterShader的回调
    	}
    
    	pairFlags |= PxPairFlag::eDETECT_CCD_CONTACT;  // 检测到CCD碰撞的时候
    	pairFlags |= PxPairFlag::eNOTIFY_TOUCH_CCD;		// 触碰且CCD,调用回调
    	pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND;	// 普通的触碰,调用回调
    	return PxFilterFlag::eDEFAULT;
    }
    
    
    
  5. 设置场景过滤函数的回调

    sceneDesc.filterCallback = &gContactFilterCallback;

  6. 运行调试即可

二、通过Geometry和Tranform来判断是否会出现碰撞

在physx中,有通过geometry+transform的api来获取两个几何体是否出现内嵌,我们可以通过这种方式来获取两个actor是否回发生碰撞。

physx里面有两种,一种只判断内嵌,一种是判断内嵌的深度,api分别如下

// 判断是否内嵌
bool PxGeometryQuery::overlap(const PxGeometry & geom0,
const PxTransform & pose0,
const PxGeometry & 	geom1,
const PxTransform & pose1 
);


// 判断是否内嵌,并求出内嵌深度
bool PxGeometryQuery::computePenetration	(	PxVec3 & 	direction,
PxF32 & 	depth,
const PxGeometry & 	geom0,
const PxTransform & 	pose0,
const PxGeometry & 	geom1,
const PxTransform & 	pose1 
)	
    

调用方式如下

int myOverlap(PxRigidActor * actor, PxGeometry &geom, PxTransform &trans)
{
	if (!actor) {
		cout << "actor is null" << endl;
		return -1;
	}
	bool isOverlapping = false;
	PxTransform pole = actor->getGlobalPose();
	const PxU32 numShapes = actor->getNbShapes();
	if (numShapes <= 0){
		cout << "Shape num is <= 0" << endl;
		return -1;
	}
	PxShape** shapes = (PxShape**)malloc(sizeof(PxShape*)*numShapes);
	actor->getShapes(shapes, numShapes);
	for (PxU32 i = 0; i < numShapes; i++)
	{
		PxShape* shape = shapes[i];
		cout << "shape[" << i << "]:" << shape->getGeometryType() << endl;;
		PxGeometry &geometry = shape->getGeometry().any();
		isOverlapping = PxGeometryQuery::overlap(geometry, pole, geom, trans);
		if (isOverlapping) {
			cout << "myOverlap isOverlapping:" << isOverlapping << endl;
			break;
		}
		cout << "myOverlap isOverlapping:" << isOverlapping << endl;
	}
	free(shapes);
	return isOverlapping;
}


int myOverlap(PxRigidActor * actor0, PxRigidActor * actor1)
{
	if (!actor0 || !actor1) {
		cout << "actor is null" << endl;
		return -1;
	}

	PxTransform pole0 = actor0->getGlobalPose();
	PxTransform pole1 = actor1->getGlobalPose();
	const PxU32 numShapes0 = actor0->getNbShapes();
	const PxU32 numShapes1 = actor1->getNbShapes();
	if (numShapes0 <= 0 || numShapes1 <= 0) {
		cout << "test Shape num is <= 0" << endl;
		return -1;
	}
	PxShape* shapes0 = NULL;
	actor->getShapes(&shapes0, 1);
	PxShape* shapes1 = NULL;
	actor->getShapes(&shapes1, 1);

	PxGeometry &geometry0 = shapes0->getGeometry().any();
	PxGeometry &geometry1 = shapes1->getGeometry().any();

	bool isOverlapping = PxGeometryQuery::overlap(geometry0, pole0, geometry1, pole1);
	cout << "testShapeGetGeometry isOverlapping:" << isOverlapping << endl;

	return isOverlapping;
}
### 关于虚幻引擎中的Tag检测机制 在虚幻引擎(Unreal Engine)中,标签(Tags)是一种用于标记Actor或其他对象的简单字符串列表。它们通常被用来分类或识别特定的对象组以便在游戏中实现逻辑控制。尽管引用未直接提及标签系统的具体改动[^1],但从整体更新来看,社区贡献可能间接影响了标签功能的相关优化[^2]。 #### 虚幻引擎中的Tag系统概述 标签可以通过蓝图或C++代码轻松附加到任何继承自`AActor`类的对象上。这些标签可以存储在`TArray<FName>`类型的变量中,并通过一系列内置函数来操作和查询。以下是几个常用的API: - **AddTag**: 向指定对象添加一个新标签。 - **HasTag**: 检查某个对象是否具有给定的标签。 - **RemoveTag**: 移除指定的标签。 以下是一个简单的例子展示如何使用C++代码执行标签检测: ```cpp if (MyActor->ActorHasTag("Enemy")) { UE_LOG(LogTemp, Warning, TEXT("This actor is an enemy.")); } ``` 此段代码检查名为 `MyActor` 的对象是否有 `"Enemy"` 这一标签。如果有,则记录一条日志消息表示该对象为敌人。 #### 实现更复杂的Tag检测解决方案 对于更加复杂的需求场景,比如基于多个条件组合判断或者动态改变规则的情况,开发者可以选择创建自定义组件或服务来进行管理。例如构建一个专门负责处理游戏内所有实体分类逻辑的服务层,在其中封装高级别的接口供其他模块调用。 另外值得注意的是物理模拟部分已经移除了不再使用的序列化支持,这表明如果之前依赖旧版PhysX特性来做某些特殊碰撞过滤可能会受到影响,因此需要重新评估现有项目里涉及到这部分的内容并考虑迁移到新的方法上去。 ### 示例:利用事件派发器增强交互反馈 下面给出一段示例脚本说明当玩家接近带有特定标签的目标时触发相应动作的过程: ```cpp void APlayerCharacter::Tick(float DeltaTime) { Super::Tick(DeltaTime); TArray<AActor*> OverlappingActors; GetOverlappingActors(OverlappingActors, AInteractiveObject::StaticClass()); for (auto& Actor : OverlappingActors) { if (Actor->ActorHasTag("KeyItem")) { OnFoundKey.Broadcast(); } } } ``` 上述片段展示了在玩家角色每帧更新过程中查找周围是否存在符合条件的可互动物体,并依据其携带的不同种类标签发出不同的广播信号通知订阅者做出反应的行为模式设计思路。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值