bevy_ecs_ldtk
bevy_ecs_ldtk copied to clipboard
"relations" feature
With LDtk 1.0, field instances can now store a reference to another entity. Ever since, I've been thinking about how to properly allow users to transform these references into "relational" components that store an Entity
object.
Here's the plan.
- Create a new default feature called "relations" to make most of the following optional
- Make
ldtk::FieldInstanceEntityReference
bothHash
andComponent
, maybe rename it to justEntityReference
- Give all LDtk entities spawned by the plugin an
EntityReference
component. - When spawning a level, create a
HashMap<EntityReference, Entity>
of all currently-spawned and soon-to-be-spawned LDtk entities, and pass it as a new argument into theLdtkEntity
creation functions. - Create a new derivable
LdtkRelation
trait for constructing relational components. - Create an
#[entity]
field attribute forLdtkRelation
for marking anEntity
field, or maybe just make it smart enough to construct anyEntity
fields w/o an attribute. - Create a new
#[ldtk_relation("FIELD_IDENTIFIER")]
field attribute for theLdtkEntity
derive that uses theLdtkRelation
constructor to create the component from the entity reference field with the given field identifier.
Example:
#[derive(Component, LdtkRelation)]
struct MyRelation {
#[entity]
entity: Entity,
other_info: i32,
}
#[derive(Bundle, LdtkEntity)]
struct MyBundle {
#[ldtk_relation("my_reference_field_identifier")]
relation: MyRelation,
#[sprite_sheet_bundle]
sprite_sheet_bundle: SpriteSheetBundle,
}
It might also be worth considering supporting deriving LdtkRelation
on tuple structs, but I'm not exactly sure how to do that nicely.
As far as WHEN to implement all of this, it'd probably be good to aim for 0.3
, but that's a lot of work so I'd like to say at least get steps 1-4 in for 0.3
to allow users to manually create relational components in their custom LdtkEntity
derives.
I think there's too many questions remaining about the design of this:
- How can we give things an
EntityReference
component when there's noworld_iid
for non-multi-world projects? - Should we use a simpler
EntityIid
component that just contains the entity's iid for the references instead? - If we use
EntityIid
, should we refactorWorldly
to be just a marker component, and change its logic to use that entity'sEntityIid
instead? - If we make a
HashMap<EntityReference, Entity>
while spawning levels, how can we guarantee that it's going to contain the entities users will need? - What if the desired entity is spawned in a level whose
LevelEvent::SpawnTriggered
is in the same update, but later in theEventReader
? - What if the desired entity is not in a currently loaded level, and not in a level that's going to be loaded in this update? Can we reserve entities for ALL entity instances in the LDtk file?
- Should we just support entity references within a single level to avoid these questions?
- Can we generalize the idea of a new field-instance-related trait like
LdtkRelation
, combined with providing field instance identifiers inLdtkEntity
attribute macros, to make component constructors inLdtkEntity
using any field instance type?
I think it's been a long enough wait for 0.3
, so we can give ourselves another release to think some of this through. I'm not confident enough in the current plan or any of these alternatives to make a decision right now.
Hi, I'm trying out bevy_ecs_ldtk
this weekend for the first time and it's fantastic so far!
I was trying to figure out how to get Entity
s from FieldInstanceEntityReference
s, but it sounds like there isn't an easy way yet? I was starting to think I would tag all my loaded entities with a component that stored that information (similar to what you're proposing here).
I'm too new to have strong opinions about a lot of the things you bring up here, but I can report back on what path I take since I do need entity references to work in my game 🙂