Question:
In the realm of cocos2d for iPhone, what's the equivalent of UIKit's -viewDidAppear callback for CCLayer?
*And if no equivalent exists (as seems to be the case in the docs), what's your recommended way knowing when a CCLayer has been rendered?
There are these two methods which are quite similar to
- (void)onEnter;
- (void)onEnterTransitionDidFinish;
Well, a CCLayer is rendered, usually, when it is created and you add sprites to it. You should do all this up front before the game play begins. Then you can move the layer around and animate its objects without worrying about "when" it will be finished rendering (usually).
Scenes are a different matter. A scene is what sets up the layers and creates them, loads images, sprites, etc, and tha can take a bit. For that you have a few options. One effective option is the the onEnter and onExit family of methods. However, another really good way is to simply have an intermediate scene, such as a mostly empty, lean Loading CCScene that you load, and then that scene loads the big scene you are trying to load. When you do this, you are freeing up old memory before adding new memory.
It really depends on what you are trying to accomplish with your equivalent of viewDidAppear.
Related
I'm making a level based game using SpriteKit. I would like to know the best practice for making level changes. I was originally using one Scene as my gameplay scene and when a level is completed, it removes all nodes in the scene and then adds the ones for the next level. I am using a background node that is persistent throughout the entire course of the game. I'm worried about memory because I don't think ARC will deallocate the nodes removed because the scene is persistent. Is this method ok or should I instantiate a new scene for when a level is changing?
The best practice is to separate game data and assets from game code. This way, you can make changes to stuff without having to recompile (and is handy if you are working with another person who doesn't code).
Here is what apple has to say about it at WWDC 2014:
When you transition between scenes, ARC will deallocate the prior scene, assuming you made no strong references to it. Since you're starting out it's unlikely you need to worry about this right now... it's mostly done with globals and closures, and you should be able to fix it if it becomes a problem (but likely won't).
You can use things like unowned self and weak var etc to ensure this doesn't happen when needed. Again this is a more advanced topic but it's good to be aware of them.
Really, making level changes is entirely up to you... if you want to make a state manager that swaps out stuff to one scene, you can certainly do that... or, you could make a bunch of scenes and transition to that. Again, the best practice here is separating game content from game code, not necessarily how you switch scenes.
Personally, I would used separate SKScenes-- because it's already built in with transitions, memory management--and you have the option of using the editor, and you get to give each scene it's own file if desired.
There is also GameplayKit which has a statemanager, in which case you could use one scene and have different states be the level.
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
My iOS game has a couple of scenes. I've noticed some lag between switching scenes, and I was wondering if it might be because I'm not removing all nodes and labels from parents when I transition to another scene. Is it good practice to remove all nodes from their parent when transitioning to another scene?
Also, I've noticed that when I do remove all nodes, the transition effect is kind of ruined, as the screen goes all black during the transition.
Is it possible to delete nodes(of previous scene) after the transition to next scene?
When you perform the transition, the scene and its nodes will be released from memory, unless you have a strong reference cycle. Also, you should know that SpriteKit has its own cache system for the SKTextures, so not all memory will freed.
The lag could be caused by a lot of thing, some possibilities:
If you instantiate the new scene on touchesEnded (or your custom button callback closure), the lag could be caused because you're doing too much work on the initialization. This can be solved by, for example, preloading the scene with a closure that run in background and, when you have to run the transition, you already have everything loaded. An example follows:
Maybe you're using assets that are too large and because they take longer to be loaded, you have the lag. You could solve this by, for example, converting images that don't need an alpha channel to .jpeg.
Another solution would be to preload assets. A code example follows.
I've been developing a board-style game in Unity3D. The main scene is the board, and has the data about each player and the current (randomly-generated) board stored within it.
I intend to add minigames into the game, for example when landing on a particular space on the board. Naturally, I would like to code the minigame in a separate scene. Is there a way I can do this without losing the instance of the current scene, so that the current scene's state is maintained?
Thanks in advance :)
Short answer: no, but there may be another way to do what you want.
A basic call to Application.LoadLevel call will destroy the current scene before loading the next one. This isn't what you want.
If your minigame is relatively simple, you could use Instantiate to bring in a prefab and spawn it far away from the rest of your scene. You can even use scripts to switch to another camera, toggle player controls and other interactions in the scene, and so on. Once the minigame is done, you can destroy or disable whatever you brought in, and re-enable whatever needs to be turned on in the main scene.
You could create a separate scene and call Application.LoadLevelAdditive to load that scene without destroying the current one. As above, you can then use scripts to manage which cameras and scene behaviors are active.
If you're careful, you don't really need two separate scenes. It may be enough to "fake" a scene switch.
Hard to give a complete answer without code, but you should look into the following things either with the unity documentation or youtube:
PlayerPrefs, this is one way of saving data, although i believe it isn't entirely secure i.e. being able to edit from a text file.
Serializable, this is apparently better than playerprefs.
DonDestroyOnLoad, can carry over information to multiple scenes.
Static variables, again not sure if this will help your particular problem.
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.
I have started programming a game for the iphone and as all beginners I feel like I am shooting in the dark. I just want to run my design and how my "graphics engine" works by you to see if it is anything close to standard design or good practise. Let me explain how it works:
For simplification reasons lets just say I have the following 3 classes:
LevelView: inherits from UIViewController and is a view with 10 buttons for each level of the game. Clicking a button creates a new GameViewController object (using initWithLevel) and instantiates it with an integer ( 1-10) according to the level the player chose.
GameViewController: inherits from UIViewController and has the initWithLevel(int) method and a big switch statement which performs the level setup according to the int that was passed. So it instantiates two types of objects (robots and planets) in various numbers according to each level. Each object it creates is inserted into an array belonging to a singleton. Then at the end it will start the gameloop which is another method in this class.
GameView: inherits from UIView and is where everything is drawn ( has a drawRect method) and where the touches Began,Moved and Ended methods are. What will happen for every gameLoop is that this will pull all objects from the global array (the array in the singleton) and according to what object it is it will draw the correct image at the correct location. ( location of robots and planets is stored within their respective objects as variables)
In the touches Began,Moved,Ended methods according to what the user does the relevant objects are pulled back from the Singleton array and their position/ability is updated. Therefore the next time the loop runs and they are drawn again the draw method wil update their location or behaviour.
Does this sound about right at this point? Should I be instantiating a GameViewController object to start the level? Should the gameLoop be in the GameViewController or should it be in the GameView. I have added the GameView onto the GameViewController in InterfaceBuilder It will draw the initial objects but I am not sure how to update them going forward. How do I call the drawRect method to update everything?
Anyways, sorry for the extremely long post. I am not looking for a specific answer just a review from someone more experienced in this to tell me:
1) yes you are going in the right direction design wise
2) no you need to rethink a few things
Thanks for your help
Stav
I would really really really recommend using a good game framework like Cocos2d, rather than rolling it all your own.
It's very fast and easy to get rolling with it, and a lot of top games were made with it.
It even has handling for "levels" like you are trying to do.
I downloaded it, and had my first test app up and running in 24 minutes!
Check it out at:
http://www.cocos2d-iphone.org/
I agree on the Cocos2d. On the other hand if you are interested in how the graphics work, start learning OpenGL ES, it's tough to learn but once you know it you aren't as limited as before by using frameworks that do all the work.
On your other question, the design. Apps are built on the MVC model. Depending on the scale of the app, you could put the game loop(logic) in the controller class or for a larger project (and a better design) you should separate the 2 in my opinion.