Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Zakarum
@omni-viral
You won't send pointers over the wire, right? :)
Michael Patraw
@mpatraw
hell yeah i would
:P
hmmmmmmmm
@eggmund

any tips for working with tasks that require comparing the current entity with every other entity? For example, getting the gravitational force between each entity with mass and position. I can't find a clean way to do it. I end up using .collect() on a join to collect components, then iterate through that vec like:

for i in 0..objects.len()-1 {
    for j in i+1..objects.len() {
       // Check and do stuff
    }
}

But this seems very inefficient

WaDelma
@WaDelma
You can do two for (entity, component) in (&*entities, &components).join() { and check that entities are not the same. Though that will check both directions which is not optimal depending on what you are doing. If you want mutable access to something you can do components.get_mut(entity)
hmmmmmmmm
@eggmund
thanks for the response, seems like a good idea. I might use the entity id's to check in one direction and see if that works
lowercase1024
@lowercase1024
Hi! I'm learning specs and ECS and have an architectural issue. Consider a tic tac toe game. There should be a game board state stored somewhere. And there should be a logic checking who wins, setting cell values (either X or O). I came from OOP world, so I'd make a GameBoard struct with all the logic tied to it (except rendering, just cell access and check who wins) and use it as a resource. I choose resource, because it doesn't relate to an entity, so that's correct, I suppose. But would it be more appropriate to make some kind of system containing the logic instead of impl block for the GameBoard struct? I know, tic tac toe is not the type of games I should be making with ECS, but just as an example.
Zakarum
@omni-viral
This is not really good example.
In ECS you are encouraged to make objects into entities
But here you have at most 9 objects with no behavior and the only its state is X or O and position
Making them into entities is a waste
+ you still need a resource for collision detection (attempt to place X or O into occupied cell should fail)
which will hold almost all the data
So here is what you get
/// Resource
struct Board { cells: [[Option<Entity>; 3]; 3] }
#[derive(Component)]
struct X;
#[derive(Component)]
struct O;

impl System {
  fn run((input, board, xs, os): ...) {
    ...
  }
}
Zakarum
@omni-viral
Looks awful but this is how tic tac toe game will look in ECS spirt
lowercase1024
@lowercase1024
Wow, I didn't realize tic tac toe was that bad for ECS :D
Ok then, thank you! I'll try and search for some ECS examples to get more into it.
Zakarum
@omni-viral
In any case you are encouraged to put "business"-logic in the systems
And only small pieces in the type's impls
As the rule of thumb if more than 1 system needs it - put it into type's impl or free function
But, for example, checking winning condition should be in WinningConditionSystem
Another system can read input events and place new Xs and Os
Surely, small systems that tied together can be merged into one, but two separate system illustrate ECS approach better
dmitsuki
@dmitsuki
Is it possible to iterate over all component types in a world? For normal functions the ecs system model works great, but I'm trying to make an inspector that exist outside of the purview of the ecs and needs to show data for all components an entity might implement. It happens before the ecs dispatcher actually runs, so I don't care about the mutability or anything of particular component stores, I just need a way to check if an entity has a certain component, and get the values from the components stored in world
Right now I'm thinking I might have to register component types with a macro and iterate over a list of strings, but I'd rather avoid that :P
Zakarum
@omni-viral
How you imagine that working? World stores components type erased, you need actual type to downcast storage value
Can you, for example, write signature for function that will "iterate over all component types in a world"?
dmitsuki
@dmitsuki
Can't you get a resource with try_fetch_internal or get_mut_raw? If so, you can have a function like "register_component_with_inspector" that takes the world its registering to, and also has a vec of typeID's, and save the type id for the type that you are adding, and then at runtime iterate over a list of those typeid's using try_fetch_internal or get_mut_raw, or am I misunderstanding somethign?
Zakarum
@omni-viral
Even if you get resource's typeids, you will only get Box<Any>
You still need an actual type
What you can do is to prepare a closure for each registered resource/storage
Which can downcast and do some predefined operations with it
dmitsuki
@dmitsuki
Do you mean something like having a map of closures, which take a type id as a key and return a closure that returns a type and cast teh Box<Any> to the type?
Zakarum
@omni-viral
I suggest map TypeId to FnMut(&mut Any)
i.e gives you closure that internally knows the type, casts and does what it needs to be done
It can't return downcasted type, cuz, you know, all those closures should have same signature
XBagon
@XBagon_gitlab
hey! does someone have any advice how I would efficiently get the amount of entities in a join and probably then cache and update it accordingly?
WaDelma
@WaDelma
I am not sure what you are asking. Can you give some simple example or more details?
XBagon
@XBagon_gitlab
hm, well I thought about trying to combine specs with some methods to "bulk simulate" find entities that have specific components and instead of doing something for each of them, do it for the amount of them instead and save the relative change to then be able to lazyily retrieve it when acting on a single entity for example. Though I'm not sure how feasible that is and how big the performance improvement really could be. especially when you have to save these things for 1000s of component combinations and also have to calculate changes for broader combinations, when having changes to more specific ones... maybe I got a bit carried away
Ghost
@ghost~5d4078b1d73408ce4fc75281
Hi! I'm trying to wrap my head around specs and specs-hierarchy. In specs is it possible to add a component to an existing entity? If so, how?
WaDelma
@WaDelma
@danaugrs_twitter You can use https://docs.rs/specs/0.15.0/specs/storage/struct.Storage.html#method.insert to add components to existing entities.
Ghost
@ghost~5d4078b1d73408ce4fc75281
Figured it out - thanks!
Is there any way to modify the order that entities/components are obtained from a .join() iterator? e.g. for z-ordering?
WaDelma
@WaDelma
@torkleyy Is there reason for not implementing Send for Dispatcher? I asked this in slide-rs/shred#147 but never got answer and now it's merged
David Komer
@dakom
Is specs suitable for wasm where there's no real multithreading (yet)?
Martin Jensen
@malynome
Hey everyone, sorry if this is a noob question(or if there is an example somewhere, although I couldnt find any), but how would I go about "comparing" entities to each other when running a system, i.e. pairwise iteration, for something like collision detection? If i also want to mutate in that system? Or is it better to separate collision detection and collision handling into 2 systems? - Thanks in advance if anyone is able to help!
Roman Holovin
@roman-holovin

Hi, I've been working on the movement system and got an issue:

impl<'a> System<'a> for DestinationMovement {
    type SystemData = (
        Entities<'a>,
        WriteStorage<'a, Position>,
        ReadStorage<'a, Speed>,
        ReadStorage<'a, Destination>,
        ReadExpect<'a, Timings>,
        ReadExpect<'a, Map>,
    );

    fn run(
        &mut self,
        (entities, mut positions, speeds, destinations, timings, map): Self::SystemData,
    ) {
                for (_entity, speed, destination, position) in
            (&entities, &speeds, &destinations, &mut positions).join()
        {
                let destination_position = positions.get(destination.0).cloned().unwrap();

                // rest of the code is irrelevant
        }
    }
}

Some entities have a destination, which is wrapper over Entity, and to calculate a path to destination I need to retrieve destination's position. Naturally, I also want to have own position of the current entity itself.

Issue is that iterator mutably borrows positions, so I cannot use it inside loop. For me it looks like a very common issue, so maybe there is known solution for this problem?

I could remove positions dependency from join and get both entity and destination position inside loop, but I don't like that it will relax component requirements for this system. Another potential solution I can think of, but haven't tried, is to collect all new positions into separate Vec and then assign them with another loop. I don't like performance implications of this approach and unsoundness of it.

Is there anything else I can do?

WaDelma
@WaDelma
@dakom Specs can be used in wasm if you disable parallel feature
David Komer
@dakom
yup! got it working :D
WaDelma
@WaDelma
@roman-holovin I think you can use mask method and get similar dependency for join, but without access to component and then get the positions. I am not sure how restrict* are supposed to be used actually. Maybe those could also be used?
WaDelma
@WaDelma
@malynome You can do join within join by using just Entities to get both entities, then compare them for inequality and then access storages. In our game I think we first did that, but now were doing simple sweep-and-prune by using flagged storage to maintain internal data structure.