4

I am not quite sure if I completely understand the Entity Component System approach, and probably that is one of the reasons for the emergence of this question. Still struggling with the OOP mindset!

I am trying to create a data structure similar to a network, so for instance, something like a circuit:

Circuit.

So, for instance, entity 4 is connected to 1, 1 to 2, and so on. So far I have understood how to create the components, but I can't understand how the connectivity information should be stored. I believe that the entity should point to another entity?!? I have also imagined that would be even better practice to have a component that would have the connectivity information, but in that case, once again, what should it store? Ideally would be the entities themself, right? How to do it?

1 Answers1

3

You should always refer to other entities using their Id and don't store pointers to them between System runs.

Entity id in Bevy stored in struct Entity Note:

Lightweight unique ID of an entity.

Also, if this network is something unique for your game (e.g. there are maximum one instance in whole game) than it's connectivity data can be stored in the "resource". You get most benefits from Entity-Component part of ECS when your entities and components are created and processed in large quantities.

I cannot say anything more about your particular use-case because I don't know how many networks there would be, how you plan use them and interact with them. ECS is DDD pattern (Data-Driven Development) so architecture depends on how much data exists, which properties this data has and how it is used.

Example of multiple networks

If you have multiple networks, you can store them in such fashion:

#[derive(Component)]
struct NetworkTag; // Any entity with this tag is network.

// Spawn network into world like this
let network_id: Entity = world.spawn()
     .insert(NetworkTag)
     .id();

And you can store parts of electric network in such fashion:

#[derive(Component)]
struct PlusConnections(Vec<Entity>);

#[derive(Component)]
struct NetworkId(Entity);

// Spawn part into world like this
let part_id = world.spawn()
       .insert(NetworkId(network_id))
       .insert(PlusConnections(other_part_ids));

After finishing spawning parts like that, you would know only connections on plus side but you can fill negative side in separate system, for example:

#[derive(Component)]
struct NegConnections(Vec<Entity>);

fn fill_negatives_system(
   query_el_parts: Query<(Entity, &PlusConnections)>,
   query_el_parts_wo_neg: Query<Entity, Without<NegConnections>>,
   mut commands: Commands
){
   let mut positive_to_negative: HashMap<Entity, Vec<Entity>> = HashMap::new();
   for (neg, pc) in query_el_parts.iter(){
       for &positivein pc.0.iter(){
          positive_to_negative.entry(positive).or_default().push(neg);
       }
   }
   for (pos, negatives) in positive_to_negative{
      commands.entity(pos).insert(NegConnections(negatives));
   }
   // At the next tick, all nodes in electric grid would know what is their negative and positive connections and in which networks they are stored.
}

  • While I don't know the OP's use-case either, this is what I can take from one diagram (and can see myself using in an app). Say you have four electrical components (Entities) - switch, battery, resistor, LED. Each one is connected to two (or more) others, and direction matters. So I might want a query that would say, "what is connected to this LED", and get back that there is one battery on its positive-pole, and a resistor on the negative-pole. I'm not really clear how Resources would help do that - aren't they World/global objects, anyway? – John C Jul 16 '22 at 19:46
  • Well, if I store those network components as entities with components and I have only one network, I can store their links in such fashion: `struct Network { negatives: HashMap>, positive_conns: HashMap> }`. So, having id of LED, we can lookup which connections it have then query those other components from Query. If I have multiple networks, I can store those connections in separate component (e.g. `struct PositiveConnections(Vec`)) and attach them to each part of network. – Angelicos Phosphoros Jul 16 '22 at 20:07
  • Well, I don't understand ECS enough to know if this will work, and it doesn't look like the OP is going to enlighten me, but hey, it *looks* good, so have a bounty. :) – John C Jul 21 '22 at 01:05