Skip to content

Commit 32e341c

Browse files
authored
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 1c9b03e.
1 parent c424213 commit 32e341c

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

sources/engine/Stride.Physics.Tests/ColliderShapesTest.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static bool ScreenPositionToWorldPositionRaycast(Vector2 screenPos, Camer
3737
if (hitResult.Succeeded)
3838
{
3939
return true;
40-
}
40+
}
4141
}
4242

4343
return false;
@@ -243,6 +243,51 @@ public void ColliderShapesTest1()
243243
Assert.Equal(0.0f, (new Vector3(-2.861034E-06f, 3.889218E-06f, -1f) - hit.Normal).Length(), 3f);
244244
Assert.Equal(0.0f, (new Vector3(-5.366335f, -0.08297831f, -17.9267f) - hit.Point).Length(), 3f);
245245

246+
game.Exit();
247+
});
248+
RunGameTest(game);
249+
}
250+
251+
/// <summary>
252+
/// Verify PhysicsComponent creation through the use of GetOrCreate<T>
253+
/// If component is added this way, must ensure ColliderShape is properly setup if added later
254+
/// </summary>
255+
[Fact]
256+
public void VerifyColliderShapeSetup()
257+
{
258+
var game = new ColliderShapesTest();
259+
game.Script.AddTask(async () =>
260+
{
261+
game.ScreenShotAutomationEnabled = false;
262+
await game.Script.NextFrame();
263+
await game.Script.NextFrame();
264+
265+
var simulation = game.SceneSystem.SceneInstance.RootScene.Entities.First(ent => ent.Name == "Simulation").Get<StaticColliderComponent>().Simulation;
266+
var cube = game.SceneSystem.SceneInstance.RootScene.Entities.First(ent => ent.Name == "CubePrefab1");
267+
268+
var body = cube.GetOrCreate<RigidbodyComponent>();
269+
270+
//verify values not properly set up
271+
Assert.Null(body.ColliderShape);
272+
Assert.Equal(RigidBodyTypes.Static, body.RigidBodyType);
273+
Assert.False(body.OverrideGravity);
274+
275+
//for further debug, can set breakpoint and check body.Simulation.discreteDynamicWorld.CollisionObjectArray before and after
276+
//the collider shape is attached to see it properly added
277+
278+
//add collider shape
279+
body.ColliderShape = new SphereColliderShape(false, 1.0f);
280+
//check if proper colliderShape setup took place
281+
Assert.True(body.ColliderShape != null);
282+
Assert.Equal(ColliderShapeTypes.Sphere, body.ColliderShape.Type);
283+
Assert.Equal(RigidBodyTypes.Dynamic, body.RigidBodyType);
284+
285+
body.OverrideGravity = true;
286+
//to verify InternalRigidBody was properly set up we can change properties such as Mass or OverrideGravity
287+
//that normally would return void if there are no InternalRigidBody values
288+
Assert.True(body.OverrideGravity);
289+
290+
246291
game.Exit();
247292
});
248293
RunGameTest(game);

sources/engine/Stride.Physics/Elements/RigidbodyComponent.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ public float Mass
8585

8686
mass = value;
8787

88-
if (InternalRigidBody == null) return;
88+
if (InternalRigidBody == null)
89+
{
90+
return;
91+
}
92+
8993

9094
var inertia = ColliderShape.InternalShape.CalculateLocalInertia(value);
9195
InternalRigidBody.SetMassProps(value, inertia);
@@ -114,7 +118,11 @@ public override ColliderShape ColliderShape
114118
return;
115119

116120
if (InternalRigidBody == null)
121+
{
122+
//When setting ColliderShape, setup could have been previously skipped (eg when PhysicsComponent is created using GetOrCreate)
123+
ReAttach();
117124
return;
125+
}
118126

119127
if (NativeCollisionObject != null)
120128
NativeCollisionObject.CollisionShape = value.InternalShape;
@@ -193,7 +201,11 @@ public bool OverrideGravity
193201
{
194202
overrideGravity = value;
195203

196-
if (InternalRigidBody == null) return;
204+
if (InternalRigidBody == null)
205+
{
206+
return;
207+
}
208+
197209

198210
if (value)
199211
{
@@ -341,6 +353,7 @@ protected override void OnAttach()
341353

342354
protected override void OnDetach()
343355
{
356+
344357
MotionState.Dispose();
345358
MotionState.Clear();
346359

sources/engine/Stride.Physics/Engine/PhysicsComponent.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,32 @@ internal void Attach(PhysicsProcessor.AssociatedData data)
681681
}
682682
}
683683

684+
/// <summary>
685+
/// Ran when properties of Components may not be fully setup and need to be reintegrated (eg GetOrCreate<RigidbodyComponent> and adding collidershapes)
686+
/// </summary>
687+
internal void ReAttach()
688+
{
689+
//TODO: Could consider fully detaching and then rebuilding, but ideally this would cause null refs on Rigidbody OnDetach calls
690+
//Shouldnt call detach, because at this point the user has added new components and this runs as a check to rebuild as needed.
691+
//Entire wipes to rebuild causes loss in the data that the user has just added (and is slower)
692+
693+
Entity.Transform.UpdateWorldMatrix();
694+
695+
BoneIndex = -1;
696+
697+
OnAttach();
698+
699+
//ensure ignore collisions
700+
if (ignoreCollisionBuffer != null && NativeCollisionObject != null)
701+
{
702+
foreach (var kvp in ignoreCollisionBuffer)
703+
{
704+
IgnoreCollisionWith(kvp.Key, kvp.Value);
705+
}
706+
ignoreCollisionBuffer = null;
707+
}
708+
}
709+
684710
internal void Detach()
685711
{
686712
Data = null;

0 commit comments

Comments
 (0)