Query-Techniques

A new order is needed to command your entities even more efficiently.

Arch has a number of different ways to search and iterate over entities. There are currently exactly 4 ways to issue commands to your entities in queries.

While this may seem a bit complex at first, each of these ways has advantages and disadvantages and is perfect for specific situations. Let us start...

All the queries listed below have been kept simple; each variant naturally also has the option of accessing the entity itself or other functionalities.

Query

Firstly, there is the type of query with which all examples were listed. Small and legible, you hardly have to worry.

World.Query(in desc,  => {
   Move(ref pos, ref vel);
});
  • Less code

  • Can use methods/delegates

  • Great for prototyping

  • Uses delegates, which is slow that the code can not be inlined.

  • All components can only be passed with ref, no security.

  • Rather slow compared to other techniques, still fast though.

  • Enclosure copies probably.

Inline-Query

As an alternative, we have the slightly faster version, which is also wonderfully reusable by distributing its tasks in structs.

public struct VelocityUpdate : <Position, Velocity> {

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Update(ref Position pos, ref Velocity vel) { 
        Move(ref pos, ref vel);
    }
}

world.<VelocityUpdate, Position, Velocity>();  
  • Damn fast

  • Uses struct and interface, can be inlined

  • Allows an order and modularization of the code

  • An instance of the structs can be passed through to process data

  • Requires more boilerplate code

  • All components can only be passed with ref, no security.

Custom enumeration

A little more manual labour, but an incredible amount of flexibility. This gives you the opportunity to design everything according to your wishes!

var query = world.Query(in desc);
foreach(ref var chunk in query.GetChunkIterator())
{
   var references =   
                          
   {
       
       ref var vel = ref Unsafe.Add(ref references.t1, entity);
       Move(ref pos, ref vel);
   }
}
  • The fastest query variant

  • Is also inlined

  • Allows custom query logic

  • SIMD

  • Own multithreading

  • Great for hotpaths

  • Requires the most boilerplate code

  • Bad for prototypes or fast coding

Source-Generation

The last variant is the source-generated queries. These are provided by Arch's rich ecosystem and can be integrated separately. They generate the code for you as if you had written it manually. Fast, efficient and simple. What more could you want?

[Query] 
// [All<...>, Any<...>, None<...>] to filter
// [Parallel] for multithreading
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MoveEntity(, ref Position pos,  Velocity vel)  
{
    Move(ref pos, ref vel, ref time);
}
  • Same as the custom query

  • Less code

  • Declarative syntax

  • Allows passing on data into the query with ease

  • You can use in, ref and out for components

  • Requires Arch.Extended

  • Code generator, probably not available for all platforms

Last updated