Here’s what I’m working on. Hopefully this answers the questions I’ve been getting, in particular those about KoboldScript. And what’s happening with it, when is it coming, when can we stop using Corona SDK, etc.
Well then, let’s start with …
Well, the short answer is: KoboldTouch is an MVC wrapper around Cocos2D.
The long answer … let me start by saying that Cocos2D is suboptimal. From a code architecture point of view. Cocos2D has no concept of structure besides views (nodes), and doesn’t encourage structure in your own code. It happily lets users subclass views in order to add data and game logic.
I can’t stop but feel helpless to see beginners learning the things we’ve abandoned 20 years ago as bad practice. Yet Cocos2D code is written by subclassing views as if it were the most natural thing to do. It’s also the very thing Apple tells you not to do.
The result are projects lacking in what is called separation of concerns. It’s not just about experience. Without a clear architectural model frequently reminding you to consider separation of concerns, anyone is more likely to end up creating a blend of design patterns at best, or worse:
Even with good intentions at the beginning my own projects often devolved over time to a greater degree than I would have liked or imagined. Unfortunately KoboldScript is one of the victims.
I created it as an extension of Cocos2D by subclassing CCScene and CCNode. I didn’t like it, yet it seemed the only possible way at the time. But it created a huge problem: a user can easily, and simply by habit, bypass the KoboldScript extensions and run methods on the super classes.
Terrible things happening. Trains crashing. Cute kittens dying in vain. Mothers-In-Law visiting.
I could have enforced policy – which would have meant unlearning how Cocos2D works. I don’t want to force developers to re-learn Cocos2D. I also wanted to encourage Cocos2D developers to stop needlessly subclassing view nodes for game code.
Unhappy with that situation, even though KoboldScript in itself is fairly complete, made me put it away and think about fixing this fundamental issue. It took me a while to realize the solution is already out there.
Why isn’t MVC employed more in game engines?
This very question kickstarted a thought process.
I’ve heard users ask about Cocos2D + MVC before and rather frequently too. I’ve read the few tutorials that exist but none convinced me, they seemed “tacked on”. MVC is certainly something developers are interested in learning or using, specifically if you have a background in Cocoa. But MVC didn’t seem to apply to Cocos2D, or does it?
The breakthrough revelation was to think of Cocos2D as the view and nothing else. Yes, Cocos2D brings along baggage like caching, input, actions, scheduling and so on, but put that away and it’s a 2D hierarchical rendering engine with animation support. Not unlike UIKit.
So I began evaluating how exactly MVC could be applied to Cocos2D. From that thought process the mindmap to the right came to be. It’s already been superseded by the actual implementation.
Right now, I’d say most of you are writing the game code inside subclassed node objects. That’s the Cocoa Touch equivalent of subclassing a UIButton in order to directly update the text that’s in your subclassed UITextField object.
It really sounds scary if you think about it that way!
Let’s put an end to that! One of the goals of KoboldTouch is to make changing these old habits a natural, easy, straightforward, wishing you’d have had always done it like this and wondering how it ever worked before kind of process. But still using Cocos2D as you know it, as the views inside a larger MVC framework.
(cue epic music)
My attempt at adding the missing Model-Controller link to the Cocos2D views is KoboldTouch. It’s a hierarchy of controllers plus an optional model for each controller, where the Cocos2D views (nodes) are encapsulated and managed by view controllers.
Among other things this solves the issue of accessing other nodes in the hierarchy, avoiding (or at least detecting) retain cycles, and having a global game and multiple scene controllers to access global functionality and global data without having to stuff these things into numerous Singleton objects.
The architecture is very modular and plugin-capable. If you need Game Center, you add the GameCenterController. If you need sprite batching, you add your SpriteViewControllers to a SpriteBatchViewController. If you need physics, you add the PhysicsController and specify the physics engine. I already have a simple wrapper for Box2D going, which is pure Objective-C and has a few tricks, like allowing you to add/destroy bodies during the contact callback method!
This works so well, I’m still amazed. Everything just seems to be falling into place naturally. I really felt stupid not having thought about it that way before. It also made me wonder why hasn’t anyone else?
KoboldTouch has the following benefits:
- Whenever possible, follows UIKit naming conventions. For example, viewDidLoad instead of onEnter (huh?) or viewWillDisappear instead of onExitTransitionDidStart (huh?).
- Every controller has a quick access to its parent, the scene and the game controller. Accessing a global controller is always within reach: self.gameController.audioController or self.sceneViewController.physicsController.
- View controllers can register themselves by name on the scene controller. Other controllers can then request a registered controller by name or class. Controllers can easily establish one-to-one relationships. Your boss’s minion controllers need a reference to the boss controller? No problem!
- Since retain cycles are a very real threat in any hierachical code architecture, the game controller verifies that the most recently replaced scene controller did actually deallocate. If not, it shoves it right in your face. The sooner you know it, the easier it’ll be to fix.
- Each controller can have an optional model object, using them comes naturally. But you can also write all the code in the controller. Such a “ModelController” is a viable alternative for simple things, small apps, prototypes and the occasional lazy bean approach.
- View controllers receive the viewWillLoad, viewDidLoad, viewWillDisappear and viewDidDisappear messages to run setup and cleanup code. Models also receive load and unload methods. You almost never have to write any code in the init method. It’s all geared towards lazy initialization.
- Xcode Class Templates for KoboldTouch will allow you to quickly create the Controller and Model source files, one or both.
- Controllers and models automatically run beforeStep, step and afterStep methods when implemented. No (un)scheduling required. To create an interval, simply set the nextStep property to the step number the step methods should run the next time.
- Both controllers and models can be paused, also pausing the step methods of sub controllers. You can pause/resume individual layers, and pausing the scene controller also pauses cocos2d (director pause), whereas pausing the game controller will stop cocos2d altogether (director stopAnimation).
- You do not necessarily have to subclass view controllers. You can use a standard view controller, and pass in a LoadViewBlock to create the nodes for the view when it loads, and assign a model object for the views’ logic and data.
- Because of the standardized controller hierarchy, sharing controller classes is straightforward. Just add the code, create the controller object and start using it! I’m going to rewrite my GameKitHelper singleton as the GameCenterController.
- Models support NSCoding. You can save your models, then when presenting the scene load the saved model data back in. When carefully designed, there’s no need to archive either controllers or views (cocos2d nodes).
One thing of note is that you write the view setup code before presenting the scene.
KoboldTouch is built with ARC, minimum targets are iOS 5.0 and Mac OS X 10.7. This enables the use of zeroing weak references, which make a couple things easier and some possible in the first place. Weak references are a small feature yet extremely helpful in designing a framework like KoboldTouch.
Here’s the preliminary, work-in-progress API reference for KoboldTouch.
Where does KoboldScript fit in?
Coming full circle, KoboldTouch reinvigorates KoboldScript development, with some alterations. KoboldScript has two goals: making it easier to design the node hierarchy (human readable and tool-friendly file format) and scripting game logic.
The view part would be similar to the LoadViewBlock, allowing you to define a branch of the node hierarchy in Lua, then feeding this as input to a ScriptViewController. Minus the part where it runs any logic. It’s primarily settings for the view: which type of view node, where, which image, what color, what text, which view controller class, which script to run, and so forth. Init parameters and properties are direct translations of the Cocos2D class interfaces, thanks to a parser and code generator tool I’ve already written.
Said ScriptViewController would also have a ScriptModel, which would then forward the step, setup and cleanup methods to regular Lua functions residing in a specific Lua script, exposing the model’s interface to Lua. Lua can set and get variables in the model, using KVC for custom variables and direct access for already existing properties.
Scripts only interact with the model, they do not directly interact with the view. If, for example, you need the player sprite to change color after eating a mushroom, you’d have to program that part in the ScriptViewController. This is still beneficial since the bulk of game code is game logic, not view logic. And that glue code requires little effort, and can often even be generalized.
How does KoboldScript compare to … ?
KoboldScript will not enable you to write a game entirely in Lua. It will not attempt to expose the entire Cocos2D API. It can not be any more cross-platform than Cocos2D already is (iOS + Mac).
It will be easy to work with and extend – that’s priority #1!
All Rolled Into Essential Cocos2D
Sometime in the second half of October I will launch Essential Cocos2D, the Cocos2D reference documentation project.
I’ll be writing one or more reference articles every week, based on your suggestions and votes. And I’ll answer your Cocos2D related questions, just like I do on stackoverflow.com but more often and more thorough.
To sweeten the deal I will also give you access to the KoboldTouch project, so you can give it a spin and help guide its development in the right direction. I find it important to see how you’re actually going to use it, to learn what I can improve and what needs fixing.
Once KoboldTouch has matured somewhat I’ll add KoboldScript to the mix!
Essential Cocos2D is not just Cocos2D reference documentation anymore. It will also include a new Cocos2D development paradigm and the support to help you get started running. You can be part of it from the beginning, help me accomplish these goals and at the same time become a better developer and learn best practices.
Stay tuned! Watch this blog for updates and follow me on Twitter.
|Follow @gaminghorror||Follow @kobold2d|