Chapter    16

Kobold2D Introduction

In more than two years of working with cocos2d, I found plenty of opportunity and need to improve the cocos2d development workflow by adding helpful code snippets, extending cocos2d classes, enabling easier cross-platform development, automating often-repeated tasks, simplifying the cocos2d upgrade process, and providing complete and accurate documentation. Eventually, this culminated in the inception of Kobold2D, a game engine that’s still very much based on cocos2d-iphone but improves the workflow for cocos2d developers.

The goal of Kobold2D is to make it easier for new developers to work with cocos2d while at the same time satisfying my own needs for a professional work environment (and I hope yours too!).

Kobold2D merges the cocos2d engine with popular libraries many developers have been using with cocos2d in the past. Some of these libraries have almost become essential add-ons, including Lua, the new cocos2d-iphone-extensions project, SneakyInput, Chipmunk SpaceManager, ObjectAL, and iSimulate. Kobold2D makes these libraries readily accessible and usable by all developers—you just have to import a library’s header files and call library methods.

And by the time you’re reading this I will have a version of KoboldScript available for you at www.koboldscript.com. KoboldScript is a Lua scripting interface for cocos2d with statemachines and game components.

In this chapter, I introduce you to the key concepts of working with Kobold2D and how it changes the way you develop cocos2d-based apps. I guide you through the Kobold2D version of the DoodleDrop project to illustrate how easy it is to write a game that also runs on Mac OS computers—and to give you an introduction on Kobold2D user input processing.

You can learn more about Kobold2D and download it at www.kobold2d.com.

Benefits of Using Kobold2D

I view Kobold2D as a game-development kit rather than a game engine. It’s more like a Linux distribution with the cocos2d-iphone project as its “kernel” and multiple other modules tacked onto it, all ready to use after installation.

To stick with the analogy, if cocos2d-iphone were a Linux kernel with just its command-line interface, Kobold2D would be providing the graphical user interface and the essential applications that make the operating system more powerful, enjoyable to work with, and accessible to a broader user base.

At the same time, the command line is still there; it has simply become part of a bigger whole.

Kobold2D Is Ready to Use

Kobold2D installs like a regular application. There’s no need to run a script in the Terminal app or perform any other such error-prone tasks. Download and run the package installer, follow the onscreen instructions, and you’re done. It’s quick and painless.

After installing Kobold2D, you can build one of the 15 template projects right away; most of them are based on projects you’ve worked on throughout the book. With the exception of the app start-up process, which is now simply a configuration file, everything you’ve learned about cocos2d in this book and elsewhere still applies.

The Kobold2D installer also adds the various API references to the Documentation tab of the Xcode Organizer window.

Kobold2D Is Free

Kobold2D is free and distributed under the MIT License. All the included libraries use either the MIT License or a compatible license.

The only exception is iSimulate, which requires the paid iSimulate app from the App Store to unlock all features. The free iSimulate Lite, for example, doesn’t support the forwarding of multitouch events to the iOS Simulator.

Kobold2D Is Easy to Upgrade

A big incentive for Kobold2D was to simplify and streamline upgrading cocos2d in existing projects. The downside of using the cocos2d Xcode project templates is that a copy of the entire cocos2d source code resides in each and every project, making the upgrade process unnecessarily tedious and error-prone.

Kobold2D fixes that by keeping your code separate from any library’s code. If a new version of Kobold2D is released, and you want your project to use the updated code, simply run the Kobold2D Project Upgrader tool of the newly installed Kobold2D version. It will scan previous Kobold2D versions and offer to upgrade each individual project with a click of the mouse. The only task that remains for you to upgrade your code is the unavoidable code maintenance because of API changes—for example, classes that may have been renamed in cocos2d or other libraries, or library methods whose parameters have changed.

Kobold2D Includes Popular Libraries

A central aspect of Kobold2D is to spare developers the pain of adding third-party libraries to cocos2d projects. Correctly setting up third-party libraries often requires intricate knowledge of the build system, an intuition about how to read compiler and linker errors, and possibly even small but crucial source code changes in the right places. It can take hours, if not days, for someone else’s code to compile and link successfully on all platforms: iOS (ARMv6 and ARMv7), iOS Simulator, and Mac OS X both in 32-bit and 64-bit variants, and all of those either with or without ARC.

That’s what Kobold2D provides: lib service. Kobold2D 2.0 includes the following libraries.

Libraries for both iOS and Mac OS X projects:

  • Kobold2D (game engine code, Objective-C)
  • cocos2d-iphone (2D graphics, Objective-C)
  • cocos2d-iphone-extensions (utility code, Objective-C)
  • Box2D (physics, C++)
  • GBox2D (Box2D physics, Objective-C)
  • Chipmunk (physics, C)
  • Chipmunk SpaceManager (Chipmunk physics, Objective-C)
  • CocosDenshion (audio, Objective-C)
  • Lua (scripting)

Libraries available only for iOS projects:

  • ObjectAL (audio, Objective-C)
  • SneakyInput (joystick, Objective-C)
  • iSimulate (library for iSimulate app)

Whenever an essential library such as cocos2d is updated, a new release of Kobold2D will follow within days, if not hours. There’s no need for you to get active on the library front.

Note  You may be wondering why I didn’t include cocos3d in Kobold2D 2.0 even though it’s part of Kobold2D 1.x. The reason is that cocos3d is targeting OpenGL ES 1.1 and is therefore incompatible with cocos2d 2.0 or any other source code that uses OpenGL ES 2.0. The cocos3d roadmap lists OpenGL ES 2.0 support as TBD, meaning when it’ll be available is unknown. Once it is, I’ll add it back in.

Some readers may wonder whether this means that Kobold2D apps are bloated, with all those libraries being included. You may be surprised to hear that early tests showed that Kobold2D apps are actually slightly smaller compared to cocos2d-iphone apps, even though Lua is built into Kobold2D. The reason is that the Kobold2D projects are set up to allow the linker to throw away any code that isn’t used in your app. That means if, for example, you don’t include any of the Box2D headers, none of the Box2D library code will be linked with your app. But if you do want to start using Box2D, it’s as simple as adding the Box2D.h header file to your project, and you’re ready to start writing Box2D-enabled physics apps.

Kobold2D Takes Dual-Platform to Heart

By having one target for each platform (iOS and Mac OS X) by default in its project templates, Kobold2D allows you to build and run your code on both platforms from within the same Xcode project.

Developing for both iOS and Mac OS platforms is also encouraged by the Kobold2D API, which goes a long way toward ensuring that game engine code compiles for both platforms. For example, if you try to read the mouse button states on iOS, the code still compiles, and the result is a safe default, which in this case would simply report that no mouse button is pressed.

The Kobold2D Workspace

After downloading and installing Kobold2D, you’ll find the most recent version of Kobold2D in a versioned subfolder of ∼/Kobold2D—for example, ∼/Kobold2D/Kobold2D-2.0 . The installer will also open the Kobold2D Project Starter.app for you, which allows you to start a new Kobold2D project from one of the supplied project templates (see Figure 16-1).

9781430244165_Fig16-01.jpg

Figure 16-1 .  The Kobold2D Project Starter tool lets you start new projects easily

Select the Hello-Kobold2D template, enter any text in the New Project Name text field, and click Create Project from Template. You can also change the Add to Workspace text if you want to add the new project to a custom workspace (it will be created if necessary). By default, Kobold2D projects are added to the Kobold2D.xcworkspace.

Xcode should now open the Kobold2D workspace that contains your new project, as shown in Figure 16-2.

9781430244165_Fig16-02.jpg

Figure 16-2 .  The Kobold2D Xcode 4 workspace view with the Hello Kobold2D Mac OS X project running

Caution  Kobold2D uses the new workspace concept of Xcode 4, which allows you to combine multiple projects in a single workspace window. If you open the .xcodeproj file of a Kobold2D project either from the most recently used list or by double-clicking it in Finder, the project won’t build successfully. You can easily spot this problem because the Kobold2D-Libraries project will be absent from the Project Navigator pane. Make sure to always open the corresponding .xcodeworkspace file that contains the .xcodeproj that you want to work with.

The Hello Kobold2D Template Project

Let’s take a closer look at the Hello Kobold2D project (Figure 16-2) to demonstrate several key concepts of Kobold2D.

The Hello World Project Files

In Figure 16-3 you’ll see the groups and files in the My First Kobold2D Project, which was created from the Hello-Kobold2D template project.

9781430244165_Fig16-03.jpg

Figure 16-3 .  The default group structure of a Kobold2D project

The immediately noticeable difference compared to a regular cocos2d project is that three groups begin with Projectfiles, and there is the additional BuildSettings group. The idea behind that is to have a Projectfiles group and folder that contain the source code and resource files common to all platforms. The majority of your source code and resources will be in this folder. The additional Projectfiles-iOS and Projectfiles-Mac groups should contain only files used by that particular platform. These groups are meant as suggestions; you’re of course free to structure your project’s group as you see fit.

The BuildSettings group contains several .xcconfig files, which are the textual format for Xcode build settings. Normally you don’t need to modify these files, but in some cases you may want to,—or example, to enable iSimulate. One huge benefit of the .xcconfig files is that you can document them, and accordingly you’ll find several notes for each build setting, what it does, what it affects, and when you might want to enable or disable it. The other big benefit of .xcconfig files is that Kobold2D controls each project’s default settings. Should an Xcode or cocos2d update require different build settings, then that change will be shipped with Kobold2D instead of leaving it up to you. In the past, this has caused a lot of grief whenever certain build settings became incompatible with cocos2d.

Almost all Kobold2D project templates provide targets for both iOS and Mac OS X, which are suffixed with -iOS and -Mac, respectively. I hope that the readily available Mac target will encourage you and other developers to consider cross-platform development from the start and to publish more apps to both the iOS and Mac App Store. It’s certainly a lot easier to take cross-platform development into account from the start rather than porting the app once it’s finished.

How Kobold2D Launches an App

Kobold2D simplifies the start-up process, in particular how much custom code is needed in your project (by default: none). Kobold2D does all the initialization performed by the main function, the app delegate, and the root view controller behind the scenes.

Furthermore, Kobold2D lets you easily modify the start-up settings, such as the first scene or layer to display, the device orientation, the render settings, the Mac window size, Retina support, and many more. All these settings are centralized in the config.lua script file.

Main and AppDelegate

The main.m file is the entry point for each application; it contains the main method. The Kobold2D implementation simply calls its internal method KKMain:

#import "kobold2d.h"
 
int main(int argc, char *argv[])
{
  return KKMain(argc, argv, NULL);
}

KKMain takes both argc and argv arguments and a third, optional parameter that can be used to pass additional parameters to the start-up process if needed. Because that’s rarely, if ever, needed, you can just pass NULL. KKMain hides the complexity of launching the app for either the iOS or Mac OS platform. It also initializes Lua and parses the config.lua file, which provides app configuration settings. I discuss the config.lua file in the next section.

At this point, it makes sense to show you the AppDelegate class of a Kobold2D project, or, rather, what’s left of it. Here’s the interface:

#import "KKAppDelegate.h"
 
@interface AppDelegate : KKAppDelegate
{
}
@end

Nothing there. Maybe there’s more in the implementation part of the app delegate?

#import "AppDelegate.h"
 
@implementation AppDelegate
// Called when Cocos2D is fully setup and you are able to run the first scene
-(void) initializationComplete
{
}
@end

Nope. I can already hear you: dude, where’s my app delegate?

Kobold2D takes care of the entire app start-up process for you and hides it within the KKAppDelegate class from which the AppDelegate class inherits. In particular, KKAppDelegate correctly sets up cocos2d based on the config.lua settings and encapsulates platform-specific app delegate code. This allows Kobold2D to integrate changes to the app delegate class introduced by newer cocos2d versions and makes them available to your projects.

The KKAppDelegate class is a regular UIApplicationDelegate on iOS and an NSApplicationDelegate class on Mac OS; you can implement (override) any of the app delegate protocol methods yourself whenever you need to do so. However, you should make sure to call the super implementation of overridden methods to ensure that KKAppDelegate still performs its duties.

The only custom method that you may find useful is initializationComplete, which is called after the app and cocos2d have been fully initialized but before the first scene is about to be run. You can call the CCDirector runWithScene method inside initializationComplete to run a specific scene. However, that’s not required, because the config.lua file has a setting FirstSceneClassName that lets you specify just the name of the class that cocos2d should run as its first scene without writing any code.

In essence, the Kobold2D classes KKMain and KKAppDelegate provide the common functionality developers expect from these classes. Furthermore, they provide the foundation code for any Kobold2D project, enabling you to use Lua for configuration files, among other things. You also have less code to maintain. In particular, if there’s an essential change to these classes in iOS, Mac OS, or cocos2d, Kobold2D will take care of these changes or additions for you.

The Start-up Configuration File

Kobold2D always loads the Lua script file config.lua, which is in the Resources group of each Kobold2D project.

The config.lua script file returns a Lua table containing all the game’s settings. A Lua table is a flexible data structure that combines the features of dictionaries (indexed by string) and arrays (indexed by value). You can create deeply nested Lua tables—which in terms of possibilities equal XML files or property lists, but with a relatively simple, readable syntax with built-in error-reporting.

Lua scripts are text files, so naturally they’re easier to edit than property lists, regardless of whether you’re using a property list editor or editing the property list XML file directly. And Lua scripts allow you to comment on each line to explain your rationale, the range of valid values, and so on. You can’t do that with property list files because property list editors don’t allow you to comment on entries.

Note  Lua support for Kobold2D was originally provided by the Wax library created by Corey Johnson. Wax allows all Lua scripts to call any Objective-C method and to instantiate Objective-C classes, including cocos2d classes. However, Kobold2D avoids Wax scripting, and eventually most of the Wax project was removed. Instead, Kobold2D uses Lua only to load settings files like config.lua, executing Lua scripts and calling Lua functions. This is fast. For actual game scripting with Lua, the add-on product KoboldScript is currently in development. You can get more info about KoboldScript on www.koboldscript.com.

The config.lua file contains settings for just about everything you might want to tweak during the start-up process. Listing 16-1 shows an example config.lua file.

Listing 16-1.  The config.lua Script Contains All Start-up Settings for Kobold2D

local config =
{
KKStartupConfig =
{
  -- load first scene from a CCScene or CCLayer derived class with this name
  FirstSceneClassName = "HelloWorldLayer",
 
  MaxFrameRate = 60,
  DisplayFPS = YES,
 
  EnableUserInteraction = YES,
  EnableMultiTouch = NO,
 
  -- Render settings
  DefaultTexturePixelFormat = TexturePixelFormat.RGBA8888,
  GLViewColorFormat = GLViewColorFormat.RGB565,
  GLViewDepthFormat = GLViewDepthFormat.DepthNone,
  GLViewMultiSampling = NO,
  GLViewNumberOfSamples = 0,
 
  Enable2DProjection = NO,
  EnableRetinaDisplaySupport = YES,
  EnableGLViewNodeHitTesting = NO,
  EnableStatusBar = NO,
 
  -- Orientation & Autorotation
  -- Kobold2D uses the supported orientations from the Target's Summary pane
  -- (same as Info.plist "Supported interface orientations")
 
  -- iAd setup
  EnableAdBanner = YES,
  LoadOnlyPortraitBanners = YES,
  LoadOnlyLandscapeBanners = NO,
  PlaceBannerOnBottom = NO,
  AdProviders = "iAd, AdMob", -- comma seperated list
  AdMobRefreshRate = 15,
  AdMobFirstAdDelay = 5,
  AdMobPublisherID = "YOUR_ADMOB_PUBLISHER_ID",
  AdMobTestMode = YES,
 
  -- Mac OS specific settings
  AutoScale = NO,
  AcceptsMouseMovedEvents = NO,
  WindowFrame = RectMake(1024–640, 768–480, 640, 480),
  },
}
 
return config

Most of these settings should be self-explanatory and may seem familiar to you. The settings are documented in the KKStart-upConfig class in the Kobold2D API Reference and here: www.kobold2d.com/display/KKDOC/Config.lua+Settings+Reference.

For example, the FirstSceneClassName setting lets you specify the name of a class inheriting from CCScene or CCLayer (automatically wrapped inside a CCScene), which will be the first scene run by the CCDirector. You can enable iAd or AdMob ad banners, or provide the default window position and size for Mac builds.

The big advantage of using a Lua-based configuration file is that the entire start-up code is part of the Kobold2D code and can be updated in new versions if it needs to be. As Kobold2D matures, more settings will be added to the start-up config, depending on what developers need to change or include most in their apps. In addition, you can create and use custom config.lua settings. The Hello World project provides an example of loading custom settings. I’ll get to that in the next section.

Tip  You can learn more about Lua from the free Programming in Lua book, available online on the official Lua home page at www.lua.org/pil. The book is for an older version of Lua but is still largely relevant. You may also want to browse the Lua reference manual at www.lua.org/manual to get a quick overview of the language. Lua has grown to be the number-one scripting language for game developers over the past ten years. It has a very small memory footprint and speed-wise often comes close to 80 to 90 percent of the performance achievable with C programming.

The Hello Kobold2D Scene and Layer

Let’s move on to the actual scene class HelloWorldLayer, which is set as the first scene via the config.lua setting FirstSceneClassName = "HelloWorldLayer". You’ll notice that this first scene is actually derived from CCLayer. Kobold2D realizes that and automatically wraps the HelloWorldLayer class into a CCScene instance behind the scenes.

Tip  To avoid writing the repetitive +(id) scene method in each CCLayer class, you can simply call the +(id) nodeWithScene method in Kobold2D:

[[CCDirector sharedDirector] replaceScene:[MyGameLayer nodeWithScene]];

The HelloWorldLayer interface declaration is pretty unspectacular and provides only three instance variables that will later be loaded from the config.lua file:

#import "cocos2d.h"
 
@interface HelloWorldLayer : CCLayer
{
  NSString* helloWorldString;
  NSString* helloWorldFontName;
  int helloWorldFontSize;
}
 
@property (nonatomic, copy) NSString* helloWorldString;
@property (nonatomic, copy) NSString* helloWorldFontName;
@property (nonatomic) int helloWorldFontSize;
 
@end

At this point, you should take note of a particular addition to the config.lua file. There’s an additional Lua table labeled HelloWorldSettings in Listing 16-2, which provides three familiar-looking settings: HelloWorldString, HelloWorldFontName, and HelloWorldFontSize.

Listing 16-2.  Custom config.lua Settings

local config =
{
  KKStartupConfig =
  {
  -- start-up settings removed for brevity
  },
 
  HelloWorldSettings =
  {
  HelloWorldString = "Hello Kobold2D!",
  HelloWorldFontName = "Marker Felt",
  HelloWorldFontSize = 50,
  },
}

With the exception of the uppercase first letter, these settings match the properties of the HelloWorldLayer class in name and data type. I’m sure you can see the connection here. Indeed, the KKConfig class method injectPropertiesFromKeyPath, shown in Listing 16-3, loads the values from the HelloWorldSettings subtable and injects them into the correspondingly named properties of the target class, in this case self.

Listing 16-3.  Injecting (Assigning) the Custom Settings to Class Properties

[KKConfig injectPropertiesFromKeyPath:@"HelloWorldSettings" target:self];

By inject I mean if there is a Lua table named HelloWorldSettings, then each setting it contains will be assigned to a correspondingly named property of the target class, in this case self. For example, the setting HelloWorldString will be assigned to the class property helloWorldString if it has the correct data type (NSString*) and isn’t set to be a readonly property.

Tip  By using KKConfig, you can easily make your app data-driven, which for example allows designers and artists to tweak your app’s behavior without having to modify source code. Data-driven development also comes to shine when you have a variety of game objects with the same or similar settings. You don’t want these settings spread throughout your code—you want to centralize them in a single file that provides the necessary overview.

After injection, the three properties will contain the same values as the HelloWorldSettings Lua table. They’re ready to be used by the label:

CCLabelTTF* label = [CCLabelTTF labelWithString:helloWorldString
                                       fontName:helloWorldFontName
                                       fontSize:helloWorldFontSize];

Listing 16-4 shows the HelloWorldLayer implementation in its entirety. Apart from the previous call to KKConfig and the use of the CCDirector extensions and platform macros discussed earlier, it’s still 100-percent cocos2d code.

Listing 16-4.  Hello Kobold2D Implementation File

#import "HelloWorldLayer.h"
 
@implementation HelloWorldLayer
@synthesize helloWorldString, helloWorldFontName;
@synthesize helloWorldFontSize;
 
-(id) init
{
  if ((self = [super init]))
  {
  CCDirector* director = [CCDirector sharedDirector];
 
  CCSprite* sprite = [CCSprite spriteWithFile:@"ship.png"];
  sprite.position = director.screenCenter;
  [self addChild:sprite];
 
  // get the hello world string from the config.lua file
  [KKConfig injectPropertiesFromKeyPath:@"HelloWorldSettings" target:self];
 
  CCLabelTTF* label = [CCLabelTTF labelWithString:helloWorldString
  fontName:helloWorldFontName
  fontSize:helloWorldFontSize];
  label.position = director.screenCenter;
  label.color = ccGREEN;
  [self addChild:label];
 
  // print out which platform we're on
  NSString* platform = @"(unknown platform)";
 
  if (director.currentPlatformIsIOS)
  {
  // add code
  platform = @"iPhone/iPod Touch";
 
  if (director.currentDeviceIsIPad)
  platform = @"iPad";
 
  if (director.currentDeviceIsSimulator)
  platform = [NSString stringWithFormat:@"%@ Simulator", platform];
  }
  else if (director.currentPlatformIsMac)
  {
  platform = @"Mac OS X";
  }
 
  CCLabelTTF* platformLabel = [CCLabelTTF labelWithString:platform
  fontName:@"Arial"
  fontSize:24];
  platformLabel.position = director.screenCenter;
  platformLabel.color = ccYELLOW;
  [self addChild:platformLabel];

  glClearColor(0.2f, 0.2f, 0.4f, 1.0f);
  }
 
  return self;
}
 
@end

Notice the way I determine the platform (iOS, Mac OS) and device type (iPad, iOS Simulator) using director properties such as currentPlatformIsIOS and currentDeviceIsSimulator. These are some of the extensions to CCDirector I mentioned earlier.

You may be wondering why I haven’t used preprocessor macros like __IPHONE_OS_VERSION_MAX_ALLOWED to determine platform and device type. First, in Kobold2D I wouldn’t have used the hard-to-remember and verbose SDK macros. Instead, Kobold2D provides the simpler macros KK_PLATFORM_IOS and KK_PLATFORM_MAC to differentiate between the two supported platforms. If needed, you can also differentiate between iOS device and iOS Simulator by using the macros KK_PLATFORM_IOS_DEVICE and KK_PLATFORM_IOS_SIMULATOR.

The real reason for not using preprocessor macros and why conditional compilation with #ifdef should be used only as a last-resort measure is this: the compiler is your friend! Every time your code is compiled, the compiler lets you know that everything is in order or tells you whatever is technically or syntactically wrong with your code. It may be annoying at times, but the compiler is only letting you know that you made a mistake or forgot something. Allowing as much code as possible to be compiled by the compiler every time you build the code is so important for cross-platform development that the added overhead of platform and device runtime tests are entirely negligible.

Once you do cross-platform development, you’ll likely spend a lot of time working on and compiling code for only one platform. Any code that’s within an #ifdef for the other platform is invisible to the compiler, and it won’t complain about errors. Now as soon as you switch targets and compile for the other platform, you’ll likely run into errors that were thus far ignored due to the use of #ifdef. These errors may be related to code changes that you made an hour ago, a day ago, or maybe even a week ago.

Not only does it cause a lot of mental load to figure out which code change caused the error and what the correct fix will be, it’s also frustrating because you’ll frequently find that switching target platforms results in build failures. Either you’ll spend more time than necessary building code regularly for both target platforms or you’ll simply give up, maybe with the good intention of porting the project when it’s finished. However, porting a completed project is much more work than developing it for both platforms from the beginning.

Code that compiles works. At least it’s technically correct. Immediate build errors are more likely to be corrected right away and easier to fix because you still have the most recent code changes in your short-term memory.

Running Hello World with iSimulate

To enable iSimulate you have to open the BuildSettings-iOS.xcconfig file, which is located in the BuildSettings group of your Kobold2D project. The only thing you have to do is to remove the comment from this line:

OTHER_LDFLAGS[sdk = iphonesimulator*][arch = *] = $(OTHER_LDFLAGS) $(FORCE_LOAD_ISIMULATE)

Now if you run the Hello World project on the iPhone or iPad Simulator, you’ll notice a network connection dialog as in Figure 16-4, which is the reason iSimulate is disabled by default. Several users have complained about it; some were confused why Kobold2D projects would want to accept incoming network connections. You’ll also notice the iAd banner that shows up because it was enabled in config.lua.

9781430244165_Fig16-04.jpg

Figure 16-4 .  Network connection warning caused by iSimulate

Note  If you see an bannerView:didFailToReceiveAdWithError error in your log with the message “The operation couldn’t be completed. (ADErrorDomain error 1.),” then this is most likely caused by the app not being set up for iAd. The iAd service needs to be enabled for each app and each developer in iTunes Connect. You’ll find more information about enabling iAd for your app at https://itunesconnect.apple.com/docs/iTunesConnect_DeveloperGuide.pdf.

As I said, the incoming network connections warning dialog is caused by iSimulate. The iSimulate library needs to accept incoming connections from the iSimulate app, which you can run on your WiFi-enabled iOS device in order to remote control the simulator. In other words, iSimulate enables you to test your game using your device but running in the Simulator. All the features the Simulator doesn’t have—such as GPS, accelerometer, or multitouch—can be simulated with the iSimulate app. It can be a real time-saver.

For example, if you have iSimulate running on your device and connected to your Mac, you will receive messages like accelerometer:didAccelerate: in your app, even though the Simulator doesn’t have an accelerometer. This makes iSimulate an invaluable tool if you consider that running your app is usually a lot faster than deploying it to a device. I recommend giving it a try with Kobold2D’s User-Input template project.

iSimulate is available on the App Store and normally costs $15.99: http://itunes.apple.com/app/isimulate/id306908756.

DoodleDrop for Mac with KKInput

So far, all the projects throughout the book were written for iOS. If you install Kobold2D, you’ll notice that not only are most of the book’s projects included in Kobold2D, almost all of them also have a Mac OS version.

So, what would it take to make a project like DoodleDrop from Chapter 4 work both on Mac and on iOS? Not that much actually. It turns out that by far the biggest change is related to handling user input. Thankfully, Kobold2D provides a platform-agnostic user input handler that simplifies user input dramatically by allowing you to test the state of input devices at any time in any class and method.

First, the accelerometer:didAccelerate event method has been removed because it’s no longer needed. Instead, KKInput will be responsible for providing the app with acceleration values. You tell it to activate accelerometer input and to set the filtering factor in the init method of the DoodleDrop GameLayer class:

// Yes, we want to receive accelerometer input events.
[KKInput sharedInput].accelerometerActive = YES;
[KKInput sharedInput].acceleration.filteringFactor = 0.2f;

Enabling the accelerometer will first test whether the device supports the Core Motion framework. If so, acceleration values will be provided by Core Motion, which gives us a tiny performance benefit. In all other cases, the standard UIAccelerometer interface is used to obtain acceleration values. The filtering factor is a percentage that determines how responsive the game character will react to sudden changes in acceleration.

Listing 16-5 shows the modified DoodleDrop update method that includes user input handling for both platforms.

Listing 16-5.  Handling User Input for Both Platforms with KKInput

-(void) update:(ccTime)delta
{
  KKInput* input = [KKInput sharedInput];
  if (isGameOver)
  {
  if (input.anyTouchEnded ||←
  [input isKeyDown:kKKKeyCode_Space] ||←
  [input isKeyDown:kKKKeyCode_Return])
  {
  [self resetGame];
  }
  }
  else
  {
      [self acceleratePlayerWithX:input.acceleration.smoothedX];
 
      if ([input isKeyDown:kKKKeyCode_LeftArrow])
      {
      [self acceleratePlayerWithX:-keyAcceleration];
      }
      else if ([input isKeyDown:kKKKeyCode_RightArrow])
      {
      [self acceleratePlayerWithX:keyAcceleration];
      }
 
      // The rest of the update code remained unchanged.
      ...
  }
}

The update method processing is split into handling the gameover and the rest of the code that runs while the game is commencing. If the game is over, you simply check whether any touch ended, or the spacebar or Return key is being held down, before resetting the game and starting over.

While the game is running, the player’s velocity is updated either based on the input.acceleration.smoothedX value or based on a constant keyAcceleration value when either the left or right arrow key is held down. The acceleratePlayerWithX method is shown in Listing 16-6 (coming up soon), which contains the code previously in the accelerometer:didAccelerate method.

KKInput provides you with built-in high-pass and low-pass filters via properties of the KKAcceleration class exposed by the input.acceleration property. You can access the raw acceleration, the smoothed (low-pass filtered), and the instantaneous (high-pass filtered) values. In most games, you want to use the smoothed values, which provide steady acceleration and cancel out sudden, short-lived movements. Instantaneous acceleration values are useful whenever you want to react to sudden acceleration movements, such as shaking or quickly flipping the device.

You’ll notice that the input code doesn’t use conditional compiling via #ifdef. If you run this code on Mac, the anyTouchEnded method is guaranteed to return NO all the time. Likewise, when running on iOS, the isKeyDown method always return NO, because there’s no keyboard available. And the input.acceleration values are all 0 on Mac OS.

If it seems wasteful to you to test for keyboard events on iOS and touch events on Mac OS, please keep in mind that the additional overhead is minimal while the benefit of always compiling all your code guarantees that it continues to work for both platforms. If the platform-specific code is extensive, you can always branch it using the Kobold2D CCDirector extensions like currentPlatformIsIOS and currentPlatformIsMac.

Listing 16-6.  Updating the Player’s Velocity

-(void) acceleratePlayerWithX:(double)xAcceleration
{
  // adjust velocity based on current accelerometer acceleration
  playerVelocity.x = (playerVelocity.x * deceleration) +
  (xAcceleration * sensitivity);
 
  // we must limit the maximum velocity of the player sprite, in both directions
  if (playerVelocity.x > maxVelocity)
  {
  playerVelocity.x = maxVelocity;
  }
  else if (playerVelocity.x < −maxVelocity)
  {
  playerVelocity.x = −maxVelocity;
  }
}

Everything else requires no changes to create the Mac OS port, thanks to the fact that no hard-coded positions and offsets were used. Nevertheless, it makes sense for game play reasons to restrict the Mac window size to that of an iPhone in config.lua:

WindowFrame = RectMake(300, 300, 320, 480),

The Lua function RectMake creates a rectangle with the given origin (300, 300) and size (320, 480). RectMake creates rectangles that are compatible with CGRect or NSRect, depending on the platform. Additional Lua utility functions are PointMake and SizeMake.

Summary

I hope that this chapter has given you a good impression of how working with Kobold2D will help you make games and apps easier and have more possibilities. On the www.kobold2d.com web site, you’ll have access to the API documentation of all libraries, a programming guide, the support forum, the feedback section, and a road map that allows you to see how Kobold2D development is progressing. And you definitely should check up on the progress I’m making regarding KoboldScript at www.koboldscript.com. KoboldScript is the Lua game-scripting interface for Kobold2D and cocos2d.

One of the most important features of Kobold2D is its ability to use Lua tables to define settings. You’ll then be able to feed these settings directly into properties of class instances with just a single call to the KKConfig class. This is even more important if you work with others who need to make changes to the app but don’t want or shouldn’t have to change the source code.

Kobold2D also makes dual-platform development for iOS and Mac OS easier and provides a convenient, one-stop class for handling user input, as you saw in this section. You’ll also find plenty of template projects in Kobold2D based on projects created throughout the book and subsequently ported to work on Mac OS.

What’s left is for you to go to www.kobold2d.com now to download the latest version, install it, and start experimenting with the provided template projects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.16.171