SpriteKit Load Texture First Time Lag Even With Preloading - ios

Here is my problem: Despite doing these:
1) Preloading all of my texture atlases
2) Having my atlases stored in Singletons so they are not disposed of by ARC
3) Having all my animation arrays stored in Singleton
SpriteKit STILL has a short "lag jitter" when adding enemies to my scene ONLY the first time they are added. After the texture is drawn once, it never lags again when that texture is added to the scene. Memory can be seen going up when the textures are drawn on the screen finally, which looks like they aren't getting preloaded.
I am currently preloading ALL of my texture atlases in my AppDelegate on startup using...
SKTextureAtlas.preloadTextureAtlases(primaryAtlas, withCompletionHandler: { () -> Void in
})
primaryAtlas is an array of all 4 of my atlases which are stored in a Singleton.
Let me point out some things I have already tried and what my current setup is.
1) The array of frames for my animations are stored in Singletons and get their images from the Atlases which are in a different singleton. They used to be in the same Singleton.
2) I've tried storing ALL my textures in a Singleton which were all loaded from the atlases. But currently my animations are stored, while my single textures are functions that fetch that texture from the atlases.
3) I've turned off all animations for enemies (don't run the SKAction) and the jitter still happens when they're added and not animating.
I've been trying to fix this for a very long time and there honestly doesn't seem to be a solution.
There seems to be a similar StackOverflow question I found here with no answer: Spritekit: First texture draw slow (preloaded)
Here is a picture of some analysis I did with Instruments.

Make sure that your texture atlases are used as singleton class properties, because if you create variables of texture atlases inside method scope which do preloading, they will be deallocated after method returns

Related

How to release memory created by SKTexture

I have an application that creates scene kit textures using the following:
let texture = SKTexture(image: image)
The problem is that after several calls, the application crashes due to low memory.
I really only need the most recently created texture so when creating a new one, the preview ones' memory can be released, however, Scene Kit seems to be holding on to these textures even when they aren't being used anymore (the nodes are no longer part of the scene).
How can I manually tell Scene Kit to release the memory and cache of the texture so I don't get into the low memory crashing situation?
Also, I know that the SceneKit documentation recommends removing all references to the texture by removing nodes and such, but that should be happening and yet the Texture is not being released. Is there a good way of debugging and seeing what's holding on to the reference?
In re-reviewing the code, I'm creating a scene to hold the image to be rendered in the primary scene (whose node doesn't change). Basically, there is an object in the scene that can display an image or a video and that gets changed out by returning a Scene which is used as the material diffuse contents.
let texture = SKTexture(image: image)
let sprite = SKSpriteNode(texture: texture)
let scene = SKScene(size: sprite.size)
sprite.position = CGPointMake(CGRectGetMidX(scene.frame), CGRectGetMidY(scene.frame));
scene.addChild(sprite)
And then being used here:
primaryObjectMaterial.diffuse.contents = scene
I would expect once the scene's node material contents are changed, this scene (and the texture and image) would be released as there would no longer be any references to it but perhaps the caching system is hanging onto something or I'm doing something wrong?
It's hard to give you an exact answer with out seeing your code or knowing how the app works but you need to take the node that the texture is on and remove it
nameOfNode.removeFromParentNode
This will remove it from memory and you need to add a new node with the new texture.

Weird nosense CCSpriteBatchNode Exception

There is something weird going on in my cocos2d game I can't figure out the problem.
I have a very simple files structure for my game, 1 intro layer, 1 main menu layer, 1 game layer.
While I was developing I skiped the menu layer in order for the game jump from intro layer to save time.
Now I finished the game, I added back the main menu and when game layer is called from it it crashes!!??
it never crashes if I skip the main menu layer.
Edit:
Important, If I have remove the main menu layer it works just fine... main menu doesn't add any texture atlas, there is only one I am using entire the whole game.
this is the message error:
"CCSprite: Batched sprites should use the same texture as the batchnode"
from this gamelayer code:
_myitens = [CCSpriteBatchNode batchNodeWithFile:#"mytextureatlas.png";
The funny thing is Main menu Layer only feature is to have a button(image from file and not texture atlas) that calls the game layer....
it is very confusing I can't see how to approach this issue
any tips are valid thanks
One of the more common causes, and in particular if the problem depends on which scene you load first, occurs when you have the same image in two atlases.
For instance, assuming you have mytextureatlas.plist and notmytextureatlas.plist and both contain an image with the same name, say "player.png". If you first load mytextureatlas all seems fine. However when you load notmytextureatlas first, and later try to add a player.png sprite to the batch node using mytextureatlas, cocos2d will actually use the player.png from notmytextureatlas, provoking this error.
Double-check that all image names across all texture atlases are unique.
How are you adding sprites to _myitems? You are adding children which have been created with a different texture, that's the meaning of the error and that's what happening.
The exception is not non-sense, it means a precise condition which somewhere you fail to obey: a batchnode must have children initialized with the same texture of the batchnode itself (and it makes sense, since it's used to batch GL calls).
For example:
_myitems = [CCSpriteBatchNode batchNodeWithFile:#"mytextureatlas.png"];
[_myitems addChild:[CCSprite spriteWithTexture:#"othertexture.png"]];
Will generate the error. You should try with:
[_myitems addChild:[CCSprite spriteWithTexture:_myitems.textureAtlas.texture]];

SpriteKit loses textures

I'm making multilevel game based on SpriteKit.
Everything works well except one thing: when user plays long time, changes many levels, etc... then SpriteKit starts losing textures.
I mean there is no big red cross like when image load fails but just empty space like nothing is there.
Hours of debugging and googling did not produce any results.
How can I deal with that bug?
I think I might be having a related issue, except the loss of textures occurs when I am rapidly running actions on a SKSpriteNode. In my code, I run an action each time I get a touch and when the touches are rapid and the animations are firing quickly, the base texture of the SKSpriteNode seemingly disappears. No memory warnings, not a peep from the console; the SKSpriteNode's texture is magically set to nil.
I get the impression from your question that this isn't your exact cause, but you are having the same symptoms. Unfortunately I don't know what is causing it. What I've done to work around the issue has been to constantly check if the texture on my SKSprite node has been set to nil immediately after I run an SKAction and then re-assign it if needed.
So, an abridged version (in Swift) of what I'm doing looks like this :
func doAnimation( ) {
_character.runAction(someSKAction, withKey: "animation")
//Whoops!, we lost our base texture again!
if _character.texture == nil {
let atlas = SKTextureAtlas(named: "someAtlasName")
let texture = atlas.textureNamed("idleFrame" )
_character.texture = texture
}
}
This is not really solution so much as a workaround, but it might be adaptable to your situation until you (or someone else on SO) figures it out. I won't argue that it's not ugly.
BTW, you are not alone with the disappearing texture issue; I wrote a similar response to a similar question here.

CoreGraphics elements inside SKNode

I'm building game-type app using SpriteKit. In one of the scenes I want to create an area, in with user will be able to draw. Sadly using SKShapeNodes produces jagged lines and causes FPS to drop. I thought about using Core Graphics method, but I need drawn lines to be a part of a Node. So is there a way to use Node as a canvas for CG?
From the SKNode documentation:
Unlike views, you cannot create SKNode subclasses that perform custom drawing.
So I think the answer is no, you can't do that.
Each node does have a scene property, and the scene does have a link to the view that contains it. But the thing that makes sprite animation fast is that sprites are canned -- the images have already been drawn and just need to be copied. Node types other than SKSpriteNode are similarly optimized for speed. Accordingly, there are no drawing methods in the sprite classes -- no opportunity for your code to do custom drawing.
You can draw to a CGImage and create a SKTexture from that using textureWithCGImage:

Storing game data for 2D game like Star Ocean Second Story and Legend of Mana

I'm trying to go for a 2D game like Legend of Mana and Star Ocean Second Story rather than tile based 2D games.
OVERVIEW
Currently, the way I'm going about building my game is like so:
I have geometry files and texture files. Geometry files store width, height, XY position, Texture ID number to use and texture name to use.
The way I'm trying to do is:
I will have a scene manager object that loads "scene" objects. Each scene object stores a list of all geometry objects in that scene as well as texture and sound objects (to be implemented).
Each scene is rendered using vertex array whereby the scene manager object would call a method like get scene vertices by scene name which returns a pointer to an array of GLFloats (GLfloat *) and this pointer to GLfloat gets used in OpenGL's glVertexPointer() function.
When I want to update each character's position (like the hero for example), my aim is to use the "hero" game objects in the current scene and call a function like:
Hero.Move(newXPosition, newYPosition);
which will actually alter the hero geometry object's vertex data. So it will do something like:
for(int i = 0; i < 8; i++)
{
vertexList[i] = vertexList[i] + newXPosition;
vertexList[i+1] = vertexList[i+1] + newYPosition;
...
}
This way, when I go to render the scene in the render frame, it will render the entire scene again with the updated vertex coordinates.
Each object in the game will just be a quadrilateral with a texture mapped to it.
THE PROBLEM
I'm using Objective C for my programming and OpenGL. This is for iOS platform.
I have been successful thus far using this method to render 1 object.
The problem I have is I'm using a NSMutableDictionary which is a data structure that uses key-value pair to store geometry instance objects in the scene object class. Dictionaries in Objective C doesn't retrieve data in the same order every time the code is run. It retrieves then in random order.
Becausing of this, I am having trouble combining all the vertex array data from each geometry object in the scene object and passing out 1 single vertex pointer to GLfloats.
Each geometry object stores it's own array of 8 vertex values (4 pairs of X,Y coordinate value). I would like each geometry object to manage it's own vertices (so I can use Move, Rotate like mentioned earlier) and at the same time, I would like my scene object to be able to output a single pointer reference to all vertices data of all geometry objects in the current scene for using in OpenGL's glVertexArray() function.
I am trying to avoid calling OpenGL's glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) multiple times. Like draw hero, draw map, draw AI agents, draw BG objects. That would not be very efficient. Minimizing the amount of GL draw calls as much as possible (to 1 draw call preferably), especially on limited hardware like the iPhone is what was suggested when I was reading about OpenGL game development.
SUGGESTIONS?
What is the best practice way of going about doing what I'm trying to do?
Should I use a SQL database to store my game data like geometry vertices data and load JUST 1 scene into iPhone memory from the sql database file on iPhone's disk?
You can use a a list of lists to keep track of draw layer and order, and use the dictionary solely for fast lookup.
What I don't understand is why you don't use Cocos2D, that happens to be built on the scene manager paradigm. Think of all the development time you will save...
I have worked in a company that did wonderful games. It eventually died because they kept putting out buggy games, due to the lack of development time for debugging. They did however find time to create a graphics rendering engine.
I thought, and still think, they had wrong priorities. It seems to me you are doing the same mistake: are you trying to make an iOS game, or are you trying to learn how to do a 2D gaming engine for iOS?
Note: Cocos2D is Open Source, you can therefore read it, now that you have thought about the process to create such an engine.

Resources