Giter Club home page Giter Club logo

Comments (10)

Ralith avatar Ralith commented on September 17, 2024 3

New idea:

for mut entry in world.entries::<(&T, &U)>().iter() {
    let (t, u) = entry.get(); // uniquely borrows entry
    // ...
    if should_destroy {
        entry.remove(); // consumes entry by value, invalidating component references
    }
}

This could also support adding/removing individual components from the iterated entity. It wouldn't permit modifying/creating/destroying other entities, but it might still be quite useful, and I believe it avoids the rustc limitations we ran into with the original plan while also being considerably more ergonomic.

from hecs.

Ralith avatar Ralith commented on September 17, 2024 1

For now, you should approach that by deferring the work until after the query, e.g. by collecting a list of components to add/remove in a Vec.

from hecs.

cedric-h avatar cedric-h commented on September 17, 2024

Some code samples that illustrate how a code sample would look with modify, using the workaround, and in specs where storages can be borrowed separately (at the cost of slow iteration)

// increment the plant timers,
// emit particles if they go up a stage.
// (amount of particles to emit is stored in growth stage)
world.modify::<&mut GrowthStage, _>(
    |growth_stage| {
        growth_stage.timer += 1;
        if growth_stage.timer >= growth_stage.duration {
            growth_stage.advance();
            Some(growth_stage.particle_count)
        } else {
            None
        }
    },
    |mut world, growing_ent, particle_count| {
        world.insert_one(growing_ent, ParticleEmitter {
            count: particle_count,
            .. ParticleEmitter::default()
        });
    }
);

/* versus:
 * how you have to do it now */

let needs_particles: Vec<_> = world.query::<&mut GrowthStage>()
    .iter()
    .filter_map(|(id, growth_stage)| {
        growth_stage.timer += 1;
        if growth_stage.timer >= growth_stage.duration {
            growth_stage.advance();
            Some((id, growth_stage.particle_count))
        } else {
            None
        }
    })
    .collect();

for (growing_ent, particle_count) in needs_particles.iter() {
    world.insert_one(ent, ParticleEmitter {
        count: particle_count,
        .. ParticleEmitter::default()
    });
}

/* versus:
 * specs approximation */
let mut particle_emitters = world.fetch_mut::<ParticleEmitter>();
let mut growth_stages = world.fetch_mut::<GrowthStages>();

for (growing_ent, mut growth_stage) in (&*world.entities(), &mut growth_stages) {
    growth_stage.timer += 1;
    if growth_stage.timer >= growth_stage.duration {
        growth_stage.advance();
        particle_emitters.insert(
            growing_ent,
            ParticleEmitter {
                count: growth_stage.particle_count,
                .. ParticleEmitter::default()
            },
        );
    }
}

from hecs.

1tgr avatar 1tgr commented on September 17, 2024

it does not enable anything you can't already do by making two passes and storing intermediate data in a Vec

Can the framework implementation take shortcuts (in the way that safe user code can't) so that the intermediate Vec is skipped?

from hecs.

Ralith avatar Ralith commented on September 17, 2024

That's the theory. Unfortunately, as discussed in #20, the proposed interface runs afoul of rustc bugs regardless of implementation.

from hecs.

Zireael07 avatar Zireael07 commented on September 17, 2024

I am using hecs for a game, and I need to add/remove components while iterating the world or a query.

from hecs.

BiosElement avatar BiosElement commented on September 17, 2024

Working on a roguelike movement system and have the following which seems a horrid mess. Anyone smarter than me have suggestions on a better way to do this? Basically querying for a component with an entity id and the desired position, then querying for the entity's current position and updating it, then finally deleting the WantsToMove component entity.

pub fn process_movement(world: &mut World) {
    println!("Processing movement boss!");
    let mut to_move = Vec::<MovingEntity>::new();
    for (id, wants_to_move) in &mut world.query::<&WantsToMove>() {
        to_move.push(MovingEntity {
            id: id,
            delta: Position {
                x: wants_to_move.x,
                y: wants_to_move.y,
            },
        });
    }

    for entity in &to_move {
        for (id, pos) in &mut world.query::<&mut Position>() {
            pos.x += entity.delta.x;
            pos.y += entity.delta.y;
        }
    }

    for entity in to_move {
        world.despawn(entity.id).unwrap();
    }
}

from hecs.

Ralith avatar Ralith commented on September 17, 2024

I'm not sure what you're trying to do there; you're adding every single position delta to every single entity, then despawning every single entity that wanted to move?

from hecs.

BiosElement avatar BiosElement commented on September 17, 2024

@Ralith Apologies I wasn't as clear as I thought! I'm roughly working through HandsOnRust using hecs rather than legion and modeled it after the 'movement intents' system.

The current process is as follows.

Query for any entities which want to move which are created solely for this task. Then query for the entities that want to move to get their position and move them. Finally, despawn all the move request entities.

Thinking about it now, it seems a global vector containing movement requests would make more sense than using ECS currently, but I'd appreciate any suggestions as I'm still learning a lot. :)

from hecs.

Ralith avatar Ralith commented on September 17, 2024

I'm not familiar with HandsOnRust, but that does sound like an unnecessarily complex and obscure solution to the hypothetical problem. I wouldn't recommend using the ECS to represent things other than logical entities; in general, hecs promotes using external data structures whenever that's more convenient. Storing requests in a vector on the side is likely to be the most convenient, because you can easily and efficiently populate it while iterating. You could later translate that back into components for the entities that want to move, but it would likely be simpler to consume directly.

Taken at face value, the most immediate issue I see with the above code is that you seem to be applying every WantsToMove to every Position, which seems unlikely to have been the intent.

from hecs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.