Physx/PhysxWorld.cs
2023-07-31 14:10:52 +08:00

1293 lines
53 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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, //<Collide with nothing
PX_COL_AIR_SHIP = 1 << 1, //<Collide with ships
PX_COL_STATIC_OBJ = 1 << 2, //<Collide with static_obj
PX_COL_SPELL_OBJ = 1 << 3, //<Collide with spell data
PX_COL_SPELL_TARGET_STATIC_OBJ = 1 << 4, // Collide with spell target obj
PX_COL_MONSTER_GROUP_OBJ = 1 << 5, // Collide with monster target obj
PX_COL_TRIGGER_OBJ = 1 << 6,
PX_COL_MONSTER = 1 << 7 // Collide with skill obj
};
public enum PhysxTestTypes
{
PX_CCD = 1 << 29, // CCD type
};
//碰撞结果 放在common中更合适
public unsafe struct PhysxCollisionHitResult
{
public PhysxCollisionHitResult()
{
hit_type = PhysxObjectType.PX_INVALIDE;
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 0.0f;
user_ptr = null;
shape_ptr = null;
actor_ptr = null;
}
public bool HasResult() { return hit_type != PhysxObjectType.PX_INVALIDE; }
public PhysxObjectType hit_type;
public PxVec3 pos;
public void* user_ptr;
public PxShape* shape_ptr;
public PxRigidActor* actor_ptr;
};
//struct ClassType
//等效于 Unsafe.AsRef<PxRigidStatic>(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]<UInt32, PxFilterData, UInt32, PxFilterData, PxPairFlags*, void*, UInt32, PxFilterFlags> 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*<PxRigidActor*, PxFilterData*, PxShape*, uint, void*, PxQueryHitType> 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<TriggerCallBack>( shape, effectType, effectValue, std::forward<TRIGGER_FUNC>(enter), std::forward<TRIGGER_FUNC>(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<physx::PxRigidDynamic*>()->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*<UInt32, PxFilterData, UInt32, PxFilterData, PxPairFlags*, void*, UInt32, PxFilterFlags> callback;
callback = &(PxConstValue.PhysxWorldFilterShader);
sceneDesc.filterShader = (void*)(delegate* unmanaged[Cdecl]<UInt32, PxFilterData, UInt32, PxFilterData, PxPairFlags*, void*, UInt32, PxFilterFlags>)callback;
//sceneDesc.simulationEventCallback = this;
delegate*<void*, PxContactPairHeader*, PxContactPair*, uint, void> tmpContact = &onContact;
_event_call_back->collision_callback = (delegate* unmanaged[Cdecl]<void*, PxContactPairHeader*, PxContactPair*, uint, void>)tmpContact;
//根据需要填写用户数据
_event_call_back->collision_user_data = null;
delegate*<void*, PxTriggerPair*, uint, void> tmpTrigger = &onTrigger;
_event_call_back->trigger_callback = (delegate* unmanaged[Cdecl]<void*, PxTriggerPair*, uint, void>)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<PxRigidActor*> 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<PxRigidDynamic*>(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]<PxRigidActor*, PxFilterData*, PxShape*, uint, void*, PxQueryHitType>)(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<IntPtr> 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<IntPtr>* 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<PxContactPairPoint> 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<IntPtr>(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<PxRigidDynamic>(ptr);
dynamic = (PxRigidDynamic*)(pairHeader->actors[0]);
}
else
{
//dynamic = Unsafe.AsRef<PxRigidDynamic>(ptr);
dynamic = (PxRigidDynamic*)(pairHeader->actors[0]);
}
if (dynamic != null)
{
//hero = static_cast<ClassType*>(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<PxRigidStatic*>(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<GeometryInfo> 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<ClassType*>(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) { }
}
}