fix: PhysicsComponent created with GetOrCreate<T> is unusable (#2422)

* Run proper Rigidbody setup when adding ColliderShape

* Added test case for proper setup with GetOrCreate

* Followed similar Bepu format with creation of ReAttach method

* Reformatted files edited

* Revert "Reformatted files edited"

This reverts commit 1c9b03eb6e.
This commit is contained in:
Dylan Loe 2024-08-30 12:02:58 -07:00 коммит произвёл GitHub
Родитель c424213701
Коммит 32e341ca05
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 87 добавлений и 3 удалений

Просмотреть файл

@ -37,7 +37,7 @@ namespace Stride.Physics.Tests
if (hitResult.Succeeded)
{
return true;
}
}
}
return false;
@ -243,6 +243,51 @@ namespace Stride.Physics.Tests
Assert.Equal(0.0f, (new Vector3(-2.861034E-06f, 3.889218E-06f, -1f) - hit.Normal).Length(), 3f);
Assert.Equal(0.0f, (new Vector3(-5.366335f, -0.08297831f, -17.9267f) - hit.Point).Length(), 3f);
game.Exit();
});
RunGameTest(game);
}
/// <summary>
/// Verify PhysicsComponent creation through the use of GetOrCreate<T>
/// If component is added this way, must ensure ColliderShape is properly setup if added later
/// </summary>
[Fact]
public void VerifyColliderShapeSetup()
{
var game = new ColliderShapesTest();
game.Script.AddTask(async () =>
{
game.ScreenShotAutomationEnabled = false;
await game.Script.NextFrame();
await game.Script.NextFrame();
var simulation = game.SceneSystem.SceneInstance.RootScene.Entities.First(ent => ent.Name == "Simulation").Get<StaticColliderComponent>().Simulation;
var cube = game.SceneSystem.SceneInstance.RootScene.Entities.First(ent => ent.Name == "CubePrefab1");
var body = cube.GetOrCreate<RigidbodyComponent>();
//verify values not properly set up
Assert.Null(body.ColliderShape);
Assert.Equal(RigidBodyTypes.Static, body.RigidBodyType);
Assert.False(body.OverrideGravity);
//for further debug, can set breakpoint and check body.Simulation.discreteDynamicWorld.CollisionObjectArray before and after
//the collider shape is attached to see it properly added
//add collider shape
body.ColliderShape = new SphereColliderShape(false, 1.0f);
//check if proper colliderShape setup took place
Assert.True(body.ColliderShape != null);
Assert.Equal(ColliderShapeTypes.Sphere, body.ColliderShape.Type);
Assert.Equal(RigidBodyTypes.Dynamic, body.RigidBodyType);
body.OverrideGravity = true;
//to verify InternalRigidBody was properly set up we can change properties such as Mass or OverrideGravity
//that normally would return void if there are no InternalRigidBody values
Assert.True(body.OverrideGravity);
game.Exit();
});
RunGameTest(game);

Просмотреть файл

@ -85,7 +85,11 @@ namespace Stride.Physics
mass = value;
if (InternalRigidBody == null) return;
if (InternalRigidBody == null)
{
return;
}
var inertia = ColliderShape.InternalShape.CalculateLocalInertia(value);
InternalRigidBody.SetMassProps(value, inertia);
@ -114,7 +118,11 @@ namespace Stride.Physics
return;
if (InternalRigidBody == null)
{
//When setting ColliderShape, setup could have been previously skipped (eg when PhysicsComponent is created using GetOrCreate)
ReAttach();
return;
}
if (NativeCollisionObject != null)
NativeCollisionObject.CollisionShape = value.InternalShape;
@ -193,7 +201,11 @@ namespace Stride.Physics
{
overrideGravity = value;
if (InternalRigidBody == null) return;
if (InternalRigidBody == null)
{
return;
}
if (value)
{
@ -341,6 +353,7 @@ namespace Stride.Physics
protected override void OnDetach()
{
MotionState.Dispose();
MotionState.Clear();

Просмотреть файл

@ -681,6 +681,32 @@ namespace Stride.Engine
}
}
/// <summary>
/// Ran when properties of Components may not be fully setup and need to be reintegrated (eg GetOrCreate<RigidbodyComponent> and adding collidershapes)
/// </summary>
internal void ReAttach()
{
//TODO: Could consider fully detaching and then rebuilding, but ideally this would cause null refs on Rigidbody OnDetach calls
//Shouldnt call detach, because at this point the user has added new components and this runs as a check to rebuild as needed.
//Entire wipes to rebuild causes loss in the data that the user has just added (and is slower)
Entity.Transform.UpdateWorldMatrix();
BoneIndex = -1;
OnAttach();
//ensure ignore collisions
if (ignoreCollisionBuffer != null && NativeCollisionObject != null)
{
foreach (var kvp in ignoreCollisionBuffer)
{
IgnoreCollisionWith(kvp.Key, kvp.Value);
}
ignoreCollisionBuffer = null;
}
}
internal void Detach()
{
Data = null;