Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECS based asset components #186

Closed
7 tasks done
azriel91 opened this issue Mar 12, 2020 · 0 comments
Closed
7 tasks done

ECS based asset components #186

azriel91 opened this issue Mar 12, 2020 · 0 comments
Assignees
Labels
M: code Code maintenance and quality.

Comments

@azriel91
Copy link
Owner

In GitLab by @azriel91 on Nov 13, 2019, 15:15

Desired outcome

System that spawns entities with all the components associated with the asset-entity.

Background

Two use cases:

  • State transition.

    • Each State has collective assets.
    • Each collective asset describes the entities to create when a State is created / resumed.
  • On demand.

Implementation options

Ran into the issue that currently WaitSequenceHandles (and all other sequences components) are loaded per asset, not per item. This means we need to choose one of:

  • clone() these per item (which means cloning many, many Vec<_>s).
  • Use Handle<_>s to those types (which would mean 2 layers of handles, not great).
  • Store that kind of data per asset ID, which would be a mess to track / discover what is item level data, vs asset level data.
  • Reorganize configuration to declare sequences per item.
  • Maintain the AssetItem maps, but introduce ItemIds for each AssetId,

    1. Simply replace AssetId in the AssetItem maps with ItemId
    2. Have another map: Map<AssetId, Vec<ItemId>>, and on a particular event, an entity is spawned for each of the ItemIds.
    let asset_id = asset_id_mappings.insert(asset_slug);
    let mut item_ids = asset_definition
        .items
        .iter()
        .map(|item| asset_item_count.get_and_increment())
        .collect::<Vec<ItemId>>();
    
    // If there is more than one list of items.
    let mut item_ids_other = asset_definition
        .items_other
        .iter()
        .map(|item| asset_item_count.get_and_increment());
    item_ids.append(&mut item_ids_other);
    
    asset_item_ids.insert(asset_id, item_ids);
    
    // Loading
    position_inits.insert(item_id, position_init);
    ui_labels.insert(item_id, ui_label);
    ui_sprite_labels.insert(item_id, ui_sprite_label);
    wait_sequence_handleses.insert(item_id, wait_sequence_handles);
    sprite_render_sequence_handleses.insert(item_id, sprite_render_sequence_handles);
  • ComponentStorages for asset components.

    1. For each asset_slug, generate a new ItemId(Entity) per entity to instantiate.
    2. Insert (asset) components against the entity, e.g. PositionInit, WaitSequenceHandles
    let mut position_inits = asset_definition
        .items
        .iter()
        .map(|item| if condition { Some(position_init) } else { None })
        .collect::<Vec<Option<ItemComponent>>>();
    let mut position_inits_other = asset_definition
        .items_other
        .iter()
        .map(|item| if condition { Some(position_init) } else { None });
    position_inits.append(&mut position_inits_other);
    
    // Loading
    // Type alias simply makes it clearer that we should use a separate `World` instance.
    type AssetWorld = World;
    let entity = asset_world
        .create_entity()
        .with(position_init)
        .with(ui_label)
        .with(ui_sprite_label)
        .with(wait_sequence_handles)
        .with(sprite_render_sequence_handles)
        .build();
    let item = Item::new(entity);
    items.push(item);
    
    asset_item_ids.insert(asset_id, items);

Usage

  1. When instantiating an item, simply insert the Item(entity) as a component:

    let entity = entities
        .build_entity()
        .with(item, items)
        .build();
    
    // That's it!
    // Possible rectification e.g. for spawning objects in game.
  2. Implement a (type parameterized?) system that, when an Item entity is inserted as a component onto another entity, that entity is initialized with all of the components associated with that Item.

    Note: Currently the SequenceComponentUpdateSystem subscribes to SequenceUpdateEvents, and based on the AssetId attached to an entity, it goes asset_scd.get(asset_id), then let component = sequence_component_data.get(sequence_id);

    // Object assets
    world.create_entity()
        .with(asset_id)
        .with(wait_sequence_handles)
        .with(spawns_sequence_handles)
        // ..
        .build();
    
    // UI assets
    world.create_entity()
        .with(asset_id)
        .with(position_init)
        .with(ui_label)
        .with(ui_sprite_label)
        .build();

Tasks:

  • Create AssetWorld, and make all AssetItem items Components.

  • Load Vec<Option<ItemComponent>> for each asset item. Can clone() item components for now.

  • Create ItemId(Entity), and initialize an ItemId(Entity) per item from each asset.

  • System that reads ComponentEvents from ReadStorage<'_, ItemId>.

    For insertions / modifications, join over all asset-components, inserting (overwriting?) the components onto the entity.

  • Type parameterized system that inserts Components based on ItemComponent existence for ItemId.

  • Remove AssetItem types.

  • Create SequenceIdMappings per UI item instead of per asset.

    Right now, wait sequence handles etc. are loaded from 0 for UiDefinition, but the sequence ID mappings starts at n = background_definition.layers.len().

@azriel91 azriel91 added the M: code Code maintenance and quality. label Mar 12, 2020
@azriel91 azriel91 added this to the Configuration Maintenance milestone Mar 12, 2020
@azriel91 azriel91 self-assigned this Mar 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
M: code Code maintenance and quality.
Projects
None yet
Development

No branches or pull requests

1 participant