using System; using System.Collections.Generic; using System.Diagnostics.Metrics; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using MagicPhysX; // for enable Extension Methods. using MagicPhysX.Toolkit; using Physx; using static System.Formats.Asn1.AsnWriter; using static System.Runtime.InteropServices.JavaScript.JSType; using static MagicPhysX.NativeMethods; // recommend to use C API. using static PhysX.PhysxWorldRaycastResultCb_1; //测试bug问题总结 使用注意点 C Api(踩坑血泪史) /* 1 physx_create_foundation 只可以初始化一次,否则后续api 调用会出现 api调用访问非法内存 2 出现调用api 接口访问非法内存错误, 一般都是当前位置参数错误,或者前面生成参数某些步骤错误(重要) 3 创建PxGemometry 只能值传递,不可以返回指针 PxBoxGeometry_new 同类型的调用方式也有同样问题 4 PxShapeFlag.SimulationShape 和 PxShapeFlag.TriggerShape 是互斥的不可同时设置为true ! 同时 当一个设置为true时 另一个必须设置为false(翻源码得知 文档中也有说明 ) 否则会崩 5 addforce 设置外力时 给与物体速度时 需要确保actor已经加入scence了 6 当触发onTriger回调方法时候,两个shap 都是PxShapeFlag.TriggerShape属性的时候是无法触发的 7 如果创建刚体的时候设置gemomry参数时候,刚体会自带一个shap ,否则会不会创建。需要另外添加shap 8 shap添加进刚体,调用release方法 是因为physx内部内存管理机制, shap是引用计数的。在添加到一个刚体之后 需要调用relase方法,否则容易引起内存泄露。 9 PxShapeFlag.SimulationShape 模式下 先执行filetershader 后执行 filterback (目前filterback func 无法生成,库不支持) 10 raycast 回调函数目前无法触发 (大概率使用原因,后续验证下) */ namespace PhysX { //先使用原来的命名方法 后续改为微软命名风格 public enum PhysxShapeType { PX_BOX = 1, PX_SPHERE = 2, PX_CAPSULE = 3 }; public enum PhysxObjectType { PX_INVALIDE, PX_STATICOBJECT, PX_AIRSHIP, PX_SPELL, PX_SPELLTARGETSTATOCOBJECT, PX_MONSTERGROUP, PX_TRIGGER, PX_MONSTER }; public enum PhysxCollisionTypes { PX_COL_NOTHING = 0, //(handler);故不实现 public unsafe static class PxConstValue { public const int MaskAirShipCollidesWith = (int)(PhysxCollisionTypes.PX_COL_STATIC_OBJ | PhysxCollisionTypes.PX_COL_SPELL_OBJ | PhysxCollisionTypes.PX_COL_TRIGGER_OBJ); public const int MaskStaticCollidesWith = (int)(PhysxCollisionTypes.PX_COL_SPELL_OBJ | PhysxCollisionTypes.PX_COL_AIR_SHIP | PhysxCollisionTypes.PX_COL_MONSTER_GROUP_OBJ); public const int MaskSpellCollidesWith = (int)(PhysxCollisionTypes.PX_COL_STATIC_OBJ | PhysxCollisionTypes.PX_COL_AIR_SHIP | PhysxCollisionTypes.PX_COL_SPELL_TARGET_STATIC_OBJ | PhysxCollisionTypes.PX_COL_MONSTER); public const int MaskSpellTargetCollidesWith = (int)PhysxCollisionTypes.PX_COL_SPELL_OBJ; public const int MaskAirShipNoColldierWith = (int)PhysxCollisionTypes.PX_COL_NOTHING; public const int MaskMonsterGroupColldierWith = (int)PhysxCollisionTypes.PX_COL_STATIC_OBJ; public const int MaskTriggerColldierWith = (int)(PhysxCollisionTypes.PX_COL_AIR_SHIP | PhysxCollisionTypes.PX_COL_MONSTER); public const int MaskMonsterColldersWith = (int)(PhysxCollisionTypes.PX_COL_SPELL_OBJ | PhysxCollisionTypes.PX_COL_TRIGGER_OBJ); public static PhysxObjectType PhysxGetUserType(PxRigidActor* actor) { if (actor->userData == null) { return PhysxObjectType.PX_STATICOBJECT; } else { //TODO 需要补充业务代码 //return actor0->getPhysxType(); } return PhysxObjectType.PX_INVALIDE; } //public delegate* unmanaged[Cdecl] tmp; public static PxFilterFlags PhysxWorldFilterShader( UInt32 attributes0, PxFilterData filterData0, UInt32 attributes1, PxFilterData filterData1, PxPairFlags* pairFlags, void* constantBlock, UInt32 constantBlockSize) { // let triggers through if (phys_PxFilterObjectIsTrigger(attributes0) || phys_PxFilterObjectIsTrigger(attributes1)) { *pairFlags = PxPairFlags.ContactDefault; if (((filterData0.word0 & filterData1.word1) != 0) && ((filterData1.word0 & filterData0.word1) != 0)) { *pairFlags = PxPairFlags.SolveContact | PxPairFlags.DetectDiscreteContact | PxPairFlags.NotifyTouchFound | PxPairFlags.NotifyTouchLost | PxPairFlags.NotifyContactPoints; } return 0 | PxFilterFlags.Callback; } return PxFilterFlags.Callback; } } //create_raycast_filter_callback_func public unsafe struct MyOwnerFilterCallbackPhysx //: public physx::PxSimulationFilterCallback { public static PxFilterFlags pairFound( UInt32 pairID, UInt32 attributes0, PxFilterData filterData0, PxActor* a0, PxShape* s0, UInt32 attributes1, PxFilterData filterData1, PxActor* a1, PxShape* s1, PxPairFlags* pairFlags) { *pairFlags = PxPairFlags.ContactDefault; PxRigidActor* first = (PxRigidActor*)a0; PxRigidActor* second = (PxRigidActor*)a1; if (first == null || second == null) { PhysxObjectType type0 = PxConstValue.PhysxGetUserType(first); PhysxObjectType type1 = PxConstValue.PhysxGetUserType(second); if ((type0 == PhysxObjectType.PX_SPELL) && (type1 == PhysxObjectType.PX_AIRSHIP || type1 == PhysxObjectType.PX_MONSTER)) { return PxFilterFlags.Kill; } } return PxFilterFlags.Kill; } public static void pairLost(UInt32 pairID, UInt32 attributes0, PxFilterData filterData0, UInt32 attributes1, PxFilterData filterData1, bool objectRemoved) { } public static bool statusChange(UInt32* pairID, PxPairFlags* pairFlags, PxFilterFlags* filterFlags) { return false; } } ///////////////////////////////////////////////////////////////////////// // PhysxWorldRaycastResultCb ///////////////////////////////////////////////////////////////////////// public unsafe struct PhysxWorldRaycastResultCb_1 { //userdata部分 public struct RaycastUserData { public PxVec3 m_rayFromWorld; // used to calculate hitPointWorld from hitFraction public PxVec3 m_rayToWorld; public PxVec3 m_hitNormalWorld; public PxVec3 m_hitPointWorld; public PxRigidActor* actor_; } public RaycastUserData userData; public PhysxWorldRaycastResultCb_1(PxVec3* rayFromWorld, PxVec3* rayToWorld) { userData.m_rayFromWorld = *rayFromWorld; userData.m_rayToWorld = *rayToWorld; } //uint flag public delegate* callback; public static PxQueryHitType preFilter(PxRigidActor* actor, PxFilterData* filterData, PxShape* shape, uint flags, void* userData) { ////filterData need adjust??? //子弹屏蔽 if ((RaycastUserData*)userData != null) { PxRigidActor* obj0 = actor; //TODO 根据自己理解暂时修改 userData 为PhysxWorldRaycastResultCb 中的自定义数据 PxRigidActor* obj1 = ((RaycastUserData*)userData)->actor_; if (obj0 != null && obj1 != null) { int type0 = (int)PxConstValue.PhysxGetUserType(obj0); int type1 = (int)PxConstValue.PhysxGetUserType(obj1); if ((type0 == (int)PhysxObjectType.PX_SPELL) && (type1 == (int)PhysxObjectType.PX_AIRSHIP)) { //业务代码先屏蔽 } else if ((type0 == (int)PhysxObjectType.PX_AIRSHIP) && (type1 == (int)PhysxObjectType.PX_SPELL)) { //业务代码先屏蔽 } else if ((type0 == (int)PhysxObjectType.PX_SPELLTARGETSTATOCOBJECT) && (type1 == (int)PhysxObjectType.PX_SPELL)) { //业务代码先屏蔽 } else if ((type1 == (int)PhysxObjectType.PX_SPELLTARGETSTATOCOBJECT) && (type0 == (int)PhysxObjectType.PX_SPELL)) { //业务代码先屏蔽 } } } return PxQueryHitType.Block; } } //此接口废弃 此接口使用的继承方式 c#中无法使用c++风格的api 只能数据和方法分离 不就是传说中的Ecs么 //public static extern PxQueryFilterCallback* create_raycast_filter_callback_func //public unsafe struct PhysxWorldRaycastResultCb /* :PxQueryFilterCallback */ //{ //}; //释放内存逻辑暂不实现 需要根据业务详细考虑 public unsafe struct WorldUserData : IDisposable { public WorldUserData() { px_scene_ = null; stamp_ = 0; _physxBase = new PhysxBase(); // trigger_mgr_ = null; } public void Dispose() { } public string PVD_HOST = "127.0.0.1"; public float DEFAULT_DENSITY = 10.0f; public PhysxBase _physxBase; public UInt64 test_sync_time_; public bool is_init_world_; public PxScene* px_scene_; public UInt64 stamp_; public TriggerManager trigger_mgr_; //是否是这样弄? public PxTriggerPair pairs; public UInt32 count = 128; public int userid; } //public static extern PxFilterFlags PxSimulationFilterCallback_pairFound_mut //先使用原来的风格 后续改为微软命名风格 //主要继承PxSimulationEventCallback 然后触发PxSimulationEventCallback中回调函数 public unsafe struct PhysxWorld : IDisposable // : public PhysxBase, public physx::PxSimulationEventCallback { { //继承而来 //PhysxBase _physxBase; SimulationEventCallbackInfo* _event_call_back; PxSimulationFilterCallback* filter_callback_; WorldUserData _worldUserData; //Interlocked.Add; //原子操作 static UInt64 atomic_next_id_; //UInt64 test_sync_time_; public PhysxWorld() { } //~PhysxWorld(); public void Dispose() { //destroy_simulation_event_callbacks(_event_call_back); if (_worldUserData.px_scene_ != null) { //TODO 构造px_scene_ 使用的 scentdesc 是否需要释放? _worldUserData.px_scene_->ReleaseMut(); } } public void SetPvdHost(string host) { _worldUserData.PVD_HOST = host; } //长方体 public PxBoxGeometry* CreateBoxGeo(float lon, float wide, float height) { PxBoxGeometry temp = PxBoxGeometry_new(lon, wide, height); return &temp; } //球体 public PxSphereGeometry* CreateSphereGeo(float radius) { PxSphereGeometry temp = PxSphereGeometry_new(radius); return &temp; } //胶囊体 public PxCapsuleGeometry* CreateCapsuleGeo(float radius, float height, int capsuleAxis) { PxCapsuleGeometry temp = PxCapsuleGeometry_new(radius, height * 0.5f); return &temp; } //创建几何体 public PxGeometry* CreateGeometry(int shape_type, PxVec3* min_position, PxVec3* max_position) { PxGeometry* geometry = null; PxVec3 size; size.x = (MathF.Abs(max_position->x - min_position->x)); size.y = (MathF.Abs(max_position->y - min_position->y)); size.z = (MathF.Abs(max_position->z - min_position->z)); switch (shape_type) { case (int)PhysxShapeType.PX_SPHERE: { float max_r = MathF.Max(size.x, size.y); max_r = MathF.Max(max_r, size.z); geometry = (PxGeometry*)CreateSphereGeo(max_r * 0.5f); break; } case (int)PhysxShapeType.PX_BOX: { geometry = (PxGeometry*)CreateBoxGeo(size.x * 0.5f, size.y * 0.5f, size.z * 0.5f); break; } case (int)PhysxShapeType.PX_CAPSULE: { float len = MathF.Max(size.x, size.y); len = MathF.Max(len, size.z); int direction = 0; float radius = 0.0f; float height = len; if (len == size.x) { direction = 0; radius = MathF.Max(size.y, size.z) * 0.5f; } else if (len == size.y) { direction = 1; radius = MathF.Max(size.x, size.z) * 0.5f; } else if (len == size.z) { direction = 2; radius = MathF.Max(size.x, size.y) * 0.5f; } if (MathF.Abs(radius) < 0.000001) return geometry; if (MathF.Abs(height) < 0.000001) return geometry; geometry = (PxGeometry*)CreateCapsuleGeo(radius, height - 2 * radius, direction); break; } } return geometry; } //创建一个形状 PxShape* CreateShap(PxGeometry* geometry, bool isExclusive = false, PxShapeFlags shapeFlags = PxShapeFlags.Visualization | PxShapeFlags.SceneQueryShape | PxShapeFlags.SimulationShape) { return PxPhysics_createShape_mut(PhysxCommon.Instance.GetPhysics(), geometry, PhysxCommon.Instance.GetDefaultMaterial(), isExclusive, shapeFlags); } ///////////////////////////////////////////////////////////////////////// // implement add Trigger shape ///////////////////////////////////////////////////////////////////////// bool AddBoxTrigger(PxRigidDynamic* actor, float lon, float wide, float height, UInt32 effectType, UInt32 effectValue, TriggerCallBack.TRIGGER_FUNC enter, TriggerCallBack.TRIGGER_FUNC leave) { PxBoxGeometry* box = CreateBoxGeo(lon, wide, height); PxShape* shap = CreateShap((PxGeometry*)box, true); //! must be exclusive if (shap == null) { return false; } return AddTriggerFromShape(actor, shap, effectType, effectValue, enter, leave); } bool AddSphereTrigger(PxRigidDynamic* actor, float radius, UInt32 effectType, UInt64 effectValue, TriggerCallBack.TRIGGER_FUNC enter, TriggerCallBack.TRIGGER_FUNC leave) { if (radius < 0.001f) { return false; } PxSphereGeometry* sphere = CreateSphereGeo(radius); PxShape* shap = CreateShap((PxGeometry*)sphere, true); if (shap == null) { return false; } return AddTriggerFromShape(actor, shap, effectType, effectValue, enter, leave); } bool AddSphereTrigger(void* userPointer, PxVec3 startPosition, PxQuat startOrientation, UInt32 filterGroup, UInt32 filterMask, float radius, UInt32 effectType, UInt64 effectValue, TriggerCallBack.TRIGGER_FUNC enter, TriggerCallBack.TRIGGER_FUNC leave) { if (radius < 0.001f) return false; PxSphereGeometry* sphere = CreateSphereGeo(radius); PxShape* shap = CreateShap((PxGeometry*)sphere, true); if (shap == null) return false; PxFilterData filterData; filterData.word0 = filterGroup; // word0 = own ID filterData.word1 = filterMask; // word1 = ID mask to filter pairs that // trigger a contact callback; shap->SetSimulationFilterDataMut(&filterData); shap->SetFlagMut(PxShapeFlag.SimulationShape, false); shap->SetFlagMut(PxShapeFlag.TriggerShape, true); PxTransform tf = new PxTransform(); tf.p = startPosition; tf.q = startOrientation; PxRigidDynamic* actor = shap != null ? //PxCreateDynamic( physx_common::GetInst()->GetPhysics(), PxTransform(startPosition, startOrientation), *shap, 10.0f): null; phys_PxCreateDynamic_1(PhysxCommon.Instance.GetPhysics(), &tf, shap, 10.0f) : null; if (actor == null) { shap->ReleaseMut(); return false; } return true; } bool AddCapsuleTrigger(PxRigidDynamic* actor, float radius, float height, UInt32 effectType, UInt64 effectValue, TriggerCallBack.TRIGGER_FUNC enter, TriggerCallBack.TRIGGER_FUNC leave) { PxCapsuleGeometry* capsule = CreateCapsuleGeo(radius, height, 0); PxShape* shap = (PxShape*)CreateShap((PxGeometry*)capsule, true); if (shap == null) return false; return AddTriggerFromShape(actor, shap, effectType, effectValue, enter, leave); } bool AddTriggerFromShape(PxRigidDynamic* actor, PxShape* shape, UInt32 effectType, UInt64 effectValue, TriggerCallBack.TRIGGER_FUNC enter, TriggerCallBack.TRIGGER_FUNC leave) { if (shape == null) return false; PxFilterData filterData; filterData.word0 = (uint)PhysxCollisionTypes.PX_COL_TRIGGER_OBJ; // word0 = own ID filterData.word1 = (uint)PxConstValue.MaskTriggerColldierWith; // word1 = ID mask to filter pairs that // trigger a contact callback; shape->SetSimulationFilterDataMut(&filterData); ((PxRigidActor*)actor)->AttachShapeMut(shape); shape->SetFlagMut(PxShapeFlag.SimulationShape, false); shape->SetFlagMut(PxShapeFlag.TriggerShape, true); //trigger_mgr_.Push(std::make_shared( shape, effectType, effectValue, std::forward(enter), std::forward(leave))); //需要注意 TriggerCallBack * 的释放 智能指针 TriggerCallBack tmp = new TriggerCallBack(shape, effectType, effectValue, enter, leave); _worldUserData.trigger_mgr_.Push(&tmp); //这一步是减少引用次数 和用户数据无关 防止内存泄露 //shape->ReleaseMut(); return true; } void DeleteTriggerCallBack(PxRigidActor* actor) { if (actor != null) { _worldUserData.trigger_mgr_.OnReleaseActor(actor); } } void ResetTrigger(PxRigidActor* actor) { if (actor != null) { _worldUserData.trigger_mgr_.ResetTriggersInActor(actor); } } ///////////////////////////////////////////////////////////////////////// PxRigidActor* AddCollisionToDynamicsWord( int mass, void* userPointer, int userIndex, int userIndex2, int shape_type, PxVec3* min_position, PxVec3* max_position, PxVec3 startPosition, PxQuat startOrientation, PxVec3* hero_position = null) { //这一部是错误的 api 有bug 不可以返回指针类型 必须在当前栈对象创建PxGemometry !! PxGeometry* geometry = CreateGeometry(shape_type, min_position, max_position); if (geometry == null) { return null; } PxVec3 center; center.x = ((max_position->x + min_position->x) * 0.5f); center.y = ((max_position->y + min_position->y) * 0.5f); center.z = ((max_position->z + min_position->z) * 0.5f); float fmax = float.MaxValue; if (mass <= 0) { startPosition = center; } //PxSceneWriteLock scopedLock(*px_scene_); _worldUserData.px_scene_->LockWriteMut(null, 0); PxRigidActor* rigActor = null; if (userIndex == (int)PhysxObjectType.PX_STATICOBJECT) { //TODO //需要确认 继承关系 才可以类型强转 var identity = PxTransform_new_2(PxIDENTITY.PxIdentity); var pxTran = new PxTransform { p = startPosition, q = startOrientation }; rigActor = (PxRigidActor*)phys_PxCreateStatic( PhysxCommon.Instance.GetPhysics(), &pxTran, geometry, PhysxCommon.Instance.GetDefaultMaterial(), &identity); } else { var identity = PxTransform_new_2(PxIDENTITY.PxIdentity); var pxTran = new PxTransform { p = startPosition, q = startOrientation }; rigActor = (PxRigidActor*)phys_PxCreateDynamic( PhysxCommon.Instance.GetPhysics(), &pxTran, geometry, PhysxCommon.Instance.GetDefaultMaterial(), 10.0f, &identity); if (rigActor == null) { //TODO 销毁api //delete geometry; return null; } //rigActor->SetActorFlag(PxActorFlag.DisableGravity, true); PxActor_setActorFlag_mut((PxActor*)rigActor, PxActorFlag.DisableGravity, true); //rigActor setAngularDamping(0); PxRigidBody_setAngularDamping_mut((PxRigidBody*)rigActor, 0); PxRigidBody_setLinearDamping_mut((PxRigidBody*)rigActor, 0); PxRigidBody_setLinearDamping_mut((PxRigidBody*)rigActor, 0); PxVec3 tmp = new Vector3(0, 0, 0); ((PxRigidDynamic*)rigActor)->SetLinearVelocityMut(&tmp, false); PxShape* treasureShape = null; rigActor->GetShapes(&treasureShape, 1, 0); treasureShape->SetContactOffsetMut(0.2f); treasureShape->SetRestOffsetMut(0.01f); if (shape_type == (int)PhysxShapeType.PX_CAPSULE) { //胶囊调整为沿z轴线缩放 //PxTransform relativePose( PxQuat(PxHalfPi, PxVec3(0, 1, 0))); var quat = new PxQuat { w = PhysxCommon.PxHalfPi, x = 0, y = 1, z = 0 }; var relativePose = new PxTransform { p = startPosition, q = startOrientation }; treasureShape->SetLocalPoseMut(&relativePose); } } if (rigActor == null) { //TODO: //delete geometry; return null; } //可以简化逻辑 调用新的api 直接设置密度和质量 // add collision mask if (mass > 0) { if (userIndex == (int)PhysxObjectType.PX_MONSTERGROUP) { SetupFiltering(rigActor, (int)PhysxCollisionTypes.PX_COL_MONSTER_GROUP_OBJ, PxConstValue.MaskMonsterGroupColldierWith); } else if (userIndex == (int)PhysxObjectType.PX_TRIGGER) { SetupFiltering(rigActor, (int)PhysxCollisionTypes.PX_COL_TRIGGER_OBJ, PxConstValue.MaskTriggerColldierWith); } else if (userIndex == (int)PhysxObjectType.PX_MONSTER) { SetupFiltering(rigActor, (int)PhysxCollisionTypes.PX_COL_MONSTER, PxConstValue.MaskMonsterColldersWith); } else { SetupFiltering(rigActor, (int)PhysxCollisionTypes.PX_COL_AIR_SHIP, PxConstValue.MaskAirShipCollidesWith); } } else SetupFiltering(rigActor, (int)PhysxCollisionTypes.PX_COL_STATIC_OBJ, PxConstValue.MaskStaticCollidesWith); _worldUserData._physxBase.AddPhysicsActors(rigActor); if (mass > 0) { if ((PxRigidDynamic*)rigActor != null) { ((PxRigidBody*)rigActor)->SetMassMut(fmax); ((PxRigidBody*)rigActor)->SetRigidBodyFlagMut(PxRigidBodyFlag.EnableCcd, true); } } else { // rigActor->is()->setMass(mass); } //rigActor->userData = ClassType::CreateClassType(userPointer, (PhysxObjectType)userIndex); _worldUserData.px_scene_->AddActorMut((PxActor*)rigActor, null); _worldUserData.px_scene_->UnlockWriteMut(); return rigActor; } PxRigidActor* AddSpellCollison( int mass, void* userPointer, int userIndex, int shape_type, int range, PxVec3 startPosition, PxQuat startOrientation, PxVec3* spell_position = null) { return default(PxRigidActor*); } PxRigidActor* AddFlyerCollison( int mass, void* userPointer, int userIndex, //Eternity::FlatBuffer::FlyerColliderData* collider_data, void* collider_data, //用户数据 PxVec3 startPosition, PxQuat startOrientation) { //return default(PxRigidActor*); return null; } public bool AddActorToDaynamicWorld(PxRigidActor* actor) { _worldUserData.px_scene_->AddActorMut((PxActor*)actor, null); return true; } public void PickUpActor(PxRigidActor* actor) { _worldUserData.px_scene_->RemoveActorMut((PxActor*)actor, true); } int StepSimulation(/*KScene* secene,*/ UInt64 delta_time = 0) { //update 时间更新代码 UInt32 error = 0; _worldUserData.px_scene_->SimulateMut(delta_time * 0.001f, null, null, 0, controlSimulation: true); _worldUserData.px_scene_->FetchResultsMut(true, &error); _worldUserData.trigger_mgr_.Update(); SyncUser(); return 1; } // world 类自身方法 start public void OnInit() { if (filter_callback_ != null) { //delete filter_callback_; //filter_callback_->dispose(); filter_callback_ = null; } MyOwnerFilterCallbackPhysx tmp = new MyOwnerFilterCallbackPhysx(); filter_callback_ = (PxSimulationFilterCallback*)&tmp; _worldUserData.trigger_mgr_.Clear(); if (!PhysxCommon.Instance.InitPhyxsSDK()) { //LogMgr::GetInstance()->Error( // "[PhysxWorld]InitPhyxsSDK() cannot init physxSDK!!!!"); return; } _worldUserData = new WorldUserData(); CreatePxScene(); _worldUserData.is_init_world_ = true; } void CreatePxScene() { if (_worldUserData.px_scene_ != null) { _worldUserData.px_scene_->ReleaseMut(); _worldUserData.px_scene_ = null; } PxSceneDesc sceneDesc = PxSceneDesc_new(PxPhysics_getTolerancesScale(PhysxCommon.Instance.GetPhysics())); sceneDesc.gravity = new Vector3(0.0f, 0.0f, 0.0f); sceneDesc.cpuDispatcher = (PxCpuDispatcher*)PhysxCommon.Instance.GetCpuDispatcher(); delegate* callback; callback = &(PxConstValue.PhysxWorldFilterShader); sceneDesc.filterShader = (void*)(delegate* unmanaged[Cdecl])callback; //sceneDesc.simulationEventCallback = this; delegate* tmpContact = &onContact; _event_call_back->collision_callback = (delegate* unmanaged[Cdecl])tmpContact; //根据需要填写用户数据 _event_call_back->collision_user_data = null; delegate* tmpTrigger = &onTrigger; _event_call_back->trigger_callback = (delegate* unmanaged[Cdecl])tmpTrigger; _event_call_back->trigger_user_data = null; //其余方法没有重载 不需要设置回调函数 sceneDesc.simulationEventCallback = create_simulation_event_callbacks(_event_call_back); //TODO: 这个需要关注下 //sceneDesc.simulationEventCallback->OnContactMut(); //TODO count该如何传参数? fixed (PxTriggerPair* ptr = &_worldUserData.pairs) { sceneDesc.simulationEventCallback->OnTriggerMut(ptr, _worldUserData.count); } _worldUserData.px_scene_ = PxPhysics_createScene_mut(PhysxCommon.Instance.GetPhysics(), &sceneDesc); if (_worldUserData.px_scene_ == null) { //LogMgr::GetInstance()->Error( // "PhysxWorld::CreatePxScene() error:px_scene_ is null"); return; } } void ChangePVDStatus(bool flag = false) { if (_worldUserData.px_scene_ == null) return; PxPvdSceneClient* pvdClient = _worldUserData.px_scene_->GetScenePvdClientMut(); if (pvdClient != null) { pvdClient->SetScenePvdFlagMut(PxPvdSceneFlag.TransmitConstraints, flag); pvdClient->SetScenePvdFlagMut(PxPvdSceneFlag.TransmitContacts, flag); pvdClient->SetScenePvdFlagMut(PxPvdSceneFlag.TransmitScenequeries, flag); } } PxScene* GetActiveScene() { return _worldUserData.px_scene_; } bool IsInitWorld() { return _worldUserData.is_init_world_; } void SyncUser() { UInt32 nbDynamics = _worldUserData.px_scene_->GetNbActors(PxActorTypeFlags.RigidDynamic); if (nbDynamics < 1) { return; } //std::vector actors(nbDynamics); PxRigidActor*[] actors = new PxRigidActor*[nbDynamics]; fixed (PxRigidActor** actorPtr = actors) { _worldUserData.px_scene_->GetActors(PxActorTypeFlags.RigidDynamic, (PxActor**)actorPtr, nbDynamics, 0); } //PxSceneWriteLock scopedLock(*px_scene_); //PxSceneWriteLock* sceneLock = PxSceneWriteLock_new_alloc(px_scene_, null, 0); _worldUserData.px_scene_->LockWriteMut(null, 0); for (UInt32 a = 0; a < nbDynamics; ++a) { //PxRigidActor* actor = actors[a]->is < PxRigidActor > (); PxRigidActor* actor = actors[a]; if (actor == null) { continue; } // PxRigidDynamic* dynamic = static_cast(actor); PxRigidDynamic* dynamic = (PxRigidDynamic*)(actor); PxShape* shape; actor->GetShapes(&shape, 1, 0); PhysxObjectType type0 = PxConstValue.PhysxGetUserType(actor); if (type0 == PhysxObjectType.PX_AIRSHIP || type0 == PhysxObjectType.PX_MONSTER || type0 == PhysxObjectType.PX_MONSTERGROUP || type0 == PhysxObjectType.PX_TRIGGER) { //业务代码 } else if (type0 == PhysxObjectType.PX_SPELL) { //业务代码 } } _worldUserData.px_scene_->UnlockWriteMut(); //PxSceneWriteLock_delete(sceneLock); } void DeleteCollisionWorld() { if (!_worldUserData.is_init_world_ || _worldUserData.px_scene_ == null) return; UInt32 error; //px_scene_->simulate(STEP_SECOND); //px_scene_->SimulateMut(10); //px_scene_->fetchResults(true, &error); //TODO 10 是为了语法不报错 需要填写实际业务代码实际STEP_SECOND _worldUserData.px_scene_->SimulateMut(10, null, null, 0, controlSimulation: true); _worldUserData.px_scene_->FetchResultsMut(true, &error); //PxScene_fetchResults_mut(px_scene_, true, &error); _worldUserData.trigger_mgr_.Clear(); foreach (PxRigidActor* it in _worldUserData._physxBase._physicsActors) { if ((it != null) && (it->userData != null)) { //TODO //释放用户数据 it->userData = null; } } _worldUserData._physxBase.RemoveAllActor(); if (filter_callback_ != null) { //TODO: //delete filter_callback_; filter_callback_ = null; } //px_scene_->release(); _worldUserData.px_scene_->ReleaseMut(); _worldUserData.px_scene_ = null; _worldUserData.is_init_world_ = false; } void RemoveAirShipOrSpell(PxRigidActor* obj) { if (obj != null) { DeleteTriggerCallBack(obj); UInt32 error; _worldUserData.px_scene_->SimulateMut(10, null, null, 0, controlSimulation: true); _worldUserData.px_scene_->FetchResultsMut(true, &error); //PxSceneWriteLock scopedLock(*px_scene_); PxSceneWriteLock* sceneLock = PxSceneWriteLock_new_alloc(_worldUserData.px_scene_, null, 0); if (obj->userData != null) { //delete obj->userData; //TODO 释放用户数据 obj->userData = null; } _worldUserData._physxBase.RemoveActor(obj); PxSceneWriteLock_delete(sceneLock); } } void SetupFiltering(PxRigidActor* actor, UInt32 filterGroup, UInt32 filterMask) { _worldUserData.px_scene_->LockWriteMut(null, 0); PxFilterData filterData = default; filterData.word0 = filterGroup; // word0 = own ID filterData.word1 = filterMask; // word1 = ID mask to filter pairs that filterData.word3 |= (1 << 29); // trigger a contact callback; UInt32 numShapes = actor->GetNbShapes(); PxShape*[] shapes = new PxShape*[numShapes]; fixed (PxShape** p = shapes) { actor->GetShapes(p, numShapes, 0); for (UInt32 i = 0; i < numShapes; i++) { PxShape* shape = shapes[i]; //shape->setSimulationFilterData(filterData); shape->SetSimulationFilterDataMut(&filterData); } } _worldUserData.px_scene_->UnlockWriteMut(); } // world 类自身方法 end bool RayTest( PxRigidActor* actor, PxVec3 start_position, PxVec3 normalizedDir, int mask, int group, PhysxCollisionHitResult* hit_result, float distance = float.MaxValue) { if (actor == null) return false; PxRaycastHit* rayHit= stackalloc PxRaycastHit[1]; PxQueryFilterData filterData; filterData.flags = (PxQueryFlags)mask; PhysxWorldRaycastResultCb_1 CB = new PhysxWorldRaycastResultCb_1(&start_position, &normalizedDir); CB.callback = &(PhysxWorldRaycastResultCb_1.preFilter); PxQueryFilterCallback* fliterCallBack = create_raycast_filter_callback_func( (delegate* unmanaged[Cdecl])(CB.callback), (void*)&CB.userData); bool hasBlock = PxSceneQueryExt_raycastSingle(_worldUserData.px_scene_, &start_position, &normalizedDir, distance, PxHitFlags.Default,rayHit, &filterData, fliterCallBack, null); PxQueryFilterCallback_delete(fliterCallBack); if (hasBlock) { hit_result->hit_type = PxConstValue.PhysxGetUserType(rayHit->actor); hit_result->pos = rayHit->position; PxVec3 disPos = start_position.Multiply(&hit_result->pos); float length = disPos.Magnitude(); //TODO: //hit_result->user_ptr = rayHit.block.actor->userData; hit_result->shape_ptr = rayHit->shape; hit_result->actor_ptr = rayHit->actor; return true; } return false; } bool SweepCheck(PxGeometry* geometry, PxTransform* shapePose, PxVec3* unitDir, PhysxCollisionHitResult* hit_result) { if (_worldUserData.px_scene_ == null) return false; //PxSweepBuffer sweepHit =default; PxSweepHit sweepHit = default(PxSweepHit); PxQueryFilterData filterData = default; filterData.flags = PxQueryFlags.Static; float distance = 0.1f; bool hasHit = PxSceneQueryExt_sweepSingle(_worldUserData.px_scene_, geometry, shapePose, unitDir, distance, PxHitFlags.Default, &sweepHit, &filterData, null, null, 0.0f); if (hasHit = true) { //hit_result->hit_type = PxConstValue.PhysxGetUserType(sweepHit.actor); //// hit_result.pos = sweepHit.block.position; //hit_result->user_ptr = sweepHit.actor->userData; //hit_result->shape_ptr = sweepHit.shape; //hit_result->actor_ptr = sweepHit.actor; return true; } return false; } bool OverlapCheck(PxGeometry* geometry, PxTransform* shapePose, List hero_list) { if (_worldUserData.px_scene_ == null) return false; PxOverlapHit* hitBuffer = stackalloc PxOverlapHit[128]; PxQueryFilterData filterData; filterData.flags = PxQueryFlags.Dynamic; bool hasOverLap = PxSceneQueryExt_overlapAny(_worldUserData.px_scene_, geometry, shapePose, hitBuffer, null,null); if (hasOverLap ) { return true; } return false; } bool RayCastStatic( PxVec3 start_pos, PxVec3 normalized_dir, float distance = float.MaxValue) { //PxRaycastBuffer rayHits = default; PxRaycastHit rayHit = default; PxQueryFilterData filterData; filterData.flags = PxQueryFlags.Static; //注意normalized_dir 需要经过 标准向量化 bool hasblock = PxSceneQueryExt_raycastSingle(_worldUserData.px_scene_, &start_pos, &normalized_dir, distance, PxHitFlags.Default, &rayHit, &filterData, null, null); if (hasblock == true) { return true; } return false; } void RayCastDynamic(PxVec3 start_pos, PxVec3 normalized_dir, float distance, List* hero_list) { PxRaycastHit* rayHit = stackalloc PxRaycastHit[128]; PxQueryFilterData filterData = default; filterData.flags = PxQueryFlags.Dynamic; //如果查询数据超过128 最多返回128 经测试不会崩溃 int buffSize = PxSceneQueryExt_raycastMultiple(_worldUserData.px_scene_ , & start_pos, &normalized_dir, distance, PxHitFlags.Default, rayHit, 128 , null, &filterData, null ,null); for (int i = 0; i < buffSize; i++) { PxRigidActor* tmp = rayHit[i].actor; PhysxObjectType type = PxConstValue.PhysxGetUserType(tmp); if (type == PhysxObjectType.PX_AIRSHIP || type == PhysxObjectType.PX_MONSTER) { } } } //工具方法 end // 静态回调方法 public static void onTrigger(void* userData, PxTriggerPair* pairs, UInt32 count) { if (userData == null) { return; } WorldUserData* _worldUserData = (WorldUserData*)userData; for (UInt32 i = 0; i < count; i++) { PxTriggerPair* tp = &pairs[i]; // ignore pairs when shapes have been deleted if ((tp->flags & (PxTriggerPairFlags.RemovedShapeTrigger | PxTriggerPairFlags.RemovedShapeOther)) != 0) { continue; } if (tp->otherActor == null || tp->triggerActor == null) { continue; } //TriggerCallBackPtr cb_ptr = trigger_mgr_.FindTrigger(tp->triggerShape); //记得释放指针 TriggerCallBackPtr是智能指针定义 TriggerCallBack* cb_ptr = _worldUserData->trigger_mgr_.FindTrigger(tp->triggerShape); if (cb_ptr == null) { continue; } if ((tp->status & PxPairFlag.NotifyTouchFound) != 0) { cb_ptr->OnEnter((PxRigidActor*)tp->triggerActor, (PxRigidActor*)tp->otherActor, cb_ptr->effectType_); } else if ((tp->status & PxPairFlag.NotifyTouchLost) != 0) { cb_ptr->OnLeave((PxRigidActor*)tp->triggerActor, (PxRigidActor*)tp->otherActor, cb_ptr->effectType_); } } } public static void onContact(void* userData, PxContactPairHeader* pairHeader, PxContactPair* pairs, UInt32 nbPairs) { if (userData == null) { return; } WorldUserData* _worldUserData = (WorldUserData*)userData; //List contactPoints; IntPtr[] contactPoints = new IntPtr[128]; for (UInt32 i = 0; i < nbPairs; i++) { PxContactPair* cp = &pairs[i]; PhysxObjectType type0 = PxConstValue.PhysxGetUserType((PxRigidActor*)pairHeader->actors[0]); PhysxObjectType type1 = PxConstValue.PhysxGetUserType((PxRigidActor*)pairHeader->actors[1]); if (((int)cp->events & (int)(PxPairFlag.NotifyTouchFound | PxPairFlag.NotifyTouchCcd)) != 0) { UInt32 contactCount = cp->contactCount; if (contactCount < 1) continue; Array.Resize(ref contactPoints, (int)contactCount); //structgen_pad0 函数地址 fixed (IntPtr* contactPointsPtr = contactPoints) { PxContactPairPoint* conPtr0 = (PxContactPairPoint*)contactPointsPtr->ToPointer(); cp->ExtractContacts(conPtr0, contactCount); } for (UInt32 j = 0; j < contactCount; j++) { if ((type0 == PhysxObjectType.PX_AIRSHIP && type1 == PhysxObjectType.PX_STATICOBJECT) || (type1 == PhysxObjectType.PX_AIRSHIP && type0 == PhysxObjectType.PX_STATICOBJECT)) { PxRigidDynamic* dynamic = null; //KHero* hero = null; void* hero = null; // 用户数据 if (type0 == PhysxObjectType.PX_AIRSHIP) { //dynamic = Unsafe.AsRef(ptr); dynamic = (PxRigidDynamic*)(pairHeader->actors[0]); } else { //dynamic = Unsafe.AsRef(ptr); dynamic = (PxRigidDynamic*)(pairHeader->actors[0]); } if (dynamic != null) { //hero = static_cast(dynamic->userData)->is < KHero *> (); //if (!hero || hero->hit_wall_) continue; //UInt64 now = KG_GetTickCount(); //TODO:需要根据实际业务完善 UInt64 now = 100; if (now - _worldUserData->test_sync_time_ <= 1000) continue; if (type1 != PhysxObjectType.PX_STATICOBJECT) continue; //auto player = hero->GetOwnerPlayer(); //if (!player) continue; //PxRigidStatic* static_actor = static_cast(pairHeader.actors[1]); PxRigidStatic* static_actor = (PxRigidStatic*)(pairHeader->actors[1]); UInt32 num = ((PxRigidActor*)(static_actor))->GetNbShapes(); PxShape*[] shapes = new PxShape*[num]; fixed (PxShape** p = shapes) { UInt32 nbShapes = ((PxRigidActor*)(static_actor))->GetShapes(p, num, 0); if (num != nbShapes) continue; } //将碰撞盒子发给客户端显示 //List geometry_list; for (UInt32 k = 0; k < num; k++) { //if (shapes[k]->GetGeometryType() != PxGeometryType.Box) // continue; //必须这么写 和system GetType重名了 总是会调用System GetType var geoType = NativeMethodsGroupingExtensions.GetType(ref *shapes[k]->GetGeometry()); if (geoType != PxGeometryType.Box) continue; PxVec3 st_pos = ((PxRigidActor*)(static_actor))->GetGlobalPose().p; PxQuat st_quat = ((PxRigidActor*)(static_actor))->GetGlobalPose().q; //GeometryInfo info; if (shapes[k]->GetGeometry() != null) { PxBoxGeometry* box_geometry = (PxBoxGeometry*)(shapes[k]->GetGeometry()); //业务代码 } } _worldUserData->test_sync_time_ = now; } continue; } else if ((type0 == PhysxObjectType.PX_AIRSHIP || type0 == PhysxObjectType.PX_MONSTER) && type1 == PhysxObjectType.PX_SPELL) { //业务代码 } else if (type0 == PhysxObjectType.PX_SPELL && (type1 == PhysxObjectType.PX_AIRSHIP || type1 == PhysxObjectType.PX_MONSTER)) { //业务代码 } else if (type0 == PhysxObjectType.PX_SPELL && type1 == PhysxObjectType.PX_STATICOBJECT) { //业务代码 } else if (type0 == PhysxObjectType.PX_STATICOBJECT && type1 == PhysxObjectType.PX_SPELL) { //业务代码 } } } else if (((int)cp->events & (int)PxPairFlag.NotifyTouchLost) != 0) { if ((type0 == PhysxObjectType.PX_AIRSHIP && type1 == PhysxObjectType.PX_STATICOBJECT) || (type1 == PhysxObjectType.PX_AIRSHIP && type0 == PhysxObjectType.PX_STATICOBJECT)) { PxRigidDynamic* dynamic = null; //KHero* hero = null; void* hero = null; //业务代码 if (type0 == PhysxObjectType.PX_AIRSHIP) { dynamic = (PxRigidDynamic*)(pairHeader->actors[0]); } else { dynamic = (PxRigidDynamic*)(pairHeader->actors[1]); } if (dynamic != null) { if (dynamic->userData != null) { // hero = static_cast(dynamic->userData)->is < KHero *> (); } if (hero == null) { // hero->hit_wall_ = false; } } } } } } public static void onConstraintBreak(void* userData, PxConstraintInfo* info, UInt32 flag) { } public static void onWake(void* userData, PxActor** actors, UInt32 count) { } public static void onSleep(void* userData, PxActor** actors, UInt32 count) { } public static void onAdvance(void* userData, PxRigidBody** ppRigid, PxTransform* pTrans, UInt32 nb) { } } }