Comments (10)
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.
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.
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.
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.
That's the theory. Unfortunately, as discussed in #20, the proposed interface runs afoul of rustc bugs regardless of implementation.
from hecs.
I am using hecs for a game, and I need to add/remove components while iterating the world or a query.
from hecs.
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.
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.
@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.
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)
- [Question/Clarification] Are bundles suppose to be able to be used as queries? HOT 2
- Ability to create a query view directly from `World` HOT 5
- Component cloning HOT 4
- Determinism through serialization cycle HOT 10
- Is it possible to clone World? With use case. HOT 6
- Queries that add/remove components HOT 1
- derive(Query) doesn't support query transformers
- Multithreading HOT 2
- Confused with different query methods HOT 4
- Missing null pointer check in archetype grow function. HOT 3
- Less than ideal codegen for iteration HOT 2
- !Sync + !Send Component HOT 2
- Document CommandBuffer.remove() will not remove any if it does not match all components
- Add ability to take components off a `TakenEntity` HOT 5
- hecs::Query should handle type parameters HOT 2
- Query by DynamicBundle HOT 3
- Entity Relationships HOT 7
- How do you run commands after performing a query? HOT 3
- (De)Serialization example HOT 1
- WASM / Parallelism in WASM support? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hecs.