feat(scripting): expose PhysX rigidbody and raycast APIs

This commit is contained in:
2026-04-15 13:58:30 +08:00
parent 914c9361ed
commit bda8a35d77
13 changed files with 787 additions and 0 deletions

View File

@@ -5,9 +5,11 @@
#include "Components/LightComponent.h"
#include "Components/MeshFilterComponent.h"
#include "Components/MeshRendererComponent.h"
#include "Components/RigidbodyComponent.h"
#include "Components/TransformComponent.h"
#include "Debug/Logger.h"
#include "Input/InputManager.h"
#include "Physics/PhysicsWorld.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Scene/Scene.h"
#include "Scripting/ScriptComponent.h"
@@ -44,6 +46,7 @@ enum class ManagedComponentKind {
Unknown,
Script,
Transform,
Rigidbody,
Camera,
Light,
MeshFilter,
@@ -144,6 +147,10 @@ ManagedComponentTypeInfo ResolveManagedComponentTypeInfo(MonoClass* monoClass) {
typeInfo.kind = ManagedComponentKind::Transform;
return typeInfo;
}
if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "Rigidbody") {
typeInfo.kind = ManagedComponentKind::Rigidbody;
return typeInfo;
}
if (typeInfo.namespaceName == "XCEngine" && typeInfo.className == "Camera") {
typeInfo.kind = ManagedComponentKind::Camera;
return typeInfo;
@@ -263,6 +270,8 @@ Components::Component* FindNativeComponent(Components::GameObject* gameObject, M
switch (componentKind) {
case ManagedComponentKind::Transform:
return gameObject->GetTransform();
case ManagedComponentKind::Rigidbody:
return gameObject->GetComponent<Components::RigidbodyComponent>();
case ManagedComponentKind::Camera:
return gameObject->GetComponent<Components::CameraComponent>();
case ManagedComponentKind::Light:
@@ -300,6 +309,10 @@ Components::Component* AddOrGetNativeComponent(Components::GameObject* gameObjec
switch (componentKind) {
case ManagedComponentKind::Transform:
return gameObject->GetTransform();
case ManagedComponentKind::Rigidbody:
return gameObject->GetComponent<Components::RigidbodyComponent>()
? static_cast<Components::Component*>(gameObject->GetComponent<Components::RigidbodyComponent>())
: static_cast<Components::Component*>(gameObject->AddComponent<Components::RigidbodyComponent>());
case ManagedComponentKind::Camera:
return gameObject->GetComponent<Components::CameraComponent>()
? static_cast<Components::Component*>(gameObject->GetComponent<Components::CameraComponent>())
@@ -441,12 +454,47 @@ Components::MeshRendererComponent* FindMeshRendererComponent(uint64_t gameObject
return gameObject ? gameObject->GetComponent<Components::MeshRendererComponent>() : nullptr;
}
Components::RigidbodyComponent* FindRigidbodyComponent(uint64_t gameObjectUUID) {
Components::GameObject* gameObject = FindGameObjectByUUID(gameObjectUUID);
return gameObject ? gameObject->GetComponent<Components::RigidbodyComponent>() : nullptr;
}
Components::Space ResolveManagedSpace(int32_t value) {
return value == static_cast<int32_t>(Components::Space::World)
? Components::Space::World
: Components::Space::Self;
}
Physics::PhysicsBodyType ResolveManagedPhysicsBodyType(int32_t value) {
switch (value) {
case static_cast<int32_t>(Physics::PhysicsBodyType::Static):
return Physics::PhysicsBodyType::Static;
case static_cast<int32_t>(Physics::PhysicsBodyType::Kinematic):
return Physics::PhysicsBodyType::Kinematic;
case static_cast<int32_t>(Physics::PhysicsBodyType::Dynamic):
default:
return Physics::PhysicsBodyType::Dynamic;
}
}
Physics::PhysicsForceMode ResolveManagedForceMode(int32_t value) {
switch (value) {
case static_cast<int32_t>(Physics::PhysicsForceMode::Acceleration):
return Physics::PhysicsForceMode::Acceleration;
case static_cast<int32_t>(Physics::PhysicsForceMode::Impulse):
return Physics::PhysicsForceMode::Impulse;
case static_cast<int32_t>(Physics::PhysicsForceMode::VelocityChange):
return Physics::PhysicsForceMode::VelocityChange;
case static_cast<int32_t>(Physics::PhysicsForceMode::Force):
default:
return Physics::PhysicsForceMode::Force;
}
}
Physics::PhysicsWorld* FindRuntimePhysicsWorld() {
return ScriptEngine::Get().GetRuntimePhysicsWorld();
}
MonoArray* CreateManagedComponentArray(MonoClass* componentClass, const std::vector<MonoObject*>& components) {
if (!componentClass) {
return nullptr;
@@ -750,6 +798,9 @@ MonoArray* InternalCall_GameObject_GetComponents(uint64_t gameObjectUUID, MonoRe
case ManagedComponentKind::Transform:
appendNativeComponents(gameObject->GetComponents<Components::TransformComponent>());
break;
case ManagedComponentKind::Rigidbody:
appendNativeComponents(gameObject->GetComponents<Components::RigidbodyComponent>());
break;
case ManagedComponentKind::Camera:
appendNativeComponents(gameObject->GetComponents<Components::CameraComponent>());
break;
@@ -1533,6 +1584,200 @@ void InternalCall_MeshRenderer_SetRenderLayer(uint64_t gameObjectUUID, int32_t v
component->SetRenderLayer(static_cast<uint32_t>(std::max(value, 0)));
}
int32_t InternalCall_Rigidbody_GetBodyType(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
return component
? static_cast<int32_t>(component->GetBodyType())
: static_cast<int32_t>(Physics::PhysicsBodyType::Dynamic);
}
void InternalCall_Rigidbody_SetBodyType(uint64_t gameObjectUUID, int32_t value) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetBodyType(ResolveManagedPhysicsBodyType(value));
}
float InternalCall_Rigidbody_GetMass(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
return component ? component->GetMass() : 1.0f;
}
void InternalCall_Rigidbody_SetMass(uint64_t gameObjectUUID, float value) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetMass(value);
}
float InternalCall_Rigidbody_GetLinearDamping(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
return component ? component->GetLinearDamping() : 0.0f;
}
void InternalCall_Rigidbody_SetLinearDamping(uint64_t gameObjectUUID, float value) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetLinearDamping(value);
}
float InternalCall_Rigidbody_GetAngularDamping(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
return component ? component->GetAngularDamping() : 0.05f;
}
void InternalCall_Rigidbody_SetAngularDamping(uint64_t gameObjectUUID, float value) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetAngularDamping(value);
}
void InternalCall_Rigidbody_GetLinearVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outVelocity) {
if (!outVelocity) {
return;
}
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
*outVelocity = component ? component->GetLinearVelocity() : XCEngine::Math::Vector3::Zero();
}
void InternalCall_Rigidbody_SetLinearVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* velocity) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component || !velocity) {
return;
}
component->SetLinearVelocity(*velocity);
}
void InternalCall_Rigidbody_GetAngularVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* outVelocity) {
if (!outVelocity) {
return;
}
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
*outVelocity = component ? component->GetAngularVelocity() : XCEngine::Math::Vector3::Zero();
}
void InternalCall_Rigidbody_SetAngularVelocity(uint64_t gameObjectUUID, XCEngine::Math::Vector3* velocity) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component || !velocity) {
return;
}
component->SetAngularVelocity(*velocity);
}
mono_bool InternalCall_Rigidbody_GetUseGravity(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
return (component && component->GetUseGravity()) ? 1 : 0;
}
void InternalCall_Rigidbody_SetUseGravity(uint64_t gameObjectUUID, mono_bool value) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetUseGravity(value != 0);
}
mono_bool InternalCall_Rigidbody_GetEnableCCD(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
return (component && component->GetEnableCCD()) ? 1 : 0;
}
void InternalCall_Rigidbody_SetEnableCCD(uint64_t gameObjectUUID, mono_bool value) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetEnableCCD(value != 0);
}
void InternalCall_Rigidbody_AddForce(uint64_t gameObjectUUID, XCEngine::Math::Vector3* force, int32_t forceMode) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component || !force) {
return;
}
component->AddForce(*force, ResolveManagedForceMode(forceMode));
}
void InternalCall_Rigidbody_ClearForces(uint64_t gameObjectUUID) {
Components::RigidbodyComponent* component = FindRigidbodyComponent(gameObjectUUID);
if (!component) {
return;
}
component->ClearForces();
}
mono_bool InternalCall_Physics_Raycast(
XCEngine::Math::Vector3* origin,
XCEngine::Math::Vector3* direction,
float maxDistance,
uint64_t* outHitGameObjectUUID,
XCEngine::Math::Vector3* outHitPoint,
XCEngine::Math::Vector3* outHitNormal,
float* outHitDistance,
int32_t* outHitIsTrigger) {
if (outHitGameObjectUUID) {
*outHitGameObjectUUID = 0;
}
if (outHitPoint) {
*outHitPoint = XCEngine::Math::Vector3::Zero();
}
if (outHitNormal) {
*outHitNormal = XCEngine::Math::Vector3::Zero();
}
if (outHitDistance) {
*outHitDistance = 0.0f;
}
if (outHitIsTrigger) {
*outHitIsTrigger = 0;
}
Physics::PhysicsWorld* physicsWorld = FindRuntimePhysicsWorld();
if (!physicsWorld || !origin || !direction) {
return 0;
}
Physics::RaycastHit hit;
if (!physicsWorld->Raycast(*origin, *direction, maxDistance, hit)) {
return 0;
}
if (outHitGameObjectUUID) {
*outHitGameObjectUUID = hit.gameObject ? hit.gameObject->GetUUID() : 0;
}
if (outHitPoint) {
*outHitPoint = hit.point;
}
if (outHitNormal) {
*outHitNormal = hit.normal;
}
if (outHitDistance) {
*outHitDistance = hit.distance;
}
if (outHitIsTrigger) {
*outHitIsTrigger = hit.isTrigger ? 1 : 0;
}
return 1;
}
void InternalCall_Rendering_SetRenderPipelineAssetType(MonoReflectionType* assetType) {
if (assetType == nullptr) {
Rendering::Pipelines::ClearManagedRenderPipelineAssetDescriptor();
@@ -1681,6 +1926,25 @@ void RegisterInternalCalls() {
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetReceiveShadows", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_SetReceiveShadows));
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_GetRenderLayer", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_GetRenderLayer));
mono_add_internal_call("XCEngine.InternalCalls::MeshRenderer_SetRenderLayer", reinterpret_cast<const void*>(&InternalCall_MeshRenderer_SetRenderLayer));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetBodyType", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetBodyType));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetBodyType", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetBodyType));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetMass", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetMass));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetMass", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetMass));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetLinearDamping", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetLinearDamping));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetLinearDamping", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetLinearDamping));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetAngularDamping", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetAngularDamping));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetAngularDamping", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetAngularDamping));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetLinearVelocity", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetLinearVelocity));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetLinearVelocity", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetLinearVelocity));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetAngularVelocity", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetAngularVelocity));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetAngularVelocity", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetAngularVelocity));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetUseGravity", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetUseGravity));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetUseGravity", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetUseGravity));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_GetEnableCCD", reinterpret_cast<const void*>(&InternalCall_Rigidbody_GetEnableCCD));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_SetEnableCCD", reinterpret_cast<const void*>(&InternalCall_Rigidbody_SetEnableCCD));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_AddForce", reinterpret_cast<const void*>(&InternalCall_Rigidbody_AddForce));
mono_add_internal_call("XCEngine.InternalCalls::Rigidbody_ClearForces", reinterpret_cast<const void*>(&InternalCall_Rigidbody_ClearForces));
mono_add_internal_call("XCEngine.InternalCalls::Physics_Raycast", reinterpret_cast<const void*>(&InternalCall_Physics_Raycast));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_SetRenderPipelineAssetType", reinterpret_cast<const void*>(&InternalCall_Rendering_SetRenderPipelineAssetType));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_GetRenderPipelineAssetTypeName", reinterpret_cast<const void*>(&InternalCall_Rendering_GetRenderPipelineAssetTypeName));
@@ -2459,6 +2723,7 @@ bool MonoScriptRuntime::IsSupportedComponentFieldClass(MonoClass* monoClass) con
}
return className == "Transform"
|| className == "Rigidbody"
|| className == "Camera"
|| className == "Light"
|| className == "MeshFilter"
@@ -2853,6 +3118,8 @@ bool MonoScriptRuntime::DestroyManagedObject(MonoObject* managedObject) {
const ManagedComponentTypeInfo typeInfo = ResolveManagedComponentTypeInfo(monoClass);
switch (typeInfo.kind) {
case ManagedComponentKind::Rigidbody:
return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent<Components::RigidbodyComponent>());
case ManagedComponentKind::Camera:
return DestroyNativeComponentInstance(gameObject, gameObject->GetComponent<Components::CameraComponent>());
case ManagedComponentKind::Light:
@@ -3075,6 +3342,8 @@ bool MonoScriptRuntime::TrySetFieldValue(
bool hasComponent = false;
if (className == "Transform") {
hasComponent = targetObject->GetTransform() != nullptr;
} else if (className == "Rigidbody") {
hasComponent = targetObject->GetComponent<Components::RigidbodyComponent>() != nullptr;
} else if (className == "Camera") {
hasComponent = targetObject->GetComponent<Components::CameraComponent>() != nullptr;
} else if (className == "Light") {

View File

@@ -74,6 +74,7 @@ void ScriptEngine::SetRuntimeFixedDeltaTime(float fixedDeltaTime) {
void ScriptEngine::OnRuntimeStart(Components::Scene* scene) {
const float configuredFixedDeltaTime = m_runtimeFixedDeltaTime;
Physics::PhysicsWorld* configuredPhysicsWorld = m_runtimePhysicsWorld;
OnRuntimeStop();
m_runtimeFixedDeltaTime = configuredFixedDeltaTime;
@@ -81,6 +82,7 @@ void ScriptEngine::OnRuntimeStart(Components::Scene* scene) {
return;
}
m_runtimePhysicsWorld = configuredPhysicsWorld;
m_runtimeScene = scene;
m_runtimeRunning = true;
m_runtime->OnRuntimeStart(scene);
@@ -118,6 +120,7 @@ void ScriptEngine::OnRuntimeStop() {
if (!m_runtimeRunning) {
m_runtimeScene = nullptr;
m_runtimePhysicsWorld = nullptr;
m_scriptStates.clear();
m_scriptOrder.clear();
m_runtimeFixedDeltaTime = DefaultFixedDeltaTime;
@@ -137,6 +140,7 @@ void ScriptEngine::OnRuntimeStop() {
m_scriptOrder.clear();
m_runtimeRunning = false;
m_runtimeScene = nullptr;
m_runtimePhysicsWorld = nullptr;
m_runtimeFixedDeltaTime = DefaultFixedDeltaTime;
m_runtime->OnRuntimeStop(stoppedScene);
}
@@ -144,6 +148,7 @@ void ScriptEngine::OnRuntimeStop() {
void ScriptEngine::OnRuntimeSceneReplaced(Components::Scene* scene) {
if (!m_runtimeRunning) {
m_runtimeScene = nullptr;
m_runtimePhysicsWorld = nullptr;
m_runtimeSceneCreatedSubscription = 0;
m_scriptStates.clear();
m_scriptOrder.clear();