Arch-ECS
💬 Join the discord!☕ Buy us a coffee!
  • 🌄Why Arch?
  • 📖Documentation
    • Concepts
    • World
    • Entity
    • Query
    • Archetypes & Chunks
    • Optimizations
      • Query-Techniques
      • Pass on data
      • Batch and Bulk
      • PURE_ECS
      • Multithreading
      • EntityData
    • Utilities
      • Component Registration
      • Non-generic API
      • CommandBuffer
      • Events
      • Dangerous Extensions
  • 🧩Extensions
    • Arch.Extended
      • Arch.System
      • Arch.System.SourceGenerator
      • Arch.EventBus
      • Arch.AOT.SourceGenerator
      • Arch.LowLevel
      • Arch.Persistence
      • Arch.Relationships
  • 💡Examples & Guidelines
    • Arch.Samples
    • Entities in Query
    • Structural changes
  • Unity
  • 🎮Projects using Arch
    • Skylandkingdoms
    • Cubetory
    • SS14
    • EquilibriumEngine-CSharp
    • Rougelite-Survivor
  • ✏️Misc
    • Roadmap
    • FAQ
Powered by GitBook
On this page
  • Create in Query
  • Modify in Query
  • Delete in Query
  • Why is that?

Was this helpful?

Edit on GitHub
  1. Examples & Guidelines

Entities in Query

Entities in Query, how to handle entities in queries correctly and what to bear in mind.

PreviousArch.SamplesNextStructural changes

Last updated 2 months ago

Was this helpful?

We need to have another serious talk about what you can and should and should not do in ! So sit down and listen!

In principle, we recommend the use of a when it comes to creating or deleting entities in a query or changing their structure. Or to simply make these changes outside a query. Changes to component values are never a problem.

Create in Query

Creating entities in Queries is harmless for the time being, nothing can go wrong.

world.Query(queryDesc, (ref DwarfSpawner spawner) => {
    
    if(!spawner.CanSpawnDwarf()) return;
    world.Create<Dwarf, Position, Velocity>();
});

The entities are created appropriately, everything is great. Arch iterates from back to front, new entities are appended at the end and therefore not reached during the query.

Modify in Query

You can usually edit existing data on entities without any problems.

world.Query(queryDesc, (ref Dwarf dwarf) => {
    dwarf.Health++;  // healing the dwarf
});

You just have to be careful whether it is a reference or a copy.

But there is one case where you really have to be careful and that is when you add or remove components.

world.Query(queryDesc, (Entity entity, ref Dwarf dwarf) => {
    entity.Add<Pickaxe>();
    entity.Remove<Helmet>();
});

Delete in Query

This is where it gets interesting and fun. Let's take a look at this case.

world.Query(queryDesc, (in Entity entity, ref Dwarf dwarf) => {
    
    if(!CanDeleteDwarf()) return;  // A random chance
    world.Destroy(RandomDwarf());
});
world.Query(queryDesc, (in Entity entity, ref Dwarf dwarf) => {
    world.Destroy(entity);
});

This is fine, we iterate all Dwarfs one by one and all of them are being deleted.

What also works, of course, is deleting entities in a query that we are not currently iterating over.

world.Query(queryDesc, (in Entity entity, ref Dwarf dwarf) => {
    world.Destroy(RandomElf());
});

This also works fine, since we are not deleting any Entity from the current iteration.

Why is that?

The reason

You're probably wondering why we don't just install a few security checks to prevent this kind of behavior? Good question!

Arch's mantra is “Pay what you use” to ensure maximum performance. Arch does nothing in the background to slow down your code, so you need to know what you are doing and sometimes check yourself.

This has pros and cons, one advantage is clean code and performance. In the future Arch will get optional security checks.

You have to be careful here. It is generally recommended NOT to change the structure of an entity during a query. It may work, but it directly moves the entity to another , which can lead to problems. We therefore recommend extensive testing or the .

This won't work and will lead to issues. We are iterating over all Dwarfs and deleting one randomly. When an Entity is deleted, the last entity from the takes the place of the deleted entity to keep the list without gaps. In this case, it can happen that we iterate over an entity twice because it takes the place of the deleted entity during the iteration

In such a case, we should use the or maintain our own list of entities, which we then delete ourselves after the Query. What works, however, is if we have a deterministic order when deleting.

💡
Querys
CommandBuffer
Archetype
CommandBuffer
Archetype
CommandBuffer