SpriteKit where to load texture atlases for thousands of sprites - iphone

In my game I have thousands of "tile" nodes which make up a game map (think simcity), I am wondering what the most frame-rate/memory efficient route for texturing and animating each node would be? There a a handful of unique tile "types" which each have their own texture atlas / animations, so making sure textures are being reused when possible is key.
All my tile nodes are children of a single map node, should the map node handle recognising a tile type and loading the necessary atlas & animations (e.g. by loading texture & atlas names from a plist?)
Alternatively, each tile type is a certain subclass. Would it be better for each SKSpriteNode tile to handle their own sprite atlas loading e.g. [tileInstance texturise]; (how does sprite kit handle this? would this method result in the same texture atlas being loaded into memory for each instance of a certain tile type?)
I have been scrounging the docs for a deeper explanation of atlases and texture reusage but I don't know what the typical procedure is for a scenario like this. Any help would be appreciated, thanks.

Memory first: there won't be any noticeable difference. You have to load the tile's textures, textures will account for at least 99% of the memory of the Map+Tiles and that's that.
Texture reuse: textures are being reused/cached automatically. Two sprites using the same texture will reference the same texture rather than each having its own copy of the texture.
Framerate/Batching: this is all about batching properly. Sprite Kit approaches batching children of a node by rendering them in the order they are added to the children array. As long as the next child node uses the same texture as the previous one, they will all be batched into one draw call. Possibly the worst thing you could do is to add a sprite, a label, a sprite, a label and so on. You'll want to add as many sprites using the same texture in consecutive order as is possible.
Atlas Usage: here's where you can win the most. Commonly developers try to categorize their atlases, which is the wrong way to go about it. Instead of creating one atlas per tile (and its animations), you'll want to create as few texture atlases as possible, each containing as many tiles as possible. On all iOS 7 devices a texture atlas can be 2048x2048 and with the exception of iPhone 4 and iPad 1 all other devices can use textures with up to 4096x4096 pixels.
There are exceptions to this rule, say if you have such a large amount of textures that you can't possibly load them all at once into memory on all devices. In that case use your best judgement to find a good compromise on memory usage vs batching efficiency. For example one solution might be to create one or two texture atlases per each unique scene or rather "scenery" even if that means duplicating some tiles in other texture atlases for another scene. If you have tiles that almost always appear in any scenery it would make sense to put those in a "shared" atlas.
As for subclassing tiles, I'm a strong proponent to avoid subclassing node classes. Especially if the main reason to subclass them is to merely change which texture they are using/animating. A sprite already is a container of a texture, so you can as well change the sprite texture and animate it from the outside.
To add data or additional code to a node you can peruse its userData property by creating your own NSMutableDictionary and adding any object you need to it. A typical component-based approach would go like this:
SKSpriteNode* sprite = [SKSpriteNode spriteWithWhatever..];
[self addChild:sprite];
// create the controller object
sprite.userData = [NSMutableDictionary dictionary];
MyTileController* controller = [MyTileController controllerWithSprite:sprite];
[sprite.userData setObject: forKey:#"controller"];
This controller object then performs any custom code needed for your tiles. It could be animating the tile and whatever else. The only important bit is to make the reference to the owning node (here: sprite) a weak reference:
#interface MySpriteController
#property (weak) sprite; // weak is important to avoid retain cycle!
#end
Because the sprite retains the dictionary. The dictionary retains the controller. If the controller would retain the sprite, the sprite couldn't deallocate because there would still be a retaining reference to it - hence it will continue to retain the dictionary which retains the controller which retains the sprite.
The advantages of using a component-based approach (also favored by and implemented in Kobold Kit):
If properly engineered, works with any or multiple nodes. If what if some day you want a label, effect, shape node tile?
You don't need a subclass for every tile. Some tiles may be simple static sprites. So use simple static SKSpriteNode for those.
It lets you start/stop or add/remove individual aspects as needed. Even on tiles you didn't initially expect to have or need a certain aspect.
Components allow you to build a repertoire of functionality you're going to need often and possibly even in other projects.
Components make for better architecture. A classical OOP design mistake is to have Player and Enemy classes, then realize both need to be able to shoot arrows and equip armor. So you move the code to the root GameObject class, making the code available to all subclasses. With components you simply have an equipment and a shooting component add to those objects that need it.
The great benefit of component-based design is that you start developing individual aspects separately from other things, so they can be reused and added as needed. You'll almost naturally write better code because you approach things with a different mindset.
And from my own experience, once you modularize a game into components you get far fewer bugs and they're easier to solve because you don't have to look at or consider other component's code - unless used by a component but even then when one component triggers another you have a clear boundary, ie is the passed value still correct when the other component takes over? If not, the bug must be in the first component.
This is a good introduction on component-based design. The hybrid approach is certainly the way to go. Here are more resources on component based design but I strongly advice against straying from the path and looking into FRP as the "accepted answer's author" suggests - FRP is an interesting concept but has no real world application (yet) in game development.

Related

Does changing multiple sprites on a single animation affect performance?

I have been building a 2D sprite based game for which I want to have the player be able to customize their equipment. This means that although I am fine with drawing the content, I'd need to ensure animations in the game run fine on top of each other. For this, I have been preparing a game object with several children to account for the equipment:
Each of the children runs a single animation and should have to follow the player, which I accomplish by using transform.localPosition = Vector2.zero; on the Update of the script each takes, so they hook to the parent's pivot and follow the player. While this has worked for the most part, there are moments in which all of the objects are not synchronized and as such sometimes the parent object (the body) is seen where it shouldn't since the other game objects should render on top:
Aside from that, to make it easy for the children to follow the parent position I had made sprites which are all the same size, which risks me having to load a lot of transparent space per sprite.
Another problem that I just noticed as I'm trying to address the issue of loading too many useless pixels involves the positioning with other objects such as the Sword game object, which doesn't follow the player fully if I use sprites that are not perfect squares (see this question for details How to align sprites of smaller sizes to a moving gameobject sprite? and this one Sibling sprite doesn't appear to follow main GameObject sprite even when transform.position updates)
I tried to fix this by making the Sword a child of the Hero, but even then changing the position through a function that sets values to add on to transform values of the sword game object only change the position of it relative to the initial value. I attempted changing the pivot of the sword sprites to a custom value to guess where the center of it would align with the main game object and appear in the right position, but even that doesn't seem to work.
I'm kind of getting tired with my current process, as I have to rely on several animations for each of the game objects, both parent and children, so that these obey to different layers in a single animator (or in the case of the sword, a separate animator), all to ensure there is some synchronization that doesn't always occur:
I really don't mind the web that is turning out in what I'm doing, but the fact that I have to repeat it across multiple layers with no real guarantee that all the objects would appear right on top of each other due to the fact of having multiple animations playing, and loading multiple sprites with empty space is becoming more of a chore than enjoyment.
So I think I came up with a possible solution: If I could make a single animation for the whole equipment used at any given point (whether only wearing pants or wearing full equipment), then having this single animation could guarantee synchronization across parent and children without the need for animator layers or special functions to update position or worrying about pivots or square sprites if I can set the position of non-square sprites in the animation, with the downside that I would need to account for every single animation for each possible equipment variation (so if I had even 3 of each sword, pants, boots, etc. that would mean 3^6 animations) and make a more complex web of animator states. The only thing I'd be worried about in this case, however, would be the performance, if having too many animations for a player would affect how fast these load. But at the benefit of eliminating the other problems mentioned, my question boils down to this:
Is it better to have a single game object with animations that change multiple sprites across children game objects and a single animator that chooses states based on multiple variables, or game objects with multiple animations that change a single sprite for each, and a single or multiple animators with multiple layers that choose states based on multiple variables?
There isn't really a set answer for something like this. It really just depends on how good your/the players computer is when playing the game. Sorry if this isn't what you wanted.

Automatically add platform area tile as player approaches the edge of current tile

Firstly, I'm new to Unity and I'm currently learning c#, please be gentle!
As a project, I'd like to create a simple 3d platform game. The idea being the player starts on a square tile, which is the game platform playing area. They explore different elements on this tile by moving around.
The perspective is 3rd person, so the player is looking down on the action. As they approach the edge of the tile Unity recognises this and adds another tile to the existing one, basically doubling the playing area.
As the player moves around further to the tiles edge, other tiles are added, increasing the discovered areas each time.
My thinking to achieve this would be to have 5 tile game objects, that have different elements like trees already built on them. The question is what is the best way to achieve this.
Would it be to build the complete level with all tiles and then using code restrict how far ahead the player can see, basically to the width and length of the tiles.
Or would it be better to trigger a new tile to appear as the player approaches the edge of the current tile.
Thought, links to example code that I could recycle would be very handy.
Thank you.
The question is primarily opinion based, but here is some advise:
There is no right way to make a game in unity. The correctness is mainly focused on performance; memory and processing.
There are two approaches here:
condition: Your world is endless (or very large) and player moves very slowly over time (say each tile takes more than a second to traverse).
solution: Do not instantiate everything at start, instead when player reaches the edge of a tile look for the next tile in your level structure to retrieve its data and then instantiate its objects.
condition: Your world is not very large (say it has less than overall 10K objects) OR player can move fast (as in Age of Empires game).
solution: Instantiate everything in loading phase and deactivate the game objects as they are being instantiated so that nothing is getting processed at the start of the game. In this case the level structure is a collection of game objects where you activate or deactivate them.
Hints:
Pooling is a good practice when it comes to repetitive objects. Pool is basically an empty game object with a script, and many many deactivated children.
e.g. If you have 1K trees of the same kind you better have a tree pool. Create a game object named tree pool, add a pool script to it and make that script generate 1K deactivated tree game objects in the loading phase. Then whenever your level generator needs a new tree just fetch a tree from tree pool and activate and reposition it. Make sure you clean up the pool after the game ends to prevent memory leak.
you can implement the pool as you like to provide object variations for a specific pool.
Instantiation in run-time is costly especially in mobile devices. Whenever you need to instantiate several game objects at once consider using a coroutine to prevent lag or freeze (this applies to loading phase too).
e.g.
IEnumerable CreateObjects(Data[] data)
{
foreach(var e in data)
{
Instantiate(e);//instantiate here and then wait
yield return null;//this line prevents lag
}
}
//...
StartCoroutine(CreateObjects(data));
//...
Having many active game objects is also costly especially in mobile devices. If many active game object have heavy scripts, the update methods will ruin performance. If many active game objects have rigidbodies or colliders the physics engine processing gets heavy.
Activating game objects is costly but less than instantiation, since it only runs Start method on its script if any, and also causes the physics engine to re-evaluate its structure if it has static collider or rigidbody.
Rendering is costly if only the rendered visuals are (fully or partially) visible to the cameras.
Create an editor project where you can design your levels. in this project you will make use of unity's editor classes to generate some kind of data (JsonObject) which represents your whole world. (collection of levels, tiles in each level and objects in each tile). Moreover you can have other data such as objectives and stuff each stored in a different JsonObject. Then use this data in your game by reading it and storing its structure in memory.
The reason I recommend JsonObject to store data is its size, portability, flexibility, accessibility and simplicity to work with. JsonObject is a dictionary stored as a plain text. and since it's a text you can encrypt it as you like

Managing SKTextures for animations

I'm wondering about the best way of managing my textures. In my current project they are all quite small, so it doesn't really matter, but I'm wondering if there is any best practice. I'm also working with the entity/component system (it's an experimental project).
So I have an animation component that I use to store all my animations related to that entity. I created a struct like that:
struct AnimationDefinition {
let animation: [SKTexture]
let timePerFrame: CGFloat
}
And I store animation definitions in a dictionnary property of my component so I can recall them by name later on. That part works really well. For now though, I have only a limited number of entities, but I plan on adding more as development goes on so the way I'm creating the animations might become messy because I'm creating all the textures in the entity's init(). So I'm pretty sure if I reuse that component in another project that uses large textures and more animations, it will slow down everything each time I create an entity.
So I thought about building a TextureManager who will create the textures at the beginning (if it becomes bigger i could make it regenerate itself at the beginning of each level with only the textures that will be used) and feed the arrays at will. Is that a good way to go?
Should I create the animation's SKAction right away and store that instead of the texture array?
Thanks for your opinions?
here are some resources, buried in there are some nuggets pertaining to what you want.
https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/DesigningGameswithSpriteKit/DesigningGameswithSpriteKit.html
https://developer.apple.com/videos/play/wwdc2014/608/
https://developer.apple.com/library/content/samplecode/DemoBots/Listings/DemoBots_SceneManager_swift.html

Does the entire scene get drawn on screen?

Ok so i'm building a game and just using the WebPlayer.
It plays just fine for me and others with no performance issues.
I loaded it to an iPhone 5 to see how it would handle performance and it's far from acceptable. Likely due to the nature of it and all of the objects and effects being drawn.
Is the entire scene loaded at once or are the items that are out of range only drawn when the camera is in that area?
Here is the game
http://burningfistentertainment.com/3D/DevilsNote/index.html
Any pointers would be great.
Is the entire scene loaded at once
Yes it is. When you load a scene everything contained is loaded into memory. Eventually try to split the scene.
are the items that are out of range only drawn when the camera is in
that area
Each active GameObject inside camera frustum with a Renderer component will be rendered. Always animated Animator components can affect performances even if not rendered.
I loaded it to an iPhone 5 to see how it would handle performance and
it's far from acceptable. Likely due to the nature of it and all of
the objects and effects being drawn.
It's hard to say what could be the bottleneck without knowing more about your code. If you think the problem is GPU related, here's
some tips for mobile:
reduce draw-calls (it depends on the device, I'd say no more than 50-70) => reduce materials count(use atlas), mark static objects as static (this way can be static batched),...
limit overdraw: reduce size and number of transparent objects (what about rain? how do you implemented it?)
consider using occlusion culling (probably not a problem in your game, but if the depth complexity increases it could save you a lot of GPU workload)

Understanding scenes in Unity3d

I have some confusion with scenes in Unity3d and I was not able to find any resources about them.
When should scenes be used? For example in a platformer would every level have to be a different scene? Would the main menu be a scene?
Can one overlay scenes?
How do assets work between scenes? Are they attached to each individual scene and have to be reloaded every time. Can one specify when an asset is no longer needed?
How does one send data between scenes/interface between scenes?
I understand that this is a broad topic, but I didn't want to spam with multiple questions.
When should scenes be used? For example in a platformer would every
level have to be a different scene? Would the main menu be a scene?
There are no general rules about that. In theory you may have just one scene for the whole game.
How you organize your scenes is entirely up to you and often depends on the type of game you are creating.
I think that there are at least 3 features to be considered of using scenes:
they are a logical container for all pre-instantiated objects that might be useful to divide your game into multiple levels/sections.
You can serialize cross references between GameObjects and Components inside a scene (if GO A needs a ref to GO B, and they belong to the same scene, the reference can be serialized and you no longer need to find the referenced object at runtime)
When you load (not in an additive way) another scene, the resources already loaded into memory are automatically released
Can one overlay scenes?
Yes you can using LoadAdditive. Unfortunately, once 2 scenes are both loaded into memory there is no automatic way of distinguish objects belonging to one or the other. So if you load additive a second level environment, it's up to you to keep track of the previous environment and explicitly destroy it if you need to.
How do assets work between scenes? Are they attached to each
individual scene and have to be reloaded every time. Can one specify
when an asset is no longer needed?
As defaults every GameObject of a scene will be destroyed once the new scene is loaded (unless you use an additive scene loading). A way to make a GameObject survive across scenes is to mark it using DontDestroyOnLoad.
If you need to share a particular "configuration" of a GameObject, you can store it as a prefab, and reference it across scenes (but remember that once in a scene it's a prefab instance, so the GO shares with the prefab the initial serialized and not overriden properties, but 2 instances of the same prefab are different objects).
How does one send data between scenes/interface between scenes?
Several ways, depending on what kind of persistent data you want to share.
For a particular GameObject instance let the object survive using DontDestroyOnLoad.
If you have some configuration data that doesn't need to be attached to a specific GameObject you can consider storing a ScriptableObject inside the AssetDatabase and reference it.
If you have data that must persist across different game sessions you can consider storing them into PlayerPrefs.
There are 2 other ways that I don't like, but just to cite them:
Using a static field can sometimes help you in doing that, but it has several problems from my point of view
Save and load from disk (could be useful in several situations, but often it's a platform dependent way and you can have some trouble especially on different mobile platforms)
This is a broad topic btw, I hope this answer can be a quite decent overview.
When should scenes be used? For example in a platformer would every level have to be a different scene? Would the main menu be a scene?
There is no rule as to how many scenes you need to have in your game. However, scenes allow you to logically separate out parts of your game from the rest of it. You have to have a minimum of one scene.
By main menu, if you are referring to a canvas with your UI elements, it will be IN a scene and not a scene itself. Canvas is just another GameObject, that we mostly happen to use for showing game menus. I mostly create a Canvas GameObject, put a script by the name of "UIManager" and put DontDestroyOnLoad on it, so I have access to it in all scenes. Make it Singleton and I ensure that it is not duplicated.
Can one overlay scenes?
Yes, there is no restriction as to how many scenes you can load at a time. What purpose do you plan to overlay scenes though? Maybe there is a better way than loading additively.
How do assets work between scenes? Are they attached to each individual scene and have to be reloaded every time. Can one specify when an asset is no longer needed?
Assets are what you see in your 'project' hierarchy. I think you meant "GameObject"s in the scene, and if so, think of your gameobjects as entities with components (Entity-Component System). All entities in a scene get destroyed when its parent scene is destroyed until explicitly stated not to, using DontDestroyOnLoad in some component (a monobehavior in case of unity). The destroyed ones will get garbage collected.
So how they are loaded (or reloaded) depends on your implementation, on whether you are instantiating/destroying them time an again or if you put their instantiated prefabs in a cached object and retrieving later from it.
How does one send data between scenes/interface between scenes?
Heisen covered the ones I could think of. Just to add a little bit to it, it also depends on how you want to the architect your project. So if you had an underlying data structure to e.g. hold Commands, you are free to use it in any part of your project
Most games would be organised to have scenes for every level(including the main menu) but that is entirely up to you.
You can use the data from one scene to another if you save it in a text file or binary. There are a lot of tutorials on how to do this. I find documentation helps a lot.
Assets are universal in a project.
You can not overlay scenes.
When should scenes be used? For example in a platformer would every level have to be a different scene? Would the main menu be a scene?
When to use a scene is up to you. If you are just starting I would recommend using a different scene for each section of your game.
Can one overlay scenes?
Yes, using LoadSceneMode.Additive(). (LoadAdditive() is obsolete)
How do assets work between scenes? Are they attached to each individual scene and have to be reloaded every time. Can one specify when an asset is no longer needed?
By default, assets are deleted when using SceneManager.LoadScene(). However, if you use DontDestroyOnLoad(), the object will not be destroyed when entering new scenes. If you want to only keep an object through a few scenes instead of all, use Destroy() with some boolean logic.
How does one send data between scenes/interface between scenes? I understand that this is a broad topic, but I didn't want to spam with multiple questions.
You can send data through scenes by using the aforementioned DontDestroyOnLoad(), referencing the data on different scripts, using ScriptableObjects, using JSON Serialization, using StreamWriter(), using PlayerPrefs (Don't use for important information), the list goes on. I would personally recommend using ScriptableObjects for their accessibility, and StreamWriter() for it's encryption capabilities.