Issues with batch drawing with atlas files and SpriteKit - ios

So I ran into a problem with lag on a platformer game I'm building. So I'm researching how to improve performance.
I'm trying to do batch drawing, so that there is less draw calls. I'm having issues though. So with a brand new project:
I have 4 hero sprites, all images are stored in a .atlas folder. so there is a 1/2/3x image for each sprite in the atlas folder.
I drag and drop that into the xcassets folder. Then I go to my sks file create 4 sprites and change the texture accordingly.
By default they all have the same blend mode. I have the default rule set to true for ignoring sibling order. All sprites are on the default z 0 layer. and I have it set to show draw count.
I would expect to see 1 draw since all images are in the same atlas file, but I see 4.
Is there something I'm missing?
Just curious how I get this to work properly. Thanks for any help!!!

There was a bug with xcassets on iOS 9 where draw calls wouldn't be reduced even if images were placed in xcassets. Apparently that was fixed with later versions, but since then I never bothered with xcassets. Instead I place images in a seperate .atlas folder in the project, which does reduce the draw calls.
Try to place 4 sprites with the same texture and see what the draw calls are then. It shouldn't be 4 if the sprites are using the same texture. I would also suggest to add 8 sprites (4 different textures * 2 sprites each) and see if the draw calls increase to 8.
If the draw calls don't increase, then I would assume that 4 draw calls is what it takes to draw your 4 different sprites (if they are very complex ones). If the draw calls do increase, try removing the images from xcassets and place them into a seperate .atlas folder in your project, and compare draw calls then.

Related

SpriteKit sktilemapnode vertical line glitch

I am making a 2d platformer and I decided to use multiple tilemapnodes as my backgrounds. Even with 1 tile map, I get these vertical or horizontal lines that appear and disappear when I'm moving the player around the screen. See image below:
My tiles are 256x256 and I'm storing them in a tileset sks file. Not exactly sure why I'm getting this or how to get rid of this and it is quite annoying. Wondering if others experience this as well.
Considering to not use the tile maps, but I would prefer to use them if I can.
Thanks for any help with this!!!
I had the same issue and was able to solve it by "extruding" the tiled image a couple pixels. This provides a little cushion of pixels to use when the floating point issue occurs instead of displaying nothing (hence the gap). This video sums it up pretty well.
Unity: extruding tile map images
If you're using TexturePacker to generate your sprite atlas' there is an option to add this automatically without having to do it to your tile images yourself.
Hope that helps!
Sort of like the "extruding" suggested by #cheaze, I simply make the tile size in the drawing code a tiny amount larger than the required tile size. This means the assets themselves do not have to be changed.
Eg. if you assets are sized 256 x 256 and all of your calculations are based on that; draw the textures as 256.02 x 256.02 pixels in size:
[SKSpriteNode spriteNodeWithTexture:texture size:CGSizeMake(256.02, 256.02)];
Only adding .02 pixel per side will overlap your tiles automatically and remove the line glitches, depending on your camera speed and frame rate.
If the problem is really bad, you can even go so far as to add half a pixel (+0.5) or an entire pixel to remove the glitches, yet the user will not be able to see the difference. (Since a one pixel difference on a retina screen is hard to distinguish).

Is it wise to export a Tiled layer into 1 big png file to save memory?

I just made the background layer in Tiled for my map for Sprite Kit. The main layer is the background layer where the grass, dirt, water & the lot is drawn - this what the player character "walks on". This map is consisted of tiles that are 16x16 (keeping them this small for having better control over the little details during design of the map). The map it self is 100x100. So it's pretty decent size wise. I have roughly between 757-778 nodes just because of these background tiles. That's too much and I haven't even added a single tree to the second layer. Since I'm using Tiled as the map editor with JSTileMap to display it, can I just somehow export the ready background layer from Tiled into a .png file and load that into the game as 1 big picture to drop the node count to 1. Wouldn't this drastically help performance and memory? The others layers have their images spread across & there's a layer that's responsible for the boundaries. Is this a clever way of going about making the game or am I missing something? If it is, does anyone know how to export the layer into a .png file? I checked Tiled & couldn't find anything like that.
You are most definitely better off having a single PNG/node as your background. There are some benefits of doing this:
You have just one node.
You can add the node to self and place it behind the rest of the action. This way it will always be there regardless of you moving any other nodes.
In the picture below I added a background to the view and have 3 other tile layers plus 1 object layer. My node count is still substantially less than 700.
As for exporting what you already have, I don't think there's a way to save an entire tile layer as one PNG. As a hack you could take a screenshot, crop the background part and work with that.

Xcode SpriteKit Designer Clear Background Red X

I'm not sure what the issue is, but I'm trying to design a level in Apple's Sprite Kit editor, and I'm running into a problem with SKSpriteNodes that have a transparent background. Sometimes the background doesn't appear as clear. Instead, SpriteKit seems to load a Red X as a background image.
Naturally, I can't have this. Also, it's a problem because I really should be doing all of the level design in the editor instead of manually adding sprites in my Scene code.
Has anyone come across this problem? Could it be a bug in SpriteKit Designer? (There are a number of issues I've had with it since starting to use the tool).
Here is a photo of what it looks like:
I found a kinda hacky way to solve it. Basically, as uchuugaka said, the Red X appears when Sprite Kit fails to load a texture. If you want a clear background, you have to load a clear png file as the background of the sprite. There is no "No Texture" option currently available in the Sprite Kit designer.
Take these steps.
1.) Open any .png file with some transparency in it.
2.) Copy an arbitrary rectangular section of pixels.
3.) Create a new file with said arbitrary pixels.
4.) Save this file as your "clear.png" and import it into your project.
5.) Click on the sprite node with the Big Red X so you can see its setting. Take a screenshot of its position, size, etc. using preview. These settings will get erased when you swap the texture over to clear.png
6.) Swap the texture to clear.png
7.) Re-enter the sprite settings from your screenshot.
8.) Because SpriteKit Editor is currently horribly terribly flawed (see post above), you will need to reset your sprite's physics properites. Set the physics body to none. Then set it to bounding box or circle or alpha mask or whatever you had earlier.
9.) I hope you remembered your collision mask, category mask, and other physics body properties because they just got reset to the default. Re-enter what you had earlier or you will get a very unexpected result.

Modify part of a Texture Map that is in use in OpenGL ES 2.0

I have a texture which I use as a texture map. Its a 2048 by 2048 texture divided in squares of 256 pixels each. So I have 64 "slots". This map can be empty, partly filled or full. On screen I am drawing simple squares with a slot of the sprite map each.
The problem is that I have to update this map from time to time when the asset for the slot becomes available. These assets are being downloaded from the internet but the initial information arrives in advance so I can tell how many slots I will use and see the local storage to check which ones are already available to be drawn at the start.
For example. My info says there will be 10 squares, from these 5 are available locally so when the sprite map is initialized these squares are already filled and ready to be drawn. On the screen I will show 10 squares. 5 of them will have the image stored in the texture map for those slots, the remaining 5 are drawn with a temporal image. As a new asset for a slot is downloaded I want to update my sprite map (which is bound and used for drawing) with the new corresponding texture, after the draw is finished and the sprite map has been updated I set up a flag which tells OpenGL that it should start drawing with that slot instead of the temporal image.
From what I have read, there are 3 ways to update a sprite map.
1) Upload a new one with glTextImage2D: I am currently using this approach. I will create another updater texture and then simply swap it. But i frequently run into memory warnings.
2) Modify the texture with glTextSubImage2D: I cant get this to work, I keep getting memory access errors or black textures. I believe its either because the thread is not the same or I am accessing a texture in use.
3) Use Frame Buffer Objects: I could try this but I am not certain if i can Draw on my texturebuffer while it is already being used.
What is the correct way of solving this?
This is meant to be used on an iPhone so resources are limited.
Edit: I found this post which talks about something related here.
Unfortunately I dont think its focused on modifying a texture that is currently being used.
the thread is not the same
OpenGL-ES API is absolutely not multi-threaded. Update your texture from main thread.
Because your texture must be uploaded on gpu, glTextSubImage2D is the fastest and simplest path. Keep this direction :)
Render on a Frame Buffer (attached on your texture) is very fast for rendering data which are already on gpu. (not your case). And yes you can draw on a frame buffer bound to a texture (= a frame buffer which use the texture as color attachment).
Just one contrain: You can't read and write the same texture in one draw call (The texture attached to the current frame buffer can't be bound to a texture unit)

cocos2d load random image from sprite sheet

Ok so I am conceptualizing for a game I want to make and have played a little bit but ran in to a problem. I am learning iOS programming and learning cocos2d also.
I have about 20 images. They are all the same size 64x64. Basically they are grouped as 5 different shapes (square, circle, etc.) each in 5 different colors. What I want to be able to do, is randomly drop them down the screen in portrait. There will only ever be one per column falling. There can be duplicates across the screen, I actually want that. While it is random, I want to control the introduction of a new color.
I have been really racking my brain to figure out how to do this. As I said, I am pretty new to this so any help would be really great.
If I could be so bold, can any answers be in a format to "Explain it like I'm 5 I have only been doing this for about 1 year"
First, have a look at this tutorial about sprites sheets: it will show you how to create your sprite sheets and load them into memory.
(Since the tutorial aims at building an animation, you can skip points 4 and 5).
Now, if you have your sprite sheets in place, what you do to create a sprite is:
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:#"frameName.png"];
and then you can add it to your layer/scene.
About the random selection: you can keep a list of image names (say, an NSArray) and then randomly (i.e., use srand to generate a random index) select the #"frameName.png" value from it.
When using Cocos2D the best way to use sprites is with Sprite Sheets. That is, a combination of two type of files:
A plist file with all the coordinates of N sprites and all different data about the sprites, size, name, etc.
A png file with all the sprites
You can make a sprite sheet with different types of software, like:
Zwoptex
Sprite Helper
Sprite Packer
Sprite Master
Texture Packer
About performance, when using a sprite sheet you will need to use CCSpriteBatchNode, as the API documentation states (read here):
A CCSpriteBatchNode can reference one and only one texture (one image file, one texture atlas). Only the CCSprites that are contained in that texture can be added to the CCSpriteBatchNode. All CCSprites added to a CCSpriteBatchNode are drawn in one OpenGL ES draw call. If the CCSprites are not added to a CCSpriteBatchNode then an OpenGL ES draw call will be needed for each one, which is less efficient.
THe code to use Sprite Sheet:
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"sprite.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"sprite.png"];
[self addChild:spriteSheet];
Hope this helps.

Resources