You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue is to discuss an ergonomics issue that I've faced both in Bones ECS and in Bevy ECS, and to explore whether or not there's a good solution.
The scenario is simple:
I have a custom system parameter named CollisionWorld that contains helper methods and logic around detecting collisions and manipulating the physics world.
As a part of that CollisionWorld parameter, I borrow the Transform components mutably. This allows me to, as a part of collision world methods like translate move entities, and also to get the entities positions, as is necessary for collision detection.
This causes an ergonomics problem when any the user wants to include both a CollisionWorld system param, and a CompMut<Transforms> system param, because that is a conflict: you have two mutable borrows of Transform components.
The current solution in my WIP branch in jumpy is to make the transforms: CompMut<Transform> field of CollisionWorld public. This allows you to access a borrow of the transforms, but it's not a perfect solution, and users are not going to expect that it's impossible to borrow both their own transforms argument, and the CollisionWorld.
Also, considering the situation where the CollisionWorldand another system parameter needs to borrow CompMut<Transform>, there is no good workaround.
This is partially just a limitation of the way borrowing works. The issue is "solved" in Bevy using ParamSets which usually feels un-ergonomic, but again, there's only so much we can do in Rust, where we must make our borrowing intentions clear at compile time. We can't have two mutable references to the Transform components at the same time. The only way around this is to delay the actual borrowing of the components, requiring an extra lock()/borrow() step.
Maybe we make a Defer system parameter, that wraps around other system parameters, deferring the borrow, and requiring an extra borrow() call to do runtime borrow checking later in the function.
In that case you would be allowed to have transforms: Defer<CompMut<Transform>> and collision_world: Defer<CollisionWorld> in your system params, but you would have to .borrow() them before you could use them, and you wouldn't be able to .borrow() them at the same time without a panic at runtime.
Or we make an equivalent to ParamSets in Bones?
Finally, another alternative, is to have CollisionWorld use it's own component to represent the entity positions, and this component must be synchronized somehow with the Transform component. This is also a foot-gun because it's easy to forget to synchronize the values, and that there is in fact a separate CollisionWorld version of the entity position.
This discussion was converted from issue #86 on February 07, 2023 19:23.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
This issue is to discuss an ergonomics issue that I've faced both in Bones ECS and in Bevy ECS, and to explore whether or not there's a good solution.
The scenario is simple:
I have a custom system parameter named
CollisionWorld
that contains helper methods and logic around detecting collisions and manipulating the physics world.As a part of that
CollisionWorld
parameter, I borrow theTransform
components mutably. This allows me to, as a part of collision world methods liketranslate
move entities, and also to get the entities positions, as is necessary for collision detection.This causes an ergonomics problem when any the user wants to include both a
CollisionWorld
system param, and aCompMut<Transforms>
system param, because that is a conflict: you have two mutable borrows ofTransform
components.The current solution in my WIP branch in jumpy is to make the
transforms: CompMut<Transform>
field ofCollisionWorld
public. This allows you to access a borrow of thetransforms
, but it's not a perfect solution, and users are not going to expect that it's impossible to borrow both their owntransforms
argument, and theCollisionWorld
.Also, considering the situation where the
CollisionWorld
and another system parameter needs to borrowCompMut<Transform>
, there is no good workaround.This is partially just a limitation of the way borrowing works. The issue is "solved" in Bevy using
ParamSets
which usually feels un-ergonomic, but again, there's only so much we can do in Rust, where we must make our borrowing intentions clear at compile time. We can't have two mutable references to theTransform
components at the same time. The only way around this is to delay the actual borrowing of the components, requiring an extralock()
/borrow()
step.Maybe we make a
Defer
system parameter, that wraps around other system parameters, deferring the borrow, and requiring an extraborrow()
call to do runtime borrow checking later in the function.In that case you would be allowed to have
transforms: Defer<CompMut<Transform>>
andcollision_world: Defer<CollisionWorld>
in your system params, but you would have to.borrow()
them before you could use them, and you wouldn't be able to.borrow()
them at the same time without a panic at runtime.Or we make an equivalent to
ParamSet
s in Bones?Finally, another alternative, is to have
CollisionWorld
use it's own component to represent the entity positions, and this component must be synchronized somehow with theTransform
component. This is also a foot-gun because it's easy to forget to synchronize the values, and that there is in fact a separateCollisionWorld
version of the entity position.Beta Was this translation helpful? Give feedback.
All reactions