iPhone_WoodBGwMarbleWe recently answered the question, “How do I access accelerometer data?”.  If you have not read this article or you are not familiar with accessing accelerometer data then please pause here and take a minute to read the article.  In today’s tutorial we will take this new knowledge and apply it to build an app to simulate a ball rolling on a table.  This technique would be used to create a Labyrinth type game.

First we will setup our Xcode project.  We will be using Sparrow 2.0 which is a pretty awesome Free and Open Source game engine for iOS. To simplify the project setup we will start with the barebones project provided with the framework.  This just gets us started quickly.  I will not cover this in detail but you can find the instructions by using the link in the resources section at the end of this article. Copy and rename the barebones project according to the instructions and add the media resources.  For your convenience we have a barebones project with media available on our Github repo.  You can use the Github ribbon link or the link from the resources section.  Before you continue make sure you can build and run this new project.

Now that we have the project in order we can move on to the fun stuff.  Our example app will contain three sprites:

  • Game which will act as our root display object.
  • PlayingField which will represent the surface on which our marble will roll around.
  • MarbleSprite which will, you guessed it, represent our marble.

Joseph-Says-Doubleclick

The Field of Play

The playing field is one of the basic building blocks of a game.  Start by adding a new Objective-C class to the project as a subclass of SPSprite named PlayingField.  Now we will set up a bit of the playing field scaffolding.

Replace the contents of PlayingField.h with

Replace the contents of PlayingField.m with

Ultimately we are just implementing some best practices of breaking the building blocks of our game into separate classes and giving them their own juggler.  This provides easier access and tighter control over the animations in your game.

Before we move on with our building block scaffolding we will add a background to our PlayingField.

Add the following to the bottom of the setup method.

Let’s continue the scaffolding work over in the existing Game class.

Replace the contents of Game.m with

Now we have our game loop set up and can implement our PlayingField class.

First we need to import the PlayingField class.

Then declare an instance variable.

Assign the variable to a new instance of the PlayingField class just inside the setup method.

Finally, let’s advanceTime:seconds of the PlayingField in the game loop.

Build and run the project using the iPhone Simulator. Voila!

iPhone_WoodBG

OK it’s not that exciting… Yet.

Where’s the marble?

We can’t have an accelerometer example without having something to roll around.  Let’s add a marble.  Start by creating another Objective-C class in our project as a subclass of SPSprite.  Name this one MarbleSprite.

We will start by adding a factory class method.  Replace the contents of MarbleSprite.h with

Now we will implement the factory method and setup our initialization methods.  Replace the contents of MarbleSprite.m with

  1. Implement our factory method.  A practice I like to follow.
  2. Override our init method to call setup.
  3. setup method which is another pattern I tend to follow.
  4. Declare an instance variable to hold our marble image.
  5. Create the image object and add it to the SPSprite child collection.

Moving back to the PlayingField we will add the marble.  First things first, add the import statement.

Then declare an instance variable.

Now create an instance of MarbleSprite, set an x-y coordinate and add it to the display tree.  Add the following to the bottom of the setup method after we add the background image.

Build and run the project, round 2.

iPhone_WoodBGwMarble

“I feel the need, the need for speed.”

Bryneth-Says-Velocity

It is time to put our marble in motion. However, it is actually velocity that we want not just speed.  Velocity is a vector quantity that refers to “the rate at which an object changes its position.”    Since our marble will be moving in two dimension we will track the velocity of the x and y positions.  Many game developers will express this with the CGPoint struct because it conveniently has an x and y property.  We will just use two variables.  Add the following two variables in MarbleSprite.m to track our velocity.

Give it a starting velocity to get us rolling. Change the setup method so that we have a velocity on the x axis of 100 and a velocity on the y axis of 100.

This means our marble will roll equally along the x and y axis by a velocity of 800.  There is no significance in the value 800.  Sample different values to see the affect.

Animate the marble

Now that the marble knows its velocity we can animate it.  There are many ways to animate a sprite.  I like to have the sprite handle its own animation by implementing the SPAnimatable protocol. SPAnimatable describes an object that is animated depending on the passing of time.  We have a velocity that tells us how to animate the marble on the x and y axes per second.  Sounds like a fit.

SPAnimatable only has one method to implement advanceTime:seconds.  Define the method in MarbleSprite.h.

In MarbleSprite.m add the method advanceTime:seconds

Note how we didn’t just add the velocity x and y values to the marbles position but rather we factored that movement according to time in seconds (twice, Google Basic Physics).  The seconds parameter tells us how far to advance the animiation.

All that is left is to ensure that advancedTime:seconds gets called which is the job of the juggler.  Add the MarbleSprite object to the PlayingField’s juggler. In PlayingField.m add the following to the setup method after we add the marble to the display tree.

Build and run the project and see that our marble is now animated.

Don’t lose your marbles

Animation is cool but we seem to have lost our marble.  It has continued on for eternity off of our device screen.  What can we do?  We could, when time advances, check to see if the marble has hit the edge.  First define the method checkEdgeCollide in MarbleSprite.h.

Then implement the method in MarbleSprite.m.

After getting the bounds of the MarbleSprite within the scene we [1] determine if the bounds are off the screen according to the x axis.  It would be possible to perform this check without getting the sprites bounds within the scene space but the SPRectangle class provides some very helpful properties that greatly simplify the process.  [2] If the marble has exceeded the left or right edge of the device then we stop the velocity on the x axis and set the marble’s x position to the appropriate edge value needed to ensure the entire marble is visible.  In some cases you may want to provide an affect of hitting the edge.  You could do this by reversing the velocity instead and possibly even apply a collide dampening factor.  For this example we are going to keep it simple.  [3] Next we check if the bounds are off the screen according to the y axis.  [4] Following the same logic as we did on the x axis, stop the velocity on the y axis and set the marble’s y position to the appropriate edge value.

All that is left is to have this check performed after the animation.  Add the following line to the end of the advanceTime:seconds method in PlayingField.m

If you build and run the project you will see that once the marble reaches the edge of the device on any particular axis it stops moving along that axis and the marble remains visible.

Sound using the Media Class 

Before we get to the accelerometer lets add a bit of spice to the example.

If we had setup our project using the Sparrow Framework scaffold project it would have included a Media class.  It is a good organizational practice to use such a class to manage sound and textures in one place.  Add a new Objective-C class file subclass of NSObject to the project and name it Media. Replace the contents of Media.h with

Here we define the interface for four static methods.  A method to initialize and one to release the sound resources.  Then we have two methods one to return a soundChannel of a specific name and one to playSound.

Now replace the contents of Media.m with

[1] We start out by declaring a static NSMutableDictionary to hold our sounds. [2] In the initSound method we first start the SPAudioEngine then we will iterate through the enumeration of files in our bundle and if they match a specific file extension we will add it you our dictionary of sounds.  [3] When we are done using the sound engine we will want to release the resources most notably stoping the SPAudioEngine.  This is accomplished in the implementation of releaseSound.

Now add the following to Media.m

[1] The first static method implemented in this section of code is playSound:soundName.  This method is used to play any sound file and is best used for general game sound effects.  The method will first look in our dictionary for previously loaded sounds otherwise it will load and play the sound from a file.   [2] Most games will have longer running sound or music such as that found in a cutscene or background music.  The soundChannel:soundName method can be used to return the SPSoundChannel for this sound.  Here again it first looks to see if the sound was preloaded during the initSound method otherwise it loads the sound from the contents of a file.

When the marble collides with the edge of the screen we are are going to play a sound.  To get things started import the Media.h in the MarbleSprite.m file.

Add a collide method to MarbleSprite.m in which we will use the Media playSound:soundName method to play a collision sound.

We will add a couple of instance variables to help us track if the marble was previously sitting on the edge.

Finally make the following changes to the checkEdgeCollide method in MarbleSprite.m.

We are simply calling the collide method if the bounds indicate an edge collision and the marble was not already on the edge.

Build and run it this time and we will see that as soon as the marble hits the top edge and then the right edge we hear the collision sound.

Control the marble using the accelerometer

device_axesNow, the moment is finally here.  We are going to implement the use of the accelerometer to control the marble.  The accelerometer provides measurement of acceleration along the three spatial axes at a moment of time.  The x, y and z values give you the acceleration of the device in each of the three directions in terms of g, the acceleration due to gravity.

In this example we will implement the acceleration data amplify and filter techniques as provided by Sparrow’s accelerometer tutorial.   We will not spend much time explaining these techniques as they are well documented in the Sparrow Framework wiki.  The link can be found in the resource section at the end of this article.

We will start with changing our initial values for our marbles velocity.  Change the following lines in MarbleSprite.m setup method.

Then define a way for us to accelerate our marble.  Define the following method in MarbleSprite.h

In this method we add the provided x and y acceleration values to our current velocity.  Add the implementation of the method to MarbleSprite.m.

The CMMotionManager provides the accelerometer data.  First we need to link to the CoreMotion.framework library.

LinkLibrary

Now add the required import statement in PlayingField.m.

Also add the constant values for use in the acceleration data amplify and filter techniques as well some instance variables.  One for the CMMotionManager and two variables to use in the accelerometer filtering.

Perform the appropriate initializations in the setup method of PlayingField.m.

Directly after this place the following in the setup method of PlayingField.m  This snippet of code will initialize the NSMutableArrays used to filter out the accelerometer noise.

Now that the accelerometer is ready to use create a processAccelerometer method in PlayingField.m.

[1] First we will setup a couple of variables for our x and y acceleration. [2] Next we access the accelleration data from the _motionManager.accelerometerData.acceleration property.  If you remember from our  “How do I access accelerometer data?” article this is using the periodic sampling technique.  [3] Now the important part, we average the previous readings and apply the accelerometer amplify technique covered in the Sparrow Framework tutorial. [4] Last, we will accelerate the marble using accellorateByX:y.

Finally, call processAcceleration from advanceTime:seconds in PlayingField.m.

That is it.  We are now controlling our marble with the accelerometer.  There is one important aspect about running our app now.  Because we are using the accelerometer the iPhone Simulator is no longer an option.  You must build and run the app from your connected device.  Do that now…. tada!

If you liked this tutorial and would like to see more, be sure to subscribe.  More tutorials coming soon!

Resources