ECSpanse - an Entity Component System framework for Elixir

I know @ConnorRigby dabbles with game development using Elixir for the server part:

1 Like

New release v0.3.1

Fixes

  • fixes a bug where events could be scheduled after they were batched for the current frame, and before the current events are cleared, causing some events to be lost. Thanks to @andzdroid for identifying and documenting the issue.
  • fixes a bug where temporary timers would crash. Thanks to @holykol for finding and fixing the issue.

Features

  • imports Ecspanse.Query and Ecspanse.Command in all systems, so all the queries and commands are available without needing the respective module prefix.
  • imports Ecspanse in the setup module that use Ecspanse so the system scheduling functions are available without needing the module prefix.

If you are using the library, please update it to 0.3.1 to get rid of the 2 bugs.

I updated also the 2 demo projects to use the latest version.

1 Like

I tried to create 1000 entities, but the fps drops to 1 per second.

I also tried creating 10000 entities, this never got past initialization (or took more time than I was willing to wait).

Thank you for doing the test.

What was your use case? Did you try it with the I’ve seen things demo project and switch the player count to 1000?

Or did you build your own custom example?

  1. If you tried with the demo project, please remember that this is not optimized. As said, it was just a side project to build while developing the library. I think many things can be done differently there.
    Also, if you spawn 1000 players, that means probably around 5-6000 entities.

  2. If on the other hand, you built your custom project, could you share it?

That being said, I am fully aware that speed is not the greatest attribute of Ecspanse. I needed a library with extended ECS capabilities to build the Orbituary project with Elixir and Phoenix, and my plan is to improve the speed (where possible) as I develop that game.

No use case, only wanted to see how it runs with more entities.

I was on the ecspanse_demo project, I added this in the SpawnMarket system:

    Enum.each(0..999, fn _x ->
      %Ecspanse.Entity{} = Ecspanse.Command.spawn_entity!(Demo.Entities.Inventory.new_map())
    end)

Actually I just found out if I comment out the MaybeFindResources system it runs at a normal framerate.

Edit:
I also have another project with my own entities. It looks like if any system locks any of the components on the 1000 entities that are spawned, the framerate drops to 1. Even if the system runs on events that haven’t triggered.

Very interesting. I will try to reproduce as soon as I find some time, and get back.

1 Like

I tried your example, but until now, I could not reproduce exactly the case yet.

I used this

    Enum.each(0..3000, fn _x ->
      %Ecspanse.Entity{} = Ecspanse.Command.spawn_entity!(Demo.Entities.Inventory.new_map())
    end)

So, I ran your example with 3000 entities, not 1000, and still got 100+ frames.

Indeed the startup is extremely slow. But give it enough time and the frame rate changes from 1 to 100+.

I also updated the demo project to display the FPS in the LiveView. You can pull the main branch and use it.

I identified some potential small improvements for the next version, but nothing major.

Also as a heads-up, I’m thinking of removing the automatically generated events like Ecspanse.Event.ComponentUpdated. Their functionality can be easily replaced with triggering custom events, and they pollute the events queue, every frame.

Later Edit

After some optimizations for the tagging system, got the same 3000 entities running at ~500FPS.
This will require a lot more work on my side, but I hope to push a new version somewhere next week.

2 Likes

New release v0.4.0

  • breaking: removes the automatically generated events on every component create, update and destroy. While this was useful, it was also very noisy, generating many events every frame. The functionality can be easily replaced by emitting a manual event wherever needed, or by creating a short-lived component for the specific entity.

  • improvement: change the way tagged components are handled. This improved the frame rate for cases when many tagged components had to be queried.

Thanks again to @andzdroid for testing the library and reporting the performance issues.
While Ecspanse was not created with a focus on performance, but mostly on functionality, it is still good to improve also the performance whenever possible.

1 Like

@andzdroid, version v0.4.0 has now been released, so you can perform your tests with the new version if you want. I have also updated the ecspanse_demo project to use the latest version.

That being said, for your specific case where you want to spawn a significant amount of entities on startup, the Ecspanse.Command.spawn_entities!/1 is a much more efficient way to do this.

Per your example, it would be something like:

    specs =
      Enum.map(0..3000, fn _x ->
        Demo.Entities.Inventory.new_map()
      end)

    Ecspanse.Command.spawn_entities!(specs)

    IO.inspect("READY!!!")
1 Like