Draw same sprite twice without replicating it

I want to draw the same sprite a couple of times with slightly changed positions.

I could of course just create one cc.Sprite for every instance, but I’m talking about thousands of sprites here which will take multiple megabytes in memory - just a complete waste of space.

So what I’d like to do is to somehow render the same sprite multiple times in different positions, but by using the same actual sprite object.

I experimented a bit and in WebGL rendering context, it seems this works by just calling the sprite._renderCmd.rendering() manually, and changing the _stackMatrix to transform the sprite to a different position.

However, that’s of course extremely hacky, and it also doesn’t work in canvas mode rendering.

Is there some better way to do this that’s already supported by the cocos2d-js renderer?

Why will thousands of instances of the same sprite take up multiple megabytes of memory? Won’t they all share the same texture?

They will share the same texture, but the raw data (as in: javascript objects and their attributes) attached to cc.Node and cc.Sprite is just so much that each individual cc.Node takes up about 900 bytes of memory and each cc.Sprite about 1100 bytes. So 1000 cc.Sprites will in fact take up about 1 megabyte of memory, just because they are bloated in terms of the data they keep. This is not acceptable for me since during the runtime of the program I will sometimes have multiple tens of thousands of these sprites lying around in memory.

Do you need something that’s different from the particle system? If so maybe there needs to be a ParticleSprite that allows only changing a few of the Node/Sprite properties and would render like the particle systems (batched and fast).

Yeah, basically I’m writing a special type of tile map (that optimizes for memory usage, because we have many of them in our game, and plan to introduce really large ones). If I could just do something like draw a series of textured rects with minimal or no additional memory overhead (like drawing a sprite, changing its texture rect, changing its position, and drawing it again, etc.) then I wouldn’t have to implement new methods to render the tilemap on WebGL and Canvas separately.

I’m not sure how the TMXTilemap works on the cocos2d-js side of the fence, but if you can read c++ and want to check out FastTMXTileLayer.cpp you’ll see how they’re creating tiles as effectively a 32-bit tile id mapped onto quads that are drawn with OpenGL.

Obviously you want it to work with Canvas as well so you’ll probably have to write your own at this point unless the javascript version of the tilemap code has been written to support this idea of not using sprites, but rather just rendering quads.

Unfortunately, someone will need to implement two implementations at some level. There was work going on for a “v4” javascript renderer. Here’s an example of a multi-draw from same texture:
https://hyperandroid.github.io/Cocos2d-html5/src/test/engine/test7.html

It’s all in TypeScript though, and hasn’t been worked on in two months, but maybe it’ll help if you need to write your own. Sorry I’m not much help, but what you want I don’t think is available out of box.

Yeah don’t worry, drawing tilemaps efficiently is not a technically hard task. This question is more about portability & ease of maintenance. I’m going to write my own implementation for canvas and webgl now (already finished canvas), but it’s going to be a pain if cocos2d-js changes anything in its API that I depend on, or if I want to add an implementation for example for the JSB binding. If the abstraction I asked for was available, this job would be a whole lot easier and I wouldn’t need any boilerplate.

That was (hopefully still is) the goal of v4 to abstract the renderer to reduce the need for heavy Node/Sprite where unecessary, but if you want it in the engine you could always submit it as PR or a more formal proposal on the dev discussion forum section. The API compatibility and ease of upgrade going forward should continue to improve as well.

/cc @Ibon

What about rendering them to a render texture?