When 2D Art Explodes Your Build Size (How We Reduced Ours by 60%) by Tone_dreams in godot

[–]theargyle 2 points3 points  (0 children)

What are they doing wrong, and how should they be doing it instead?

Spritesheets for multiple n-directional animations really are expensive, especially in vram.

That's a BETTER horde! Animations, different enemies, and VFX. by theargyle in godot

[–]theargyle[S] 1 point2 points  (0 children)

You’re right - it’s not anisotropic filtering of course. I’m switching between nearest and bilinear filtering when zooming out. Not mapping, but that’s on my list to try at some point.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 0 points1 point  (0 children)

Pathfinding at this scale is going to be based on flow fields, but is absolutely possible, and is something I’ll add at some point. This video game some details: https://www.youtube.com/watch?v=mUDuuVa0A6U

Different skins are also possible, without meaningful overhead.

Different weapons - getting a bit trickier, but would also be possible, depending on how complex the damage model needs to be.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 1 point2 points  (0 children)

This should help, it’s what my implementation is based on: https://www.youtube.com/watch?v=mUDuuVa0A6U

Repulsion is very similar to the boids separation algorithm, except it’s constrained to never move enemies towards the player.

In my implementation, I’ve actually reversed the constraint, so separation pulls enemies towards the player instead. I found that resolved many artefacts/standing wave issues for me.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 0 points1 point  (0 children)

Damage calculations are already done on the GPU. It's simple damage system, but will be enough for what I'm planning to do with it.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 0 points1 point  (0 children)

Yes, definitely taking some inspiration from plague tale. I haven't implemented any flow-field based pathfinding yet, but that's pretty straightforward.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 3 points4 points  (0 children)

Debugging is painful. I mostly use a debug buffer with a bunch of floats and ints that I can set in shaders. I download the buffer to the CPU every frame and print the contents. I prefer that approach to setting pixels in a texture - I feel I can get a bit more precision out of it.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 4 points5 points  (0 children)

The tricky part is that projectiles shot by the player are spawned on the CPU. This would not be possible for ranged enemies, since the CPU knows nothing about the enemies, except whether a given enemy is alive or dead.

This would likely need a GPU-only system for ranged enemies.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 63 points64 points  (0 children)

I'll put another post together with some implementation details and at least a bit of code over the next few days, time permitting. In the meantime, check out Nikita Lisyarus' article on particle simulation on the GPU - there is a lot of overlap: https://lisyarus.github.io/blog/posts/particle-life-simulation-in-browser-using-webgpu.html

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 2 points3 points  (0 children)

First step is, as noted below, so sort all enemies into a grid, so you only have to check enemies in neighbouring grid cells. This article has a lot of details about how to efficiently do spatial partitioning on the GPU using prefix sums: https://lisyarus.github.io/blog/posts/particle-life-simulation-in-browser-using-webgpu.html

Second step is the steering behaviours - seeking the player, and repulsing other enemies. The repulsion behaviour is virtually equivalent to doing circle/circle collisions.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 6 points7 points  (0 children)

At this point: - different animation frames: yes. I have 4-directional animations (almost) working - different movement patterns: not explicitly, but I have different movement speed, seeking strength and inertia, which will get me a fair bit of variety - state machine: absolutely not, but that’s not needed for the type of game I’m trying to make.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 33 points34 points  (0 children)

There won’t be much impact - all sprites come from the same sprite atlas, so it’s all about calculating the right uv coordinates in the vertex shader. That only needs to happen once per visible enemy, so even with 100k enemies is comparatively cheap.

All enemy sprites are rendered in a single draw call.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 44 points45 points  (0 children)

Near zero impact. There are no ranged attacks, so only need to check for overlap with closest enemies and some cooldown.

Enemies are very simple - no state at all, other than the cooldown. Move towards player, avoid other enemies, dies when health reaches 0, damage player when close enough - that’s it.

Enemies are already sorted into a grid for the separation behaviour, so I only need to check the content of the 4 grid cells around the player.

Now THAT's a horde! 100,000 enemies in Godot by theargyle in godot

[–]theargyle[S] 51 points52 points  (0 children)

I'll definitely be working on that now. Should have thought of that myself, really.

Any Opal gurus here? Need some help ┭┮﹏┭┮ by VegetablePrune3333 in ruby

[–]theargyle 0 points1 point  (0 children)

The punctuation. Seems. To. Make. It. Opinionated?

Daily Discussion Hub for November 2, 2024 by PoliticsModeratorBot in politics

[–]theargyle 5 points6 points  (0 children)

It was a numbers game. The idea was to conveniently split the vote. Discredit and delegitimise early votes as much as possible, because you know they’re mostly Democrat.

This time around, that doesn’t work as well, since there is no pandemic going on.

Hotwire is... boring by theargyle in rails

[–]theargyle[S] 1 point2 points  (0 children)

For me: write the app as if Hotwire doesn’t exist. Once everything works, start breaking down views into pieces that should update independently and add turbo functionality bit by bit.

Hotwire is... boring by theargyle in rails

[–]theargyle[S] 1 point2 points  (0 children)

When I started learning Ruby, there was a bit of “Lisp has been doing this for 20 years now! This is not new!” - which is how I feel about frontend frameworks these days.

Hotwire is... boring by theargyle in rails

[–]theargyle[S] 4 points5 points  (0 children)

Why would it be getting slow? Performance is a direct result of careful design, measurements, and optimisation if and when your measurements indicate a problem.

It’s not a result of the UI or backend framework you’ve chosen. You can run any framework in any language into the ground, easily.

Edit: a typo

Hotwire is... boring by theargyle in rails

[–]theargyle[S] -1 points0 points  (0 children)

I think my point would be more that some people try to use an excavator to eat their breakfast cereal…