Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a Swarm/Mob/Flock/etc system for managing large amounts of entities #2380

Open
reduz opened this issue Feb 28, 2021 · 52 comments
Open

Comments

@reduz
Copy link
Member

reduz commented Feb 28, 2021

Describe the project you are working on

Godot

Describe the problem or limitation you are having in your project

Godot is designed to be easy to use as first priority. The Scene system in Godot (Scene and Nodes) are designed for maximum flexibility as well as simplicity. This works great in most cases.

In some situations, however, this can be too much when dealing with very large amount of objects (passing the thousands, or dozens of thousands). While in most cases this is not a common case, some situations require large amounts of elements to be processed, such as:

  • Projectiles (bullet hells as an example)
  • Units (certain types of games, such some type of strategy, or city builders) require large amount of units moving around.
  • Flocks /Swarms/ Mobs
  • Debris
  • More complex CPU particles than what supported by the CPUParticles.
  • Etc.

These situations have different requirements than what you often find in most games, as they consist of large amounts of simple entities, rather than smaller amounts of complex ones. Again, Godot scene system is designed for moderate amounts of complex entities (as this is what is required in most games), but proves to be overkill for large amounts of simple ones, as lack of cache efficiency and the complexities of the tree-based structure slow things down.

The only way to do this in Godot right now is to talk to servers directly or go via GDNative, but this is not accessible for most Godot users. Other game engines rely on ECS to solve this (Unity is working on it), but this is also an approach geared to more experienced programmers, whereas Godot aims to be a very easy to use tool where someone without high technical education or lots of experience can still solve the complex problems inherent to game development (then Again, for those more experienced, or more complex problems, GodEx can be the solution).

Describe the feature / enhancement and how it helps to overcome the problem or limitation

What I propose is creating an alternate way to deal with large amounts of simple entities. It could be called "The Swarm System". A system would be created in a Resource and edited in the editor. You would visually configure how you want your swarm to be basically ticking boxes such as:

  • 2D or 3D
  • Has collision shapes
  • Is a rigid body, kinematic or a character body (in case it has collisionshapes)
  • Will draw to the screen
  • If draws, it does using individual canvas item (2D)/visual instance(3D) or as par of a MultiMesh
  • For 3D, whether it has skeletal animation, for which it will contain a very simplified/more optimized skeletal animation data.
  • For 2D, most likely animation frame data
  • Is a navigation agent (will use navigation)
  • Whether it will want to query access to nearby objects and what will be the maximum distance checked (for flocks).
  • Script

The script (at least GDScript and and C#) will probably need to support something extra internally, as its data will need to stored contigous in memory in order to be processed. C++/GDNative will expose this also so other languages can support it.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

There will be a SwarmFormat resource, which can be edited and configured, saved to disk or similar. Probably with a bit more advanced options whether you want this to be processed in threads (more entities at the cost of being more careful with threads).

Additionally, there will be a Swarm node that will allow setting swarms and control their spawning and execution via API.

A common question to this may be, what if you want to have slightly different objects in a swarm? For this, you can either create multiple ones, or just do whatever you need by code in every swarm entity at the cost of performance/flexibility.

Again, if more flexibility is required, users can use an ECS system or simply write their own low level code and interact with the servers directly, but the idea of swarms is to cover the vast majority of cases where you need this performance optimization and still keep it easy to use and well integrated to Godot.

Swarms will be able to interact easily with nodes and vice versa, for greater ease of use.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Is there a reason why this should be core and not an add-on in the asset library?

No, this is definitely core, needs to interact with everything that is there easily.


The idea of this proposals is for community to discuss and give feedback on this idea!

@Ansraer
Copy link

Ansraer commented Feb 28, 2021

I spent some time trying to get EnTT (amazing framework) to work as a module (for crowd sims) and would definitely appreciate an official solution.
Is there a reason why you suggest only one Script/Swarm? In my experience multiple scripts are necessary to take full advantage of such a system. Here is a somewhat oversimplified example:

  1. global script to prepare information that will be used by all agents (e.g. current targets, delta time,...) so that this information doesn't need to be recalculated by each agent individually.
  2. One script to plan the next action.
  3. some sort of boids, react to what other nearby agents have planned in 2, if necessary react to it, and actually perform the planned action.

@reduz
Copy link
Member Author

reduz commented Feb 28, 2021

@Ansraer Well the script is just the actions that execute in the linear memory buffer, nothing prevents you from putting a global script in the node or something they can interact with.

@Ansraer
Copy link

Ansraer commented Feb 28, 2021

@Ansraer Well the script is just the actions that execute in the linear memory buffer, nothing prevents you from putting a global script in the node or something they can interact with.

That would solve 1, but I dont see how I could accomplish 2 and 3 with that. Unless you want to add barriers to gdscript?

@Calinou Calinou changed the title Create a Swarm/Mob/Flock/etc system, for managing large amount of entities, Create a Swarm/Mob/Flock/etc system for managing large amounts of entities Feb 28, 2021
@reduz
Copy link
Member Author

reduz commented Feb 28, 2021

@Ansraer I have no idea honestly, I suppose when we are closer to implementation, if community actually likes this, we can see whether it's possible/worth implementing something like this (and how) or whether something else, more custom, should be used.

@triplefox
Copy link

Script in the update loop is likely to present a major bottleneck; two ideas come to mind for defining simpler script logic that will scale with a swarm:

  1. Behavior driven by lookup tables. The majority of "gameplay rules" are of the form "take input -> lookup result -> change state".
  2. Behavior driven by greedy pattern matching akin to a simple regex. This acts on the other axis from lookup tables - instead of one input producing wide results, it's multiple inputs, perhaps over multiple updates, resulting in a matched pattern and a state change. (If we introduced backtracking/minimal-matching it would be capable of all sorts of things, but backtracking adds a large amount of implicit state)

A combination of both of those would suffice even for a simple character controller, and most likely the AI requirements of any swarm, if hooked into API calls - which could also allow triggering script if it's necessary to do something like compute some arithmetic, likely with some restrictions.

The main consideration beyond that would be how much state is tracked by each entity, with the smallest amount being a single value that enumerates all possible states.

@API-Beast
Copy link

Movement seems like the biggest issue for this since that often requires significant scripting per entity per frame. Compute shaders would be perfect for that, but is probably out of scope due to OpenGL ES support.

One solution I could think of is that you can set a path the entity should follow, then the logic of that entity only needs to be updated whenever it has finished moving towards it's current target. It would be good to have some options for how that path should be followed too, e.g. steering behaviours: aligning movement vectors with nearby objects of the same flock, attraction/repulsion towards certain elements, avoiding collisions.

@reduz
Copy link
Member Author

reduz commented Feb 28, 2021

@triplefox and @API-Beast A lot of work is being done towards optimizing scripting, so this should hopefully not be a problem at the time this is implemented.

@groud
Copy link
Member

groud commented Feb 28, 2021

I kind of dislike this proposal. This resource, along with the associated system, look like a big carryall thing, which has several problems to me.

While it does a lot of things, you will always with people having specific situations where something does not work as they expect or is missing a feature to work for their use case. This will also make it annoying to maintain.

But I think its main problem is not here. I might be wrong, but I think you highly overestimate how difficult are the servers to use.
At least from my experience with the rendering server, I find the API very simple and straightforward. It's indeed not a node with tickboxes, but it should be usable even for a beginner.

So in my opinion, instead of creating an in-between solution between using nodes and using the servers, I think a better way to go is to make using the servers a lot more accessible instead. This should go through providing examples, demos and documentation. Some Nodes' documentation pages could redirect to their corresponding example in the documentation, so that people could easily replicate what they do in a node to a script (like the Sprite documentation would redirect to a page explaining how to use the rendering server directly instead).

For the demos, we could go for a bullet hell game, an RTS or things like that. That would make it more obvious that you don't have to use nodes all the time to build your game.

@Calinou
Copy link
Member

Calinou commented Feb 28, 2021

For the demos, we could go for a bullet hell game, an RTS or things like that.

We had a "Bullet Shower" demo in 2.1 but it was never ported to Godot 3.0 and later.

@thimenesup
Copy link

I think that the servers (plus GDNative) could already accomplish the same functionality expected of an ECS, the problem is that (as of 3.2) the servers dont allocate memory in pools/allow preallocating memory? And using RIDs seems to be slow since it uses a hashmap instead of just being an index to said memory pool.

RIDs would also need some improvements to interfacing better with non-server api, because I remember trying to get a texture reference from a server handle and there was no way unless I made a copy of the image data and upload it as a new texture, which was definitely inefficient.

@aaronfranke aaronfranke added this to the 4.1 milestone Feb 28, 2021
@aaronfranke
Copy link
Member

aaronfranke commented Feb 28, 2021

I think this proposal would be better as an add-on in the asset library. Perhaps even an official one. When it comes to "needs to interact with everything that is there easily", I think we should make it easy to interact with those things (servers etc) from an add-on as @groud suggested. In any case, this is something we don't need for the 4.0 release, so I've added this to the 4.1 milestone (can be moved to 4.2/etc if needed later).

For the demos, we could go for a bullet hell game, an RTS or things like that.

I think that's a great idea. It would be nice to have a simple RTS demo, we could use it to showcase things like navigation, minimaps, selection, camera ray projection, RTS style camera movement and zooming, and as you suggested, interaction with servers directly (to be honest, it's still fairly new to me). It may be better to make this demo for 4.0 only and skip 3.2 due to the navigation rewrite in 4.0. Bonus points if we can get terrain in Godot 4.0 and we could use terrain in this demo.

(Further discussion on making a demo like this would mostly be off-topic for this thread so it can be continued elsewhere).

@LillyByte
Copy link

LillyByte commented Feb 28, 2021

Swarm systems are, more often than not, very specialized systems.

I feel like the subset of games that could use this would be rather small. There are instances it would be useful, but the problem here is... you're going to have trouble with a "one size fits all" when it comes to "how does the swarm behave"? How do you interact with it?

The time dedicated to this would be better spent on other systems that actually benefit larger groups of game devs.

It's a good idea, for further down the line, when we are not lacking in more core features/functionality.

@TackerTacker
Copy link

I do like the suggestion of demos and documentation for servers, I would like to learn more about them. That said I would still really really like some purpose build solution for these types of problems because I wouldn't trust my own coding ability enough, and I need this for a game if I don't want to cripple it's feature set significantly.

I come from the perspective that coding is an obstacle that's in the way of my creative vision. Something I need to overcome, not a fun puzzle to solve along the way. My experience with more low level code is that I waste multiple days fighting through obstacles to come out at the end with nothing useful. I'm using a game engine to take tasks like these of my already full task list as a solo dev, and my current solution for these problems would most likely just be, I can't do that.
And I'm not sure if some demo or documentation would change that.

I bet I'm not the only one too. Just the only one who is willing to admitting that his glue code skills are probably not enough to make some of these features production ready.

@Calinou
Copy link
Member

Calinou commented Feb 28, 2021

For those looking for documentation on low-level servers, I ported the Bullet Shower demo from Godot 2.x to Godot 3: godotengine/godot-demo-projects#588

@reduz
Copy link
Member Author

reduz commented Feb 28, 2021

@groud There is documentation on how to use the servers directly, as been around for a while as well as demos (which are not up to date I believe, though):

https://docs.godotengine.org/en/latest/tutorials/performance/using_servers.html

Still, this did not catch on. it's also still very hard to optimize with linear memory for cache efficiency for most end users. Additionally, with GDScript it's not even possible, so large part of this work needs to be done anyway.

Using servers also is not that easy, they require RIDs and are too low level in many cases. Even if you do demos, the resulting code is not that simple for a large part of our use base. I suspect you are biased in this regard because you are a very skilled developer and contributor and know the engine well, but large part of the Godot userbase does not have this experience nor the time to acquire it, they just want to make games with as less hassle as possible.

So, in the end, users still complain to this day that using the scene tree for lots of objects is slow and that there isn't a simple and fast way to create lots of instances for simple entities. This problem is real and it needs a solution. This proposal aims to be that solution.

While it does a lot of things, you will always with people having specific situations where something does not work as they expect or is missing a feature to work for their use case. This will also make it annoying to maintain.

This is not a problem, we always strive to support the most common use cases (the ones I listed I think are a good starting point), then leave the door open for users to implement whatever they may miss. Nothing new here, has been our development philosophy since ever.

@aaronfranke

I think this proposal would be better as an add-on in the asset library.

This would be the case if this was something easy to workaround, or a rare use case (the common rules to make something an add-on). Unfortunately, it is neither and this is a very common problem among Godot users (plenty of complaining about performance with large amount of objects in Godot), for which it needs to be core.

@LillyByte

Swarm systems are, more often than not, very specialized systems.

You talk as if swarm systems were something standard, maybe they are but I was not referring to any of that I only used the word Swarm because it needs to be named somehow, but this proposal is not some sort of common thing and it's designed for a very specific problem in Godot.

@reduz
Copy link
Member Author

reduz commented Feb 28, 2021

@Calinou the bullet shower demos is ok, but it's very far from being the most optimized form of something like this. As I described in my proposal:

  • You need contiguous memory addressing for instances in order to maximize performance. Not so easy to do for users and not possible in GDScript right now.
  • You need to handle processing in multiple threads in order to also maximize performance, this is also not easy for users.
  • To improve performance evem further you need to make processing become instances of a multimesh, this further increases complexity.
  • Physics probably also needs specialized APIs to avoid having to rely on callbacks (which is inefficient).
  • If you use move_and_slide or similar, or pathfinding, you probably want, at some point, to call this in batch to maximize the performance and cache utilization on the server side. For users who just want to move bullets or little guys around a citty, you really are asking a lot.

I think the complexity that this proposal hides from users is probably understimated, it's not easy or obvious how to do a lot of these optimizations for a large part of the Godot user base, while all they may want to do is move a thousand bullets and see if any hit the player.

So, if using servers directly (which by itself is far for being the most optimal solution) did not really catch on for most users, there are zero chances that something more complex will. We need a better way to simplify the "large amount of simple entities" problem.

@jknightdoeswork
Copy link

jknightdoeswork commented Feb 28, 2021

I'm sure it will work extremely well for certain scenarios, but I worry that it will be very constrained and limited. If the desired feature is not supported by this system, users will still be pushed into GDNative/Godot Modules in order to achieve the level of performance they desire. I recommend that we work on improving the raw performance of GDScript.

How much further can we push the performance GDScript's design? Can we add new APIs to GDScript that support batched and parallel operations?

Perhaps we can work on lowering the friction to using GDNative and Modules and increasing the adoption of that approach. I think this could have a side effect of educating the user base, which will help train the next generation of programmers to understand and contribute to Godot. This will benefit us because the user base will be able to contribute in ways that we ourselves cannot, including after we are all dead and gone.

Imagine a very young person finds Godot and enjoys it's simple and accessible system. It's true that Godot is very easy to use. Now imagine if that child can find his or her way into the Godot source code. That child has the potential to become a prodigy. If we can channel the passion for Godot into c++, we can contribute to the education of people all over the world. This will not only benefit us, but will benefit the planet.

In summary, here are some approaches we should consider:

  • Further Optimize GDScript
  • Add SIMD or Parallel APIs to GDscript
  • Increase usability of GDNative and custom Modules
  • Empower community to build out a library of GPU & Compute
  • Document & empower the integration of Entt & Flecs
  • Godex
  • Make more of the Godot API thread safe to further empower a job/worker approach in GDScript

@aaronfranke
Copy link
Member

aaronfranke commented Feb 28, 2021

@jknightdoeswork These things are planned regardless of whether or not this proposal is implemented (though, I would argue that improving GDScript and GDNative are vastly more important things that should be worked on before this proposal is considered). @vnen has already been working on rewriting GDScript and GDNative for the past year, hopefully this will include performance and usability improvements in addition to bug-fixing and a cleaner API. And of course, the community is encouraged to create libraries and APIs and distribute them via the Godot Asset Library (or by any other means).

@ghostbutter-games
Copy link

ghostbutter-games commented Feb 28, 2021

I'm glad that finally a discussion is happening around "swarm systems"/ECS/whatever you might call it.
But: Having used an ECS on a commercial game I just released, I have to add: The reason people want this is not just about performance! I want to keep on using ECS with every engine because it's super fun to make games with it. It leads to less bugs, more robust decoupled systems, there are so many advantages.

It boils down to this: I love the idea & love that you want it to be core Godot. But to add to @jknightdoeswork s points, I very much agree: If you ever end up tackling this, please consider ergonomics & also make this as powerful as possible. Don't just optimize it for "swarm" style games, sandbox & city builders, but make it a good option for using Godot in general.
I think the best approach would be to collaborate with the Godex dev and build on what he has, or at least learn from it!

I think it would be well worth the effort! :)

EDIT: Further reading which expresses my thoughts far better than I could: https://ajmmertens.medium.com/ecs-from-tool-to-paradigm-350587cdf216

@reduz
Copy link
Member Author

reduz commented Mar 1, 2021

@konstantinkopka ECS is not under discussion, this covered by projects such as Godex (see proposal)

@reduz
Copy link
Member Author

reduz commented Mar 1, 2021

@jknightdoeswork the idea is to cater to simple and common use cases and then work from there, it is fine that more complex/uncommon cases are pushed to gdnative

@jasperbrooks79

This comment has been minimized.

@jasperbrooks79

This comment has been minimized.

@gitcatrat
Copy link

gitcatrat commented Mar 1, 2021

I kind of dislike this proposal. This resource, along with the associated system, look like a big carryall thing, which has several problems to me.

While it does a lot of things, you will always with people having specific situations where something does not work as they expect or is missing a feature to work for their use case. This will also make it annoying to maintain.

But I think its main problem is not here. I might be wrong, but I think you highly overestimate how difficult are the servers to use.
At least from my experience with the rendering server, I find the API very simple and straightforward. It's indeed not a node with tickboxes, but it should be usable even for a beginner.

So in my opinion, instead of creating an in-between solution between using nodes and using the servers, I think a better way to go is to make using the servers a lot more accessible instead. This should go through providing examples, demos and documentation. Some Nodes' documentation pages could redirect to their corresponding example in the documentation, so that people could easily replicate what they do in a node to a script (like the Sprite documentation would redirect to a page explaining how to use the rendering server directly instead).

For the demos, we could go for a bullet hell game, an RTS or things like that. That would make it more obvious that you don't have to use nodes all the time to build your game.

This is where I stand as well. I'd also like to brainstorm server APIs expansion, i.e could we add mid/high level server methods that do something in 1 API call instead of 5. Server API calls will always be the bottleneck with this system.

Servers documentation and examples could be improved A LOT. I did build a huge simulation using Visual and Physics servers but the process was painful and at the end of the day I gave up before I figured out how to do rig stuff with servers.

@API-Beast
Copy link

API-Beast commented Mar 1, 2021

This is getting very offtopic. This proposal has nothing directly with ECS nor with servers.

I think the proposal itself is a great idea, that could really help Godot move forward as an engine. Historically, general purpose engines (like Godot) were well suited for making platformers or shooters, this is because the medium complexity entity approach works well for these kind of games. However other genres, like tower defense or RTS games are significantly harder to implement, because they depend on more complex systems. ECS makes such systems more performant but not easier to implement, the same goes for Godot-style servers. You generally need some significant programming experience to implement such systems.

A swarm system on the other hand could make implementing such systems really easy, without need for such advanced programming knowledge. Godot would be the only engine having such a system and if it is well designed would attract a lot of talented game designers.

@YuriSizov
Copy link
Contributor

YuriSizov commented Mar 1, 2021

This is getting very offtopic. This has nothing directly with ECS nor with servers.

On the contrary, discussing alternative solutions and comparing them to the proposed solution is a part of the process. And while ECS is off the table, better API for servers is not. People have concerns that this porposal is attempting to be a one-size-fits-all solution, whereas extending servers would provide better building blocks for a more customizable approach.

Groud also mentioned that this is going to be annoying to maintain. And I think he meant that this all-encompassing proposal will make it hard to draw the line and judge which parts are relevent for core and which parts are to be discarded and left for users to implement. Say, this is added as is and a user comes with a proposal to add Y to the new system. When the system is very spread on features, not as focused as Godot's standard "node does one thing" idea, it's harder to evaluate if user's proposal has merits, or is less improtant than an arbitrary list of features described in this here OP.

And servers are granular but focused systems, so it's easier to appreciate where their core capabilities end and user expansions begin.

So, no, talking about alternatives is not off the topic.

@API-Beast
Copy link

It is "just" a more advanced (and maybe more user-friendly) MultiMesh node. It's really not all that radical.

@red1939
Copy link

red1939 commented Mar 2, 2021

@gitcatrat

Do I understand it correctly that this is just a way to create and store entities? I.e everything else is still in code?

1. create node
2. configure it
3. attach script
4. write code, e.g like this

(...)

I am not sure we will be able to use exact nodes that we have access to, today. In a way I see this as ECS-light system where you select what properties given flock has, and then you can do:

for bird in self.flock:
  bird.transform = Vector2() # only accessible property if you denoted this as being a 2D element with position
  bird.modulation_color = bird.script.modulate_var / 2.0 # only when you are allowing it to render 2D and have a script
  # Drawing would be handled automatically, as we ticked the "2D rendering" box

I have no idea what might be the restrictions of the script itself. Is it only a resource-like object that keeps data (like good old struct) or it's allowed to execute calls on itself/outside system? I am bit worried if we go the "storage-of-logic" route, because we might lose most (all?) of the performance gain of having tightly packed data (w/ hot instruction cache) if we allow (possibly different across each object!) expensive detours of nested scripts. Sure, that might be the example of "you have to pay for flexibility" (and learn the performance characteristic of flocks), but we might just as well say: no, this is a high performance tool and doing it this way gives you what you want.

@hilfazer
Copy link

hilfazer commented Mar 3, 2021

If entities are supposed to be controlled by some central coordinator then i'd avoid terms "Flock" and "Swarm" as they have strong connotations with AI where each agent is making its own decisions:
https://youtu.be/mjKINQigAE4
https://en.wikipedia.org/wiki/Swarm_intelligence

"Mob" would be good. Another option would be "Herd". While wild herds exist there are also domesticated herds controlled by a shepherd.

@willnationsdev
Copy link
Contributor

willnationsdev commented Mar 4, 2021

Of those two, Herd is probably better. Lots of devs use "mob" as a shorthand for monsters and such, so occupying the global namespace with that term might annoy folks. "Horde" would also be an interesting one to use.

@TackerTacker
Copy link

Can someone roughly explain to me how a setup for a swarm would look like in Godot? I get the feeling that everyone has a different idea of this system in their head.
For example, I thought iterating over the entities in a swarm would be taken care of by the swarm system, but the pseudo code I see is iterating manually over arrays of entities and such, I'm not saying that it is wrong, just that it is not how I thought it would work.

Here is a high level overview of how I thought it would work, on a simple example of a bullet that bounces off of walls.

I create a single bullet entity with a swarm node.
I create some variables that can be set when the bullet is spawned.
I write code that handles the entities behavior based on the initial spawn conditions set by the variables I declared. For this example, set the bullets rotation, speed, the sprite to use, how often the bullet bounces etc.,
and I write some code to handle specific events that can occur, like collision with a wall, and the response to it. For this example bouncing off the wall, and counting down the bounces it has left before destroying itself.
After setting this up, spawning and setting the initial conditions is all the influence I have over the entity. Every entity is the exact same, that runs the exact same code it was setup with and reacts to events accordingly.
The spawning is done via the swarm system, you tell it where to spawn the entity and the spawn conditions you've setup and the swarm system schedules when it's actually a good time to spawn the entity, the swarm system takes care of updating the entities, handles the collision events, the drawing, ... with low level code in a cache efficient way.

@SirPigeonz
Copy link

SirPigeonz commented Apr 23, 2021

I think this proposal is going in the right direction.
Big amounts of a bit more complex objects than a particle is often a use case in many games.

I also don't agree it should be left just as a server API. Godot is an Engine not a "just framework".
Providing good systems for basic and often used problems should be the core of Godot philosophy just as it was for now.
This philosophy is one of the corner stones of Godot success.

Maybe I will sound a bit harsh, but sometimes I get the feeling that some want to shift from Godot Engine Project to Godot Framework Project. Server APIs should be last resort when the user needs something that exceeds common use cases, not a default way of using Godot.

@thimenesup
Copy link

thimenesup commented Dec 18, 2021

I feel like this Godot project I made a while ago may be relevant, it basically a demo project similar to the shower of bullets, which is a case mentioned in the proposal, in the project you can see as I previously said, you can use GDNative and handle everything yourself, getting a lot of performance.
But as I mentioned, Godot lacks a bunch of things that still may impose a bottleneck.
I think that before implementing this proposal, that should be fixed first.

@Calinou
Copy link
Member

Calinou commented Dec 18, 2021

I feel like this Godot project I made a while ago may be relevant

There is a typo in the URL; it should be https://github.com/thimenesup/GodotDataOrientedTest 🙂

@Calinou Calinou modified the milestones: 4.1, 4.x Dec 18, 2021
@PoisonousGame
Copy link

PoisonousGame commented Jul 7, 2022

Recently there is a game called Vampire Survivors. The game has a large number of rigid bodies. Is Godot capable of handling this situation without gdnative? With the advent of this game, I think this proposal is necessary.

@Calinou
Copy link
Member

Calinou commented Jul 7, 2022

Recently there is a game called Vampire Survivors. The game has a large number of rigid bodies. Is Godot capable of handling this situation without gdnative? With the advent of this game, I think this proposal is necessary.

I've seen Vampire Survivors-like games being developed with Godot, so it sounds feasible. You may have to use various optimization tricks such as decreasing physics FPS and using interpolation, using low-level servers, using C#, etc.

@azur-wolf
Copy link

azur-wolf commented Aug 18, 2022

few things that come to mind:

  • share common data between entities → flyweight design pattern
  • SIMD
  • what about mix a bit between nodes & ECS (the separation between both can be diffuse, already have attached stuff to nodes, similar to what ECS does in essence; like resources, inner classes, non-node instances as properties, etc.)
  • auxiliary classes/objects that can be either invoked or instanced inside Scenes or Custom nodes/resources to bring functionality.
  • design it in such way that are all common pieces that can be used to work either simple stuff or advanced stuff; pre-built solutions for the most common kind of tasks, that are used the bast majority of the time, for either people that has basic coding skill, or for use when need functionality, but not want too much complications. And allow more advanced users to craft more advanced stuff by using extra pieces. When such solutions aren't enough, then its time to jump into a more complex language and DIY.
  • use ML to calculate the optimum stuff, by running analysis to detect patterns, and then use such collected data to apply changes, some sort of baking.
  • typical scenarios are:
    • calculate stuff that is on screen, or inside a certain player radius (established by developer)
    • calculate simplified versions of the stuff on background (enough good to be coherent when they get inside of player scope, and converted to their "complete versions")

@dukemagus
Copy link

While not an apples-to-apples example, Defold has a plugin that could serve as a base for at least the higher level logic of this setting.

https://github.com/dev-masih/defarmy

it's written in Lua, so at least it's easier to read even if you don't use the engine regularly

@Patchcoat
Copy link

I like this idea.

You would visually configure how you want your swarm to be basically ticking boxes

I think it would be nicer if we had a swarmlet node that accepts child nodes. If we want to associate data with an individual member of a swarm, using nodes seems like the most natural way to do that in Godot. The engine would just enforce some heavy restrictions.

  • Only certain nodes are allowed to be a child of the swarmlet
  • All nodes beyond one layer deep are lost, save for collision shape nodes that are a child of a collision node
  • Functions in scripts on child nodes are inaccessible and never run, but variables may be accessed.
  • Methods, variables, and signals on the child nodes that harm the efficiency to the point of defeating the purpose are inaccessible (a swarmlet could send a signal to the swarm manager, but having every swarmlet listen for signals may tank the efficiency)
  • You can have multiple different swarmlets managed by a single swarm manager, so long as they have the same node structure and behavior (for example: all of the pieces of a shattered statue)

The editor would show in real time when a child node is breaking the rules. When the game is built, all the data in the child nodes would be flattened into a structure that is memory and cache efficient. Even if it's effectively a toggle and a bunch of drop-downs on the backend, I feel like "I want physics" should mean "add a physics node of the desired type" instead of "click the 'I want physics' toggle and select the right type from a drop-down".

@oparisy
Copy link

oparisy commented Sep 8, 2023

I think it would be nicer if we had a swarmlet node that accepts child nodes. If we want to associate data with an individual member of a swarm, using nodes seems like the most natural way to do that in Godot. The engine would just enforce some heavy restrictions.

The way you describe those nodes as dataholders and the associates tree constraints, I think what you are after are Resources owned by the swarmlet node, more than full fledged subnodes. I'm not sure if a node can own a list of Resources though.

@Patchcoat
Copy link

I think what you are after are Resources owned by the swarmlet node, more than full fledged subnodes.

You are correct. A list of resources + a script associated with a node sounds perfect for this kind of thing. You could even sidestep the swarmlet node entirely and have the swarmlet be a conceptual collection of an array of resources plus a script, which is closer to the implementation anyway.

I think that this would benefit from a new bottom panel. It could provide a list of the resources in a swarmlet for easy access and make it easier to manage many different swarmlets of the same structure. For example: a statue that you can shatter. Each swarmlet would have collision and a mesh renderer, but the mesh and collision shape would be different for each one. You wouldn't gain any bonus from instancing, but you may still benefit from the cache coherency. If we wanted people to use it like this we would also need a "load into swarm" toggle in the importer that loads all of a model's individual mesh and collision shapes into swarmlets, but that's besides the point.

Doing it this way, it would be nice to be able to promote a swarmlet to a full node tree with a non-swarmlet script, and visa versa. Defining the structure of a promoted swarmlet could be another job of the bottom panel, and the developer would understand that anything other than this structure can't turn back into a swarmlet. Imagine you have an RTS and you can possess units. The unit is a swarmlet until the player inhabits it, at which point it becomes a node tree with a character controller and it stops listening to the swarm manager. When the player leaves the unit it's either welcomed back into the swarm or stays a node tree. Developers are warned if they can't go from node tree to swarmlet. The logs would show something like Error: cannot demote node tree $NODE to swarmlet, $NODE structure is incompatible with the swarm.

@Patchcoat
Copy link

I've given this some more thought.

Resizing

Ideally a high-performance component like this would allocate once when it's loaded. The swarm would have a max size set by the developer and so long as you stay in this max size you never have to perform another memory allocation. Resizing after it's loaded could mean one of two things:

  1. We allocate new memory and link it to the end of the existing block of memory. Multiple resizes would hamper performance as the data structure approaches a linked list since iterating over a linked list is slooooow.
  2. We realloc, then we take the performance hit of (maybe, sometimes) copying all of the data from the old block of memory to a new block of memory. The performance of a resize has the potential to be much worse than the linked list approach above, but iteration remains fast.

Of the two, I think the second one is better. It's simpler and faster when iterating. It's a tradeoff. Users who want their swarm to be fast should keep the number of resizes to a minimum; ideally 0.

Shared and Unique Data

For all swarmlets in a swarm, there is shared data and unique data. Shared data is stored in the swarm manager and may be instanced, and unique data is stored in the swarmlet array and won't be instanced. It's up to the user to decide what is shared and what is unique.

Take boids, for example. All boids share the same art, but the position and velocity is unique. The shattering statue example would have a shared texture, but the mesh data for each fragment would be unique. A squad of soldiers could have a single velocity and position as a group, but a different offset from that central position.

From a performance point of view:

  • If you want the benefits of instancing, use shared data.
  • If you want the benefits of cache coherency, use unique data.

That being said, we don't actually want to store unique art data in the swarmlet array. For the sake of performance we want to store it on the GPU and just send the position/rotation for each datum and let a vertex shader do its thing.

@ysypnbh

This comment was marked as off-topic.

@Calinou
Copy link
Member

Calinou commented Apr 24, 2024

@ysypnbh Please don't bump issues without contributing significant new information. Use the 👍 reaction button on the first post instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: On Hold
Development

No branches or pull requests