This first lesson goes through the steps to set up a Kobold2D project in XCode and use the accelerometer in the IPhone or IPad.
I am going to focus on the IPad, but the example should work fine in an IPhone as well. The example is very simple and is not yet a game. As the lessons continue a basic game will emerge.
Kobold2D is based on Cocos2D for IPhone project. Kobold2D helps make developing games in Cocos2D easier.
The example works in portrait orientation. Later lessons you change the orientation. Their is a green circle graphic that sits at the bottom of the screen and you can move it left and right by tilting the device. The accelerometer data is read and using some basic velocity adjustments the image moves until it reaches an edge. Here is a screen shot of the completed project.
The frames per second indicator is an option you will see later in the config.lua file.
You need to download and install Kobold2D and XCode.
Lesson Downloads
- Images for project
- Completed Project. This is built in Kobold2d 1.0.1.
[ad name=”Google Adsense”]
Step 1: Start a New Kobold2D Project
Kobold2D handles the creating of XCode projects through its own utility. Currently the recommendation is to close XCode before creating a new Kobold2D project.
Find the folder you installed Kobold2D and then launch the Kobold2D Project Starter application.
Step 2: Select the Empty-Project Template
You are going to start with a bare bones project. The project will actually run but only displays a default splash screen and title screen.
Select an XCode workspace. The default KBold2d.xcworkspace is fine. All Kobold2d projects must be in an XCode workspace. This will appear to be an overkill once you get into XCode such as the Run shows all workspace projects and each with their own targets. You will find launching the wrong project a common problem.
You can create a new workspace here by typing the name. For now we are staying with the default KBold2d.xcworkspace workspace.
Type a project name and click the Create Project from Template button.
Step 3: Add IOS Icons
This step is optional as there will be default Kobold2d icons ready in your project. However if you have your own set you need to copy over them outside of XCode since they are already referenced in the XCode project. I provided a download of the various IOS icons in case you want to practice this step. Copy them as per this image.
Step 4: Add Game Player Images
The game pieces are provided in the download. There is a low and high resolution version named according to the XCode IOS conventions. They are going to be in the Project Files->Resources group. You must copy them from the Finder into the XCode project navigator shown as follows:
Here is the “Choose options for adding these files” dialog. Check “Copy items into destination group’s folder (if needed)”. “Create folder references for any added folders” option is selected although it does not apply as we are not copying folders.
Finally Kobold2D is set up to build your game for a Mac delivery if you choose. We are building for IOS and so you can choose -IOS choice which is proceeded by the name you gave to the project. In our case the “Intro_Tutorial_Lesson_01-IOS”
[ad name=”Google Adsense”]
Step 5: Naming the Game Layer Class Files
The default name for the Game Layer class is HelloWorldLayer. We can leave that and proceed without any issues. But most developers want more control over the name of classes.
Plus you get to see the first glimpse to the internal workings of Kobold2D with the Lua file used for game configuration choices. One configuration is the main game layer class name.
In the project explorer window rename the HelloWorldLayer.h and HelloWorldLayer.m files to GameLayer.h and GameLayer.m files respectively.
Now open the config.lua file. You find this in the ProjectFiles->Resources folder. It is a text file. Change line 18 as you see below. You can look over some of the other potential configuration choices we can use as our work progress such as lines 42- 47 for controlling device orientation.
Line 25 for example contains the DisplayFPS to toggle the viewing of the frames per second. You might use this for testing when your game has performance issues. We will leave it on and you should see the 60 frames per second that is defined on line 24 most of the time for this lesson project.
As well you can add our own configuration variables to this file. A future lesson will provide an example.
--[[ * Kobold2D™ --- http://www.kobold2d.org * * Copyright (c) 2010-2011 Steffen Itterheim. * Released under MIT License in Germany (LICENSE-Kobold2D.txt). --]] --[[ * Need help with the KKStartupConfig settings? * ------ http://www.kobold2d.com/x/ygMO ------ --]] local config = { KKStartupConfig = { -- load first scene from a class with this name, or from a Lua script with this name with .lua appended FirstSceneClassName = "GameLayer", -- set the director type, and the fallback in case the first isn't available DirectorType = DirectorType.DisplayLink, DirectorTypeFallback = DirectorType.NSTimer, 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 DeviceOrientation = DeviceOrientation.Portrait, AutorotationType = Autorotation.CCDirector, ShouldAutorotateToLandscapeOrientations = NO, ShouldAutorotateToPortraitOrientations = YES, AllowAutorotateOnFirstAndSecondGenerationDevices = YES, -- Ad setup EnableAdBanner = NO, PlaceBannerOnBottom = YES, LoadOnlyPortraitBanners = NO, LoadOnlyLandscapeBanners = NO, AdProviders = "iAd, AdMob", -- comma seperated list -> "iAd, AdMob" means: use iAd if available, otherwise AdMob AdMobRefreshRate = 15, AdMobFirstAdDelay = 5, AdMobPublisherID = "YOUR_ADMOB_PUBLISHER_ID", -- how to get an AdMob Publisher ID: http://developer.admob.com/wiki/PublisherSetup AdMobTestMode = YES, -- Mac OS specific settings AutoScale = NO, AcceptsMouseMovedEvents = NO, WindowFrame = RectMake(1024-640, 768-480, 640, 480), EnableFullScreen = NO, }, } return config
Next each GameLayer.h and GameLayer.m file needs to be edited to replace HelloWorldLayer with GameLayer. I will point out those changes as their code is explored for this lesson.
Step 6: The GameLayer.h File
Our header file is rather simple.
First be sure you change HelloWorldLayer to GameLayer on line 10.
On line 12 we define a CCSprite. This defines a 2d image game sprite for our game.
Line 13 defines the velocity for the player. This is a CGPoint object defined as “a structure that contains a point in a two-dimensional coordinate system”. In other words an x and y value.
/* * Kobold2D™ --- http://www.kobold2d.org * * Copyright (c) 2010-2011 Steffen Itterheim. * Released under MIT License in Germany (LICENSE-Kobold2D.txt). */ #import "kobold2d.h" @interface GameLayer : CCLayer { CCSprite* player; CGPoint playerVelocity; } @end
[ad name=”Google Adsense”]
Step 7: The GameLayer.m File
First you need to rename HelloWorldLayer to GameLayer on lines 8, 10 , 20 highlighted so you do not miss them.
Constants defined here include the deceleration of the x velocity of our player at 40%. You can play with the responsiveness of of the accelerometer. The value of 6 seems to work well. Last is the fastest movement for the x velocity of our player.
/* * Kobold2D™ --- http://www.kobold2d.org * * Copyright (c) 2010-2011 Steffen Itterheim. * Released under MIT License in Germany (LICENSE-Kobold2D.txt). */ #import "GameLayer.h" @interface GameLayer (PrivateMethods) @end // Velocity deceleration const float deceleration = 0.4f; // Accelerometer sensitivity (higher = more sensitive) const float sensitivity = 6.0f; // Maximum velocity const float maxVelocity = 100.0f; @implementation GameLayer
The init method allows us to set up basic elements in the game.
Line 27 gets the accelerometer involved. Line 28 sets the filtering in a range of 0 to 1 to respond to movements of the device. Here you are looking for impact of spikes.
Line 30 and 31 adds our player sprite. The z argument is for layering. The tag argument is for developers to use to identify sprites in other Kobol2D methods without having to reference or create a CCSprite object. We do not have a use of the tag property at this point.
Lines 33-35 are for horizontally centering our player. The CCDirector class gives us access to the viewing size with the winSize property. The CCDirector is a Cocos2D class creates and handle the main Window and manages how and when to execute the Scenes.
Line 36 gives the bluish background color. The glClearColor function is clearing the graphics layer.
Lines 38 – 50 demonstrate how to add labels to the game. There are two lines of labels for this example.
The positioning takes advantage of the CCDirector screenCenter property for the first label. The second label uses screenCenter for the x property and offsets against the first label’s y position.
The ccCyan is the color for the text.
The scheduleUpdate method on line 52 calls the update method as often as possible up to the MaxFrameRate set in the config.lua file.
-(id) init { if ((self = [super init])) { // Enable accelerometer input events. [KKInput sharedInput].accelerometerActive = YES; [KKInput sharedInput].acceleration.filteringFactor = 0.2f; // Graphic for player player = [CCSprite spriteWithFile:@"green_ball.png"]; [self addChild:player z:0 tag:1]; // Position player CGSize screenSize = [[CCDirector sharedDirector] winSize]; float imageHeight = [player texture].contentSize.height; player.position = CGPointMake(screenSize.width / 2, imageHeight / 2); glClearColor(0.1f, 0.1f, 0.3f, 1.0f); // First line of title CCLabelTTF* label = [CCLabelTTF labelWithString:@"Kobold2d Intro Tutorial" fontName:@"Arial" fontSize:30]; label.position = [CCDirector sharedDirector].screenCenter; label.color = ccCYAN; [self addChild:label]; // Second line of title CCLabelTTF* label2 = [CCLabelTTF labelWithString:@"Lesson 1" fontName:@"Arial" fontSize:24]; label2.color = ccCYAN; label2.position = CGPointMake([CCDirector sharedDirector].screenCenter.x ,label.position.y - label.boundingBox.size.height); [self addChild:label2]; // Start animation - the update method is called. [self scheduleUpdate];; } return self; }
These next lines handle the case of using automatic reference counting added with the XCode 4.2 compiler. Kobold2D has these constants to help with the alternative compiling choices.
-(void) dealloc { #ifndef KK_ARC_ENABLED [super dealloc]; #endif // KK_ARC_ENABLED }
The acceleratePlayerWithX method adjust the player x velocity keeping it within the maximum limits.
Line 67 is degrading the velocity with the deceleration while increasing it based on the provided input coming from the accelerometer we will see in the update method.
#pragma mark Player Movement -(void) acceleratePlayerWithX:(double)xAcceleration { // Adjust velocity based on current accelerometer acceleration playerVelocity.x = (playerVelocity.x * deceleration) + (xAcceleration * sensitivity); // Limit the maximum velocity of the player sprite, in both directions (positive & negative values) if (playerVelocity.x > maxVelocity) { playerVelocity.x = maxVelocity; } else if (playerVelocity.x < -maxVelocity) { playerVelocity.x = -maxVelocity; } }
The update method on lines 82 and 83 uses KKInput acceleration smoothedX value to call the acceleratePlayerWithX method. The smoothing helps take out spikes in device data input.
The remaining lines 84 to 108 are positioning the player but keeping it withing the left and right boundaries.
#pragma mark update -(void) update:(ccTime)delta { // Gain access to the user input devices / states KKInput* input = [KKInput sharedInput]; [self acceleratePlayerWithX:input.acceleration.smoothedX]; // Accumulate up the playerVelocity to the player's position CGPoint pos = player.position; pos.x += playerVelocity.x; // The player constrainted to inside the screen CGSize screenSize = [[CCDirector sharedDirector] winSize]; // Half the player image size player sprite position is the center of the image float imageWidthHalved = [player texture].contentSize.width * 0.5f; float leftBorderLimit = imageWidthHalved; float rightBorderLimit = screenSize.width - imageWidthHalved; // Hit left boundary if (pos.x < leftBorderLimit) { pos.x = leftBorderLimit; // Set velocity to zero playerVelocity = CGPointZero; } // Hit right boundary else if (pos.x > rightBorderLimit) { pos.x = rightBorderLimit; // Set velocity to zero playerVelocity = CGPointZero; } // Move the player player.position = pos; } @end