Spritesheet, simple explosion in ECS

So, trying to get into ECS a bit more, and after viewing some CodeMonkey tutorials, I got to wondering, how do spritesheets fit into there?

So, I have this simple, spritesheet; it goes boom. So, now I want to use that as an animation. Watching these tutorials;

Getting Started with ECS in Unity 2019
Draw a Sprite with ECS in Unity 2019
Simple Sprite Sheet Animation in Unity ECS

Made me think this is going to be quite complex, for such a simple thing. I can either create 23 separate materials and cycle through them. Or implement a complete seperate animation system. Both don’t really feel like the ‘right way’.

I’d love to hear some insights and or comments/suggestions.

5082152--500057--Explosion.png

I suggest check recent sprites topics.
https://forum.unity.com/search/112734359/?q=Sprite&t=post&o=date&c[node]=147
I.e.
__ 200k dynamic animated sprites at 80fps __
There are some good examples and repositories, which may be of use for you.
There was somewhere repo, with nice sprite dino animation.

I think there were topic discussing with keyword ‘quad’. But not 100% now.

Thanks, I think the 200K topic is on the mark. Even if I don’t need quite that many sprites.

If it applies to 200k, I think it will work well with 1k, or 10k :stuck_out_tongue:

I think it will. I did misspeak a bit, I intent to have as many entities as possible, 10k, 100k a friggin million billion if I can. But, only a “handfull” will be on screen at the same time.

Just to see what this ECS bit can do.

Is this a stress test or you have a use case?

Little bit of both.

I have a use case, that need managing a whole lot of objects. But normally, I would simplify or remove those outside of the view. With ECS, I am going to see if that optimization is still needed.

A minimal system, not knowing you use case, could be:
1- camera system (sprites are animated, but static)
2- animation system (time based)
3- cull & render system (animation index of on-screen entities pushed into compute buffer, uv lookup in shader)

I’ve made a thing, based on CodeMonkey’s examples. But apparently, ECS has already moved beyond that. So I am looking into it again.

CodeMonkey’s approach works extremely well as long as you use’re okay with having a specific frame count and other restrictions on your art. In fact it works so well that animating 20k entities with a sprite atlas of 4 by 10 frames costs apparently 0.2ms. I used CodeMonkey’s approach to calculate the stuff in a job system and it does wonders for me.

How has ECS ‘moved beyond that’? Let me know I’m curious even though I’m not going to change my implementation.

Beyond as in CodeMonkey’s bit depends on a feature that will be/is deprecated;

Assets/ECS_SpriteSheetAnim/SpriteSheetRenderer_Basic.cs(15,15): Warning CS0618: 'NativeQueue<SpriteSheetRenderer_Basic.RenderData>.Concurrent' is obsolete: 'NativeQueue<T>.Concurrent is deprecated, use NativeQueue<T>.ParallelWriter instead. (RemovedAfter 2019-10-25)' (CS0618)

So, I’d need to rework that bit. I am trying to make something that is easily used with common spritesheets. So my spaceship can have an exhaust flame and some asteroids fly around space so to say.

For the sheer number of objects I’d like ECS seems prime. For the complexity in managing them, well, I am learning.

All you have to do is use ParallelWriter() instead of Concurrent and it will work the same :slight_smile:
CodeMonkey’s code can be further optimized. I think the bottleneck in his code was his rendering system if I’m not mistaken.

Most likely. I am actually refollowing his tutorial right now, to figure out a better way for my particular use case.

Maybe I am still looking at this too much from an OO perspective. Old habits do die hard. My case is one spacestructure for the player, many outside entities interacting with that. CM’s way to set the UV’s to enable use of spritesheets is usefull there. I did it a bit like this to point to a sprite in a spritesheet;

        private Vector4 getUVForFrame(int currentFrame, SpriteSheet spriteSheet)
        {
            // Get the column and row for our frame in the spritesheet
            // Row is rounded down
            int row;
            row = currentFrame / spriteSheet.xDimension;

            // And the column is the rest
            int col;
            col = currentFrame - (spriteSheet.yDimension * row);

            // Create the UV from that bit
            float uvWidth  = 1f / (spriteSheet.frameCount / spriteSheet.xDimension);
            float uvHeight = 1f / (spriteSheet.frameCount / spriteSheet.yDimension);

            float uvOffsetX = uvWidth * col;
            float uvOffsetY = uvHeight * (spriteSheet.yDimension - (row + 1));

            return new Vector4(uvWidth, uvHeight, uvOffsetX, uvOffsetY);
        }

i recommend you look at some examples posted in #2 - for best performance you best

  • use drawmeshinstancedindirect
  • use compute buffers
  • minimize data per frame to gpu (i.e. send uvs once and then only an index, cache buffers + only send changes - this can work well with animation which does not update every frame, etc.)

I want to limit the amount of custom work I’d have to do for what is, in essence, a ‘simple’ sprite based space shooter. To make sure the code is reusable and easy to understand. So far I’ve cut out all the culling bits and made it so the spritesheet can be used with a simple grid system. Ie, I can use an 5x5 spritesheet and point to a discrete frame to render it.

I am looking into how to proceed, as of this, I can comfortably render about 2.500 simultaneously looping exploding sprites. Asynchronous, so at different points in the animation. That is about 70 fps on a MacPro without a real gaming GPU. Since I am developing for a tablet system, there should be room for improvement. The thing is, it doesn’t matter if the sprites are visible in the camera or not. So really zoomed in, with only a 100 sprites in the view, it’s just as slow/fast as really zoomed out. Or even with the camera moved way out of the way, not showing any sprites, still 70 fps. At 20 instances it’s about 120 fps.

Now that I’ve gained some basic understanding, I will probably use the 200k dynamic animated sprites at 80fps code shared there.