You are on page 1of 63

Audience for This Book

This book is for all developers who are interested in creating games on smartphone platform, especially on iOS (including iPhone, iPad, and iPod touch) and Android. This book assumes basic understandings of programming language (i.e. JavaScript) and basic knowledge of software development using IDE (Eclipse or Xcode). This book is a hands-on guide to creating games for smartphone with emo-framework, which uses easy-to-use, intuitive scripting language.

What is emo-framework?
emo-framework is a cross-platform lightweight game engine for smartphone platform which uses scripting language for your game logic. emo is licensed under the terms of New BSD license, which is popular open-source license that can be used with any commercial products. You can write your game logic once with emo that runs on both iOS and Android platforms. emo uses Squirrel: an object-oriented scripting language for your game logic. Every programmer who get used to JavaScript, C++, Java or Lua could easily get used to Squirrel because Squirrel has simple syntax that is similar to JavaScript and Lua etc. emo is based on OpenGL ES: the widely known graphic library for embedded platforms which enables smooth rendering on iOS and Android. emo for Android is based on NativeActivity that causes no garbage collection and no "stop the world" thing. emo also uses OpenAL and OpenSL for audio interface that provides low latency audios. emo is currently runs on iOS (including iPhone, iPad, and iPod touch) and Android 2.3 and above.

emo is released under the terms of the open-source license: New BSD License. You can use emo framework at absolutely free of charge. You don't have to disclose your source code even in the commercial products. And also you don't have to show any logo or something like that of emo framework in your game. (Note: redistributions in binary form must reproduce the copyright notice, see the license documents for details: http://www.emo-framework.com/license.html

http://www.emo-framework.com/

emo-framework official site provides a number of reference documents, source codes and the latest news about emo. Go to http://www.emo-framework.com/ for details.

What is Squirrel?
"Squirrel is a high level imperative, object-oriented programming language, designed to be a light-weight scripting language that fits in the size, memory bandwidth, and real-time requirements of applications like video games." -- squirrel-lang.org Squirrel is intuitive lightweight object-oriented programming language that fits real-time requirements of your games. You can write all of your game logic by using Squirrel programming language. You don't have to learn Objective-C or even Java, You need no knowledge about Apple's Foundation Framework nor Android API. With the power of Squirrel and emo framework, you can write your game once by Squirrel that runs on both Android and iOS!

http://squirrel-lang.org/

What does Squirrel look like?


// Define Entity class class Entity { constructor(etype, entityname) { name = entityname; type = etype; } name = null; type = null; } // Define Player class that extends Entity class Player extends Entity { constructor(entityname) { base.constructor("Player", entityname) } function DoDomething() { print("something"); } } // Create Player instance local newplayer = Player("da playar"); newplayer.doSomething(); The example above explains how Squirrel treats object-oriented classes. This example defines a Player class that extends Entity class. The syntax of Squirrel is much like other modern programming language like JavaScript, C++ and Java but the language has a very dynamic nature like Python/Lua etc. Squirrel offers a wide range of features like dynamic typing, exception handling, delegation and cooperative threads. You can write your game logic in object-oriented way because Squirrel supports object-oriented scripting for its nature. For details about specifications about Squirrel scripting language, please refer to http://squirrel-lang.org/#documentation for details.

What does emo look like?


emo-framework uses Squirrel scripting language for your game logic. The script below defines two stages that load sprite images. Level_1 stage is loaded after the script is loaded, and Level_2 stage will be loaded after user touches screen on Level_1. // emo.Stage instance for loading stages local stage /* * Define Level_1 stage class */ class Level_1 { dogSprite = emo.Sprite("dog.png"); // Load dog sprite function onLoad() { dogSprite.load(); } // Dispose dog sprite function onDispose() { dogSprite.remove(); } // When user touches the screen, loads next stage (Level_2) function onMotionEvent(motionEvent) { if (motionEvent.getAction() == MOTION_EVENT_ACTION_DOWN) { stage.load(Level_2()); } } } // continue.. = emo.Stage();

/* * Define Level_2 stage */ class Level_2 { kingSprite = emo.Sprite("king.png"); // Load king sprite function onLoad() { kingSprite.load(); } // Dispose king sprite function onDispose() { kingSprite.remove(); } } // Load Level_1 after script is loaded function emo::onLoad() { stage.load(Level_1()); }

How about that? The syntax of Squirrel is much similar like JavaScript or C++ and programmers who are familiar with them are soon get used to it in a minute. The stage class like Level_1 and Level_2 receives onLoad callback when the stage is loaded, and receives onDispose callback when the stage is going to be disposed. onMotionEvent is fired when the user touches the screen. As you can see, the stage classes are very simple Squirrel classes. For more information about how Squirrel treats object-oriented classes, see ttp://squirrel-lang.org/doc/squirrel3.html#d0e1580 for details.

The Development Environment


You can write your game logic once that runs on both Android and iOS with the power of emo. emo uses IDEs to develop games. emo uses Eclipse with Android SDK for Android, and Xcode for iOS.

Figure: emo uses Android SDK and iOS to build emo applications.

You can use Windows, Mac and even Linux when you decide to develop games for Android. If you have Windows PC only, Android SDK is your choice. If you have Mac you can use both Android SDK and Xcode. In my opinion it is better to use Xcode when you develop game on Mac because the iPhone simulator on Xcode seems to be much faster than the Android simulator. If you write your game for Android you can use Android simulator and/or physical Android devices. If you write your game for iOS, iPhone simulator will be your choice. Note that even though you can install any applications on your Android devices through adb for debug, on the other hand you can 't install your applications on your iPhone for debug if you are not the member of iOS Developer Program. For more information about iOS Developer Program, see http://developer.apple.com/ for details.

Apple Developer: http://developer.apple.com/

Setup Eclipse and Android SDK


If you are going to write games for Android, setup Android SDK and Eclipse first. emo uses Android SDK to develop games for Android.

Figure: Eclipse with Android SDK

emo uses Android SDK platform 2.3 and above to build games for Android. For more information, please refer to the following document to see how to install Eclipse with Android SDK.

http://developer.android.com/sdk/installing.html

Setup Xcode
If you would like to develop games for iOS, you need to install Apple's Xcode. It is easy to setup Xcode because Apple delivers application installer for Xcode. Go to Developer Tools page of Apple Developer, download and install the latest Xcode program. If you have OS X Lion, Xcode is also available on Apple's App Store. l l http://developer.apple.com/technologies/tools/ http://www.apple.com/iphone/from-the-app-store/

Figure: Welcome dialog of Xcode

After installing Xcode, you have to install project template for emo. emo is shipped with project template installer for Xcode that is detailed in the later section.

10

Downloading emo-framework
After installing development environment for each platforms, proceed to the next! Go to download section on emo-framework.com and grab the latest source codes.

Downloads: http://www.emo-framework.com/downloads.html

Go to http://www.emo-framework.com/downloads.html and click the folder icon at "Download the source" section. emo is an open-source project and entire source codes are on the Google Code project page. Go to Google's project hosting page and grab the latest code that is marked as "Featured".

11

Google Codehttp://code.google.com/p/emo-framework/downloads/list

After downloading the latest archive, unzip it into your working directory. You can also checkout the latest source codes from the repository using subversion as emo is an open-source product that is placed on Google Code project hosting. Use svn to checkout the latest development source codes if you like.

Figure: Checking out the latest source codes using subversion

12

Installing emo (Android)


After downloading the source codes of emo framework, setup them into your development environment. For Android platform, there is no installer. emo delivers the project template for Eclipse in the Android-Template directory that will be detailed in the later section.

Installing emo (iOS)


emo delivers project template installer for Xcode. Start Terminal app and go to the directory of emo-framework that is created after unzipping the source archive, and execute "install-templates-Xcode4.sh". $ cd ~/Downloads/emo-framework-x.x $ ./install-templates-Xcode4.sh

Figure: Installing project template for Xcode 4

After installing project template for Xcode, run Xcode. The project template for emo-framework is installed if the project template installer succeeds. The project template for Xcode contains entire source codes of emo-framework and you can start developing games with emo-framework right now. You don't have to learn Objective-C and Apple's Foundation Framework when you use this project template.

13

Figure: project template of emo-framework

For your information, emo-framework for iOS is mostly written in Objetive-C by using Apple's Foundation Framework. If you're familiar with the Foundation Framework and Objective-C, you can easily fix up the framework to be fit with your needs. Now, you're ready to develop new game with emo-framework!

14

Examples for Android


emo-framewok contains a lot of examples that can be your first step. For Android, import Android-Examples directory into your workspace of Eclipse to try these examples. 1. Run Eclipse 2. Select "Import" from "File" menu 3. Select "General" and then select "Existing projects into your workspace"

Figure: Importing examples into your workspace

15

Choose 'Select root directory' and browse for the parent directory of the Android-Examples directory.

Figure: Select root directory of the projects to import

Check the 'copy projects into workspace' if you want to copy them to your workspace. (Normally you may need to check it.) Check the 'Android-Examples' directory and press 'Finish' button After importing Android-Examples into your workspace, you can run examples in the Android-Examples with Android simulator and/or the physical device. emo contains a lot of physical examples that can use with your physical projects.

16

Examples for iOS


The examples for iOS are placed under the iOS-Examples directory. These examples are just the Xcode project so you can run them with your Xcode. Just double-click iOS-Examples/iOS-Examples.xcodeproj to try these examples.

Figure: Running examples with Xcode

The script files are placed under the Resources group. It must be fun to edit and run them to see what is going on with Squirrel and emo-framework.

17

Creating new project for Android


Now is the time to proceed next! Import Android-Template project template to create new project with emo-framework. 1. Start your Eclipse 2. Select "File" menu and select "Import" 3. Select "General" and then select "Existing projects into your workspace"

Figure: Importing project template for Android

18

Choose 'Select root directory' and browse for the parent directory of the Android-Template directory.

Figure: Select root directory of the projects to import

Check the 'copy projects into workspace' if you would like to copy them to your workspace. (Normally you need to check it). Check the 'Android-Template' directory and press 'Finish' button.

19

Figure: Importing project template for Android

If you do not check "Copy projects into workspace", Android-Templates won't be copied into your workspace and the original source files are imported into your workspace (that means you will edit the template itself).

20

After importing templates into your workspace, edit the package name in the AndroidManifest.xml xml file to fit with your application package name. If you do not edit the package name "com.emo_framework.examples" is used for your app. (normally you won't be happy with it...)
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.emo_framework.examples" android:versionCode="1" android:versionName="1.0">

Figure: Eclipse project for emo

21

The main script file is assets/main.nut. Edit the main file to create your own game. emo::onLoad is the starting point of the application.

function emo::onLoad() { // print log message to the logcat print("It works!"); emo.Stage().load(Main()); } The print function prints messages to the console. On Android platform you can see console messages at logcat that can be seen by using DDMS.

Figure: Console messages on Eclipse

22

Creating new project for Xcode


If you develop games on iOS platform, you can use Xcode to develop emo games. emo is shipped with Xcode project template and you can start with the template. Run Xcode and Select "New" inside "File" menu, then select "New Project". If you have installed project template for emo-framework that was detailed in the previous section, you can start with the template. Select "emo-framework" inside the "iOS" tab and then select "An Application".

Figure: Choose a template for your new project

This project template for Xcode contains entire source codes to start creating games with emo-framework.

23

If you have created new project with the project template of emo-framework, you are ready to run emo application now. The main script is Resources/main.nut.

Figure: Running emo applications with Xcode.

You can see the console message in the console of Xcode if you have succeeded to run your first application that uses emo-framework,

24

Hello, World!
Now, it is time to create new games with emo! emo uses simple and intuitive object-oriented scripting language: Squirrel for your game logic. If you are familiar with modern scripting languages like JavaScript, C++, Java and so on, you can easily get used to it in a minute. Here is the "HelloWorld" script that runs on emo-framework. // prints "Hello, World" to the console print("Hello, World!"); How simple it is! :) Squirrel's syntax is much like JavaScript and programmers might be familiar with it. The print function displays messages to the console: logcat on Android and debug console on Xcode. As emo is event-driven framework, you can receive several events and status from the framework. For example, emo::onLoad will be called after the script file is loaded. // prints message after the script file is loaded. function emo::onLoad() { print("script is loaded!"); } As you can see, emo::onLoad is the starting point of emo-framework. The next thing you have to do is to create new stage and load it inside onLoad. The Stage is a very basic class like "scene" or "level" that is responsible for rendering of your game logic. Use emo.Stage to load the stage. It might be something like below. function emo::onLoad() { emo.Stage().load(YOUR_STAGE_CLASS_NAME()); }

25

The definition of the stage class is like below. class YOUR_STAGE_CLASS_NAME { function onLoad() { // Called when the stage is loaded } function onDispose() { // Called when the stage is disposed } } The next example shows how stages work. Level_1 class that prints messages at onLoad and onDispose will be loaded after the script is loaded. /* * Define Level_1 stage class */ class Level_1 { // Called when the stage is loaded function onLoad() { print("Level_1 is loaded!"); } // Called when the stage is disposed function onDispose() { print("Level_1 is disposed!"); } } // Load Level_1 after the script is loaded function emo::onLoad() { emo.Stage().load(Level_1()); } As you can see emo entirely uses object-oriented classes to build your game. The Stage has several callback events that are described in the later section.

26

Loading Sprites
After understanding how to create stage with emo, try to load a image to the screen. The images that are loaded to the screen are called 'sprites'. With emo, it is very easy to load sprites to the screen. /* * Define Level_1 stage class */ class Level_1 { sprite = null; // Called when the stage is loaded function onLoad() { print("Level_1 is loaded!"); // Create new sprite and load 'ball.png' sprite = emo.Sprite("ball.png"); sprite.load(); } // Called when the stage is disposed function onDispose() { sprite.remove(); // Remove the sprite print("Level_1 is disposed!"); } } // Load Level_1 stage function emo::onLoad() { emo.Stage().load(Level_1()); } This example loads "ball.png" when the stage is loaded and the sprite is displayed on the screen after loading is finished. The sprite is removed when the stage is unloaded at onDispose. The sprite image files are placed under "assets/graphics" directory for Android, and "Resource/graphics" directory for iOS.

27

Moving Sprites
In previous section we load one sprite into the screen. Now it's time to move the sprites around the screen. emo loads sprites at upper-left corner when no position is specified. This is because the upper left corner of the screen has coordinate of (0,0) and the x and y values increase as you move to the bottom right.

Figure: Upper-left corner has the coordinate of (0,0)

Note that the lower-right corner has coordinate of stage width and height. The actual stage size differs among individual devices. emo runs on a lot of different devices that have different screen density and when the device has larger resolution the screen size becomes larger. In most cases it is needed to move sprites at relative position against the screen. Use move method to move the sprite. The example below shows how to move a sprite at (100, 100). // Move sprite at X=100, Y=100 sprite.move(100, 100);

28

If you would like to move the sprite into the relative position to the screen, you have to take the screen width and height into account. The stage width can be retrieved via getWindowWidth and the stage height can be retrieved via getWindowHeight of the emo.Stage class. For example you can move the sprite into the center of the screen by calculating the screen size and the sprite size. // Move the sprite to center of the screen local stage = emo.Stage(); local x = (stage.getWindowWidth() - sprite.getWidth()) * 0.5; local y = (stage.getWindowHeight() - sprite.getHeight()) * 0.5; sprite.move(x, y); The 'stage' variable is the emo.Stage instance. The move method moves the sprite to the given position. The local coordinate system of the sprite is the same as the global coordinate system: the upper-left corner has the coordinate of (0, 0). The Sprite class also has moveCenter() method that moves center of the sprite at given coordinate. The example below shows how to move sprite to center of the screen using moveCenter method. // Move the sprite to center of the screen sprite.moveCenter(stage.getWindowWidth() * 0.5, stage.getWindowHeight() * 0.5); Moving sprites at your will must be very basic starting point of your game. Keep in mind that the sprite has the same local coordinate system that upper left corner has coordinates of (0,0) and bottom right corner has coordinates of (w, h).

29

Elements of the Game


emo consists of some simple elements that represents your game. emo has no "layers" nor "camera system".

Sprite
Sprite represents a rectangle area that contains single image texture. This is very basic element for your game. Sprite can be moved, scaled and rotated, etc. For example in shooter games, elements like player, enemies, weapons and bombs are all sprites. emo.Sprite class is the base class and the sub classes are like SpriteSheet, MapSprite, Line, and TextSprite.

Stage
Stage represents the stage like "scene" or "level" and responsible for rendering of your game logic. Only one stage can be handled by emo at a time, that is loaded via emo.Stage class.

Event
Event is callback function that tells status changes or important events of the game. Events are "stage is loaded", "screen is touched", "memory is low" and something like that.

30

Stage Events and Life Cycle


As the stage class is responsible for rendering of your game logic, stage receives status change events from the framework.

onLoad
Called when the stage is loaded. Initialize member of the stage and load them at onLoad.

onGainedFocus
Called when the application has gained focus. On devices that support multi-tasking, application can be gone to background process. onGainedFocus is also called when the background process returns to foreground.

onLostFocus
Called when the application has lost focus. On devices that support multi-tasking, onLostFocus is called when the application is gone to background.

onDrawFrame
Called when the framework draws the stage. The interval of this callback can be changed. This function is detailed in the later section.

onDispose
Called when the application finishes or current stage is disposed because the other stage is loaded. Release the stage resources in this callback.

31

Creating Stages
Now it's time to create new stages. The code below explains how to define multiple stages and how to load them. local stage = emo.Stage(); // Define Level_1 stage class class Level_1 { // Called when stage is loaded function onLoad() { print("Level_1 is loaded"); } // Called when stage is disposed function onDispose() { print("Level_1 is disposed"); } // When the user touches the screen, load Level_2 stage. function onMotionEvent(motionEvent) { if (motionEvent.getAction() == MOTION_EVENT_ACTION_DOWN) { print("Level_2 will be loaded"); stage.load(Level_2()); } } } // Define Level_2 stage class class Level_2 { function onLoad() { print("Level_2 is loaded"); } } // Load Level_1 after the script is loaded function emo::onLoad() { stage.load(Level_1()); } 32

The code above defines two stages and Level_1 stage loads Level_2 stage when user touches the screen. Now what happened when Level_2 is loaded? The load function of emo.Stage disposes current stage before it loads the next stage. On above example, the console messages are like below. Level_1 is loaded Level_2 will be loaded Level_1 is disposed Level_2 is loaded On emo application only one stage can be handled at one time. This is how stage transition works. The stage class has onDrawFrame callback that is called when the framework draws the stage. onDrawFrame callback is disabled by default. The interval of onDrawFrame callback can be changed via enableOnDrawCallback. The periodical logic can be written through this onDrawFrame callback. class Level_1 { // Called when the stage is loaded function onLoad() { // Enable onDrawFrame callback that is called on every 500 msec. emo.Event().enableOnDrawCallback(500); } function onDrawFrame(dt) { // Called on every 500 msec. dt is actual msec. } // Called when the stage is disposed function onDispose() { // Disable onDrawFrame callback emo.Event().disableOnDrawCallback(); } }

33

The periodical logic can be written via onDrawFrame. The example below shows how to write the periodical events: the sprite moves around eternally. class Level_1 { sprite = null; distantX = 2; distantY = 2; // Called when the stage is loaded function onLoad() { sprite = emo.Sprite("ball.png"); sprite.load(); // Enable onDrawFrame callback that is called on every 500 msec. emo.Event().enableOnDrawCallback(500); } function onDrawFrame(dt) { local x = sprite.getX() + distantX; local y = sprite.getY() + distantY; // Invert the sprite direction (X axis) if (x } // Invert the sprite direction(Y axis) if (y >= stage.getWindowHeight() || y <= 0) { distantY = -distantY; } sprite.move(x, y); } // Called when the stage is disposed function onDispose() { emo.Event().disableOnDrawCallback(); sprite.remove(); } } 34 >= stage.getWindowWidth()|| x <= 0) { distantX = -distantX;

Handling Motion Events


On smartphone games, it is important to handle motion events on the screen because most devices have very few buttons (i.e. iPhone has only one button). emo handles the motion events via onMotionEvent callback. The example below shows how to handle the motion event. It prints a message when user touches the screen. function onMotionEvent(ev) { if (ev.getAction() == MOTION_EVENT_ACTION_DOWN) { print("motion event action down"); } } On onMotionEvent you can retrieve some information from the argument. The example below shows how to get coordinates from the event. It moves the sprite at the position of the motion event. function onMotionEvent(ev) { if (ev.getAction() == MOTION_EVENT_ACTION_DOWN) { // Moves the sprite at the position of motion event sprite.moveCenter(ev.getX(), ev.getY()); } } Multi-touch is also supported. The pointer-id represents individual pointers. function onMotionEvent(ev) { if (ev.getAction() == MOTION_EVENT_ACTION_DOWN) { print(format("pointer id = %d", ev.getPointerId())); } } With the source distribution emo delivers several examples like drag and multi-touch. Refer to these examples for more information. 35

Handling Sprites
The Sprite class is the very basic element of the game and you can apply several effects to the sprite.

Rotation
Sprite can be rotated. The rotation angle follows clockwise direction. Sprite rotates against center of the Sprite by default but any local coordinates can be set. // Rotates the Sprite at 30 degree. sprite.rotate(30);

Scaling
Sprite can be scaled. The scaling factor can be set for each individual X axis and Y axis. The width and height of the sprite are not changed even when you scale the sprite. Use getScaledWidth and getScaledHeight to retrieve the width and height of the scaled sprite. // Scale down the sprite sprite.scale(0.5, 0.5);

Transparency
The transparency of the sprite can be changed. The alpha takes value from 0 to 1. alpha=0 means full transparency. alpha=0.5 means half-translucent. // Make the sprite half-translucent sprite.alpha(0.5); The Sprite class has a lot of functions other than the functions detailed in this section. See http://www.emo-framework.com/APISprite.html for details.

36

Collision Detection
Collision detection is a basic element of your the game. For example the shooter game consists of a set of collision detections: player, enemies, bullet and bombs. The Sprite class has basic collision detection functions.

contains
Sprite#contains checks whether the given coordinate is inside the sprite. It returns true if the coordinate is inside the sprite. // Check if the coordinate (X=100, Y=100) is inside the sprite if (sprite.contains(100, 100)) { print("contains!"); }

collidesWith
Sprite#collidesWith checks whether the sprite collides with the other sprite. It returns true if the sprite collides with the other sprite. // Does the sprite collides with the other sprite? if (sprite.collidesWith(otherSprite)) { print("collides!"); } Sprite#contains and Sprite#collidesWith assumes that the sprite is a rectangle. It does not take rotation and scaling into account. emo has basic collision detection functions and in most cases developers should override them to fit with the individual needs. Create new subclass of the sprite and override contains and collidesWith to rewrite the collision detections. Or, you can simply create new function that provides complex collision detections.

37

Animation of the Sprite


SpriteSheet is a subclass of the Sprite and it has ability to animating textures. SpriteSheet is of a texture that contains multiple image frames. The example below shows a dog sprite sheet that contains 10 frames.

Figure: Sprite sheet

In this case if the first frame and second frame are switched one another in short period of time, it seems the dog is walking to the right. It is easy to implement such animation on emo. local dogSprite = emo.SpriteSheet("dog.png", 34, 42, 1, 1); The example above creates a sprite with width equals 34, height equals 42, border equals 1 and margin equals 1. The border is the border between each frame. Use animate method to animate these frames. The example below shows animation from frame 0 to frame 1 at each 500 milliseconds. // Animate the dog like walking toward right dogSprite.animate(0, 2, 500, 3);

38

Figure: Frame index of the sprite sheet

The frame index starts from 0 like above. If you animate this sprite sheet from index 0 to 1, you can see the dog animating like walking toward right. If you animate this sprite sheet from index 5 to 6, you can see the dog animating like walking toward left. // Animate the dog like walking toward left dogSprite.animate(5, 2, 500, 3); SpriteSheet#animate animates the sprite sheet but the position of the sprite won't be changed. If you would like to animate and move the sprite you have to move the sprite by yourself or you have to move the background. Use stop method to stop the animation. // Stop the animation dogSprite.stop(); In previous examples we just use the first parameter of animate method as frame index. SpriteSheet#animate also supports multiple frame index as an array. The example below shows how to use frame index as an array. // Animate the dog like walking toward right dogSprite.animate([0, 1], null, 500, 3); // Animate the dog like walking toward left dogSprite.animate([5, 6], null, 500, 3); Looks like more intuitive? The first parameter of animate can be an array that represents the frame indices. If you use first parameter as an array, the second parameter is ignored because the second parameter is redundant.

39

SpriteSheet is used for not only animating the sprite but also showing a selected frame. For example if you would like to make the dog faced toward right side, set frame index to 0. At the same time if you would like to make the dog faced toward left side, set frame index to 5.

Figure: Frame index of the sprite sheet

// Face the dog toward right dogSprite.setFrame(0); // Face the dog toward left dogSprite.setFrame(5); For your information, you can also use Sprite#setFrame to animate the sprite. In periodical operation like onDrawFrame you can change the frame index of the sprite progressively that makes your sprite animating. // Changing frame index manually local index = 0; function onDrawFrame(dt) { if (dogSprite.getFrameCount() <= index) { index = 0; } dogSprite.setFrame(index); index++; } Implementing sprite sheet animation manually makes complex animation comes true.

40

Packing Sprites
In previous sections we use tiled sprite sheets that consists of images with same region. By using texture packing tool like TexturePacker (http://www.texturepacker.com/), we can pack images with different region into one sprite atlas.

Figure: A sprite atlas

emo can read sprite atlas definition file made with texture packing tool like TexturePacker. Currently Sparrow and CEGUI/OGRE data file format is supported.

Figure: TexturePacker (http://www.texturepacker.com/)

41

TexturePacker is handy tool that runs on Windows, Mac and Linux. Although it delivers PRO version for a price, you can still use its basic functions of TexturePacker at no charge. The sprite atlas definition XML file is like below.
<?xml version="1.0" encoding="UTF-8"?> <TextureAtlas imagePath="my_atlas.png"> <SubTexture name="A" x="0" y="0" width="64" height="64"/> <SubTexture name="B" x="0" y="64" width="64" height="64"/> <SubTexture name="ball" x="98" y="80" width="29" height="29"/> <SubTexture name="block" x="64" y="50" width="34" height="34"/> <SubTexture name="gear" x="98" y="50" width="30" height="30"/> <SubTexture name="tv" x="64" y="0" width="53" height="50"/> </TextureAtlas>

You can create sprite sheet instance from the sprite atlas definition file like below. local myAtlas = emo.SpriteSheet("my_atlas.xml"); You can call animate and setFrame and so on to operate your SpriteSheet because this is just a normal SpriteSheet instance. In addition to that, you can select your sprite by frame name. myAtlas.selectFrame("ball"); Since sprite sheet saves the resource of the device, try to use sprite sheet as much as possible. Sprite sheet saves memory resource and texture switching overhead even if the sprite is not an animation sprite but a static sprite.

42

Using Unicode and TrueType


Even though emo runs on various devices, currently only ASCII text can be used for your script text. Multilingual developers can use Unicode text through the strings xml file that defines Unicode strings. Those properties are used from emo.FontSprite class that has an ability to render the Unicode strings and TrueType fonts.

Figure: Definition of Unicode strings (Android)

For Android platform, the strings file is placed under res/values/strings.xml. For iOS platform it is placed under Resources/strings.plist. If you use Xcode you can easily edit plist file by using the property editor. The strings xml file is written in Unicode so you can mix multilingual texts into the property file.

Figure: Definition of Unicode strings (iOS)

43

emo.FontSprite class uses the Unicode strings text that is defined in the strings xml file. The strings can contain multiple placeholder string like "%s". // "Hello, %s!" goes to "Hello, World!" local fontSprite = emo.FontSprite("hello ", 30); fontSprite.setParam("World"); Note that only ASCII code can be used for your parameter text because only ASCII text can be used in your script text still. placeholders. // At most 6 parameters can be set for your placeholders // e.g. "Hello, %s, %s, %s, %s, %s, %s" fontSprite.setParam("World", "2", "3", "4", "5", "6"); TrueType fonts are also available for the FontSprite. The TrueType fonts should be placed under assets directory for Android platform, and Resources directory for iOS platform. local ttfSprite = emo.FontSprite("hello", 30, "YourTTF"); At most 6 parameters can be used for your

Figure: Unicode strings and TrueType font

44

As FontSprite is just a subclass of Sprite, you can apply same operation to your FontSprite like Sprite instance. // Load the sprite and change its color to red fontSprite.load(); fontSprite.color(1, 0, 0, 1); // Operate FontSprite like Sprite fontSprite.move(100, 100); fontSprite.rotate(30); fontSprite.alpha(0.5); After loading instance from the strings, you can change the text of the FontSprite by using reload. The changes to FontSprite will be applied after calling reload. For example, you can change the parameters and reload your FontSprite. // "Hello, %s" goes to "Hello, Font!" fontSprite.setParam("Font"); fontSprite.reload(); FontSprite#reload accepts a parameter for the strings property key and you can use this parameter to change the sprite text. // Reload FontSprite with given key fontSprite.reload("hello_ja"); Althogh FontSprite class seems like a convenient class rather than TextSprite, it always re-creates text textures at reloading sprite. Reloading font sprite in your game loop might make your game slow because reloading font sprite costs. Consider using TextSprite when you use text sprite in your game loop.

45

The Motion Tweens


emo supports special animation effect that is used by Flash and Silverlight which is called "motion tweens" and "easing". By using motion tweens you can create complex animations easily. First of all, guess how to move your sprite from coordinate (0, 0) to (100, 100) in 5 seconds. As we discuss in the previous sections, with the periodical operation like onDrawFrame you can make this come true. By using periodical operation like onDrawFrame, you have to calculate the interval seconds and the distance from starting point and move the sprite by yourself. But what if you would like to move the sprite accelerated instead of linear moving? What if you would like to apply "Back In" or "Bounce In" effect? With easing you can easily implement such complex animations. // Move the sprite from (0, 0) to (100, 100) in 5 seconds with linear moving local modifier = emo.MoveModifier( [0, 0], [100, 100], // from (0,0) to (100,100) // in 5 seconds with linear 5000, emo.easing.Linear); sprite.addModifier(modifier); How about that? emo calls such motion tween as "Modifier". MoveModifier makes your sprite moving. All you have to do is setting the starting point and the destination point, effect interval and linear easing. Easing is a kind of formula expression that knows how to increment or decrement values. Linear easing increases values linearly. Now you can accelerate your sprite. As you can see, only easing should be updated. // Move the sprite from (0, 0) to (100, 100) in 5 seconds with accelerated moving local modifier = emo.MoveModifier( [0, 0], [100, 100], // from (0,0) to (100,100) // in 5 seconds with acceleration 5000, emo.easing.CubicIn); sprite.addModifier(modifier); This example uses CubicIn easing that accelerates the sprite. As you can see it is easy to implement complex motions when you use motion tween and easing. 46

For more information, the documentation of Flash and Silverlight explains much about tweens and easing. Refer to the documentations below. l l http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:actions_ease http://msdn.microsoft.com/en-us/library/cc189019%28VS.96%29.aspx#easing_functi ons Multiple modifiers can be added to the sprite. For example you can add rotation effect to the previous example. // Move the sprite from (0, 0) to (100, 100) in 5 seconds with rotation local moveModifier = emo.MoveModifier( [0, 0], [100, 100], // from (0, 0) to (100, 100) 5000, emo.easing.Linear); local rotateModifier = emo.RotateModifier( 0, 360, 5000, // rotate 360 degree in 5 seconds emo.easing.Linear); sprite.addModifier(moveModifier); sprite.addModifier(rotateModifier); // add motion effect // add rotation effect

In shooter games most all motions of enemies and bullets can be represented using Modifiers. The expression of Modifiers can be reused so you can move a lot of sprites with single logic. The modifier can be applied to the stage transition that is detailed in the later section. There are a much more Modifiers in emo framework other than MoveModifier and RotateModifier. Refer to http://www.emo-framework.com/APIModifier.html for details.

47

Using Controllers
In previous articles we moves the sprites as our will. Now it's time to move them by your fingers! Most of all games on smartphone use the on-screen direction controller pad that is called "on-screen controller", "Joystick", "Joypad" or "D-PAD" that enables to control your characters by your fingers.

Figure: On-screen direction controller and buttons

emo is shipped with the handy on-screen controller. emo has an analog controller that can be moved freely and a digital controller that can be moved to the four direction like Nintendo entertainment system. It is very easy to use these controllers as it is treated like normal sprites. The on-screen controllers are subclass of the Sprite so just load and move them to use the on-screen controller. // Load the analog joystick controller controller = emo.AnalogOnScreenController( "control_base.png", "control_knob.png"); // Move the controller to the front controller.setZ(99); controller.load();

48

Make sure that you have to keep in mind the z order of the sprite. You have to move the controller in front of the other sprites otherwise controller disappears from the stage. Use setZ to change z order. You can use the controller images that are delivered with the examples of the framework like below. Of course you can use your controller images. The images of controller consist of the base image and the stick image like below. Only stick image follows your fingers.

Figure: Images of on-screen controller

After adding and loading on-screen controller, it's time to receive events from the controller. Override onControllerEvent to receive the event from the controller like below. // Receive events from the on-screen controllers
function onControlEvent(controller, controlX, controlY, hasChanged) {

// Do somothing important
}

On control event callback, controlX and controlY takes value from -100 to 100. These values are distance from the center of the controller that can be used to move your sprites. onControllerEvent occurs constantly while user touches the on-screen controller. The boolean flag of hasChanged means whether the values are changed or not. When user releases fingers from the screen, controlX and controlY become 0 because 0 is the neutral position. Use first parameter to determine what controller sends this event when you place multiple controllers on the screen.

49

For example the code below shows how to receive value from controller event and how to move the sprite. Note that this example does not contain screen boundary check and the sprite can be moved outside of the screen. // Receive events from the on-screen controllers
function onControlEvent(controller, controlX, controlY, hasChanged) {

// Move the sprite, max value takes 10


sprite.move(sprite.getX() + controlX / 10, sprite.getY() + controlY / 10); }

Use controller#getDirection to detect the direction of the joystick. This function only detects up/down and left/right but it might be handy for changing frame index of your sprite sheet. // Receive events from the on-screen controllers function onControlEvent(controller, controlX, controlY, hasChanged) { // Move the sprite, max value takes 10 sprite.move(sprite.getX() + controlX / 10, sprite.getY() + controlY / 10); // Change the frame index of the sprite if (hasChanged) { local direction = controller.getDirection(); if (direction == CONTROL_LEFT) { sprite.setFrame(0); // Set frame index to 0 } else if (direction == CONTROL_RIGHT) { sprite.setFrame(1); // Set frame index to 1 } else if (direction == CONTROL_UP) { sprite.setFrame(2); // Set frame index to 2 } else if (direction == CONTROL_DOWN) { sprite.setFrame(3); // Set frame index to 3 } } } 50

Using Sensor Event


Today most of all smartphone including iPhone and Android have some kind of sensor like accelerometer. It must be fun if your game supports accelerometer sensor that makes your game more interactive. emo handles these sensors as sensor event. The basic program flow that supports sensor event is like below. First of all we need to register the sensor to declare the sensor type. Then enable the sensor when application is gained focus. While the sensor is enabled sensor event occurs constantly. Disable the sensor when the sensor is no longer used otherwise the resource of the device like battery will be consumed. local event = emo.Event(); class Level_1 { // Register sensor when loaded function onLoad() { event.registerSensors(SENSOR_TYPE_ACCELEROMETER); } // Enable sensor at interval of 100 msec function onGainedFocus() { event.enableSensor(SENSOR_TYPE_ACCELEROMETER, 100); } // Disable sensor when application lost focus function onLostFocus() { event.disableSensor(SENSOR_TYPE_ACCELEROMETER); } // Receive sensor event function onSensorEvent(sevent) { if (sevent.getType() == SENSOR_TYPE_ACCELEROMETER) { // Do something important } } }

51

Currently only accelerometer sensor is supported for Android and iOS with emo. The following code shows how to receive events from the sensor. // Receive sensor event function onSensorEvent(sevent) { if (sevent.getType() == SENSOR_TYPE_ACCELEROMETER) { // Print values from accelerometer print(format("x=%f, y=%f, z=%f", sevent.getAccelerationX(), sevent.getAccelerationY(), sevent.getAccelerationZ() )); } } Use getAccelerationX, getAccelerationY, getAccelerationZ to receive values from the accelerometer sensor. The interval of this event can be changed when you update the interval parameter of enableSensor. Note that the sensor consumes resources of the device so use them as less as you can. By using sensors you can make your game more interesting. The following pages contain a lot of ideas about sensors so check them out. l l http://rikravado.hubpages.com/hub/10-Best-Accelerometer-Apps http://www.creativeapplications.net/iphone/10-creative-ways-to-use-the-accelerome ter-iphone/

52

Using Audio
emo supports sound features such as sound effects and background music. The framework has emo.Audio class that is responsible for audio processing. emo supports multiple audio channels where emo.AudioChannnel comes in. The example below shows how to create audio manager that has three audio channels. // Create new audio manager that has three audio channels local audio = emo.Audio(3); // Create audio channels local audioCh0 = audio.createChannel(0); local audioCh1 = audio.createChannel(1); local audioCh2 = audio.createChannel(2); You can handle audios through the channels. The supported audio format is wav(.wav) for Android, and aiff(.afi, .aiff), caf(.caf), mpeg-1 to 4(.mp1, mp2, .mp3, .acc, .m4a, .mp4), wav(.wav), 3gpp(.3gp), 3gp2(.3g2) etc for iOS platform. The audio files are placed under "assets/sounds" for Android, "Resouces/sounds" for iOS. // Load bang.wav sound file audioCh0.load("bang.wav"); audioCh0.play(); audioCh0.pause(); audioCh0.stop(); // play audio // pause audio // stop audio

The sound file that is associated with a channel can be changed. You don't have to stop or close audio channel before reloading new audio. // Reload another sound audioCh0.load("explosion.wav");

53

The AudioChannel supports not only short sound effects but also long background music. Note that the background music should be paused or stopped when the application has lost focus otherwise the sound will not be stopped. // Play audio when app gets focus function onGainedFocus() { audioCh0.play(); } // Pause audio when app lost focus function onLostFocus() { audioCh0.pause(); } Close the audio channel when the channel is no longer used. // Close audio when disposed function onDispose() { audioCh0.close(); } You can create multiple audio channels and they can be played in parallel. Note that the loading audio consumes memory resources and it depends on the device how many channels can be handled at a time.

54

Saving and Loading Data


Saving and loading game data must be a key function for your game. emo provides a easy way to handle data storage with Preference class. The Preference class acts as key-value storage. For instance "Level" is a key and "1" is a value. Below example shows a typical usage of the Preference. // Create Preference instance local preference = emo.Preference(); local level = 0; // Load the game data if (preference.openOrCreate() == EMO_NO_ERROR) { local value = preference.get("Current_Level"); if (value.len() > 0) { level = value.tointeger(); } preference.close(); } // Save the game data if (preference.openOrCreate() == EMO_NO_ERROR) { preference.set("Current_Level", level); preference.close(); Preference class should be opened before getting values from it and should be closed when the Preference is no longer used. Use openOrCreate to open the database that will be newly created if the database does not exist. Use open to only open the database. Note that the value that you can retrieve from Preference is just a 'string' value. If you would like to handle the value as integer, you have to convert it to integer by yourself. If the value is not found for the given key, the empty string returns. You can check whether the return value is empty or not to detect the value associated with the key is not found. 55

Use del method to delete the value associate with the key. // Delete the game data if (preference.openOrCreate() == EMO_NO_ERROR) { preference.del("Current_Level"); preference.close(); Use keys to retrieve the list of the key in Preference. // Retrieve the list of the key in Preference. if (preference.openOrCreate() == EMO_NO_ERROR) { local keys = preference.keys(); for (local i = 0; i < keys.len(); i++) { local key = keys[i]; local value = preference.get(key); } preference.close(); As you can see the database function in emo is very simple and easy to use. For more information about api and sample codes, refer to following links. l l http://www.emo-framework.com/APIPreference.html http://www.emo-framework.com/APIDatabase.html

56

The Scene Transition


The modifier that is detailed in the previous section can be used to not only for sprites but also for the stages. The effect to the stage is called "Scene Transitions" that animates the scenes. The example below shows how to move out the current stage when you click the screen. As you can see the Modifier can be applied to the stage transition. // Load next stage when you click the screen function onMotionEvent(mevent) { if (mevent.getAction() == MOTION_EVENT_ACTION_DOWN) { // Load next stage after the current stage move out with animation local currentSceneModifier = emo.MoveModifier( [0, 0], [0, stage.getWindowHeight()], 2000, emo.easing.BackIn); stage.load(SceneB(), currentSceneModifier); } } The second parameter of the Stage#load is the Modifier. MoveModifier moves the stage. In this example the stage moves out from the screen in 2 seconds with BackIn animation. The example below shows how to load the next stage before animating current stage. The forth parameter of load is the flag that indicates whether loading next stage immediately or not. // Move out current stage after loading the next stage. local currentSceneModifier = emo.MoveModifier( [0, 0], [0, stage.getWindowHeight()], 2000, emo.easing.BackIn); stage.load(SceneB(), currentSceneModifier, null, true);

57

When the forth parameter of the load is true, the next stage is loaded before the current scene animation starts. As you can see below the right image shows how it works: the next stage that has blue background is loaded when the current red stage animation starts. If the forth parameter is not true the background of the current red stage animation kept blank (the image by the left side).

Figure: The difference between stage transition

Note that not only current stage but also the next stage can be animated. The third parameter of the load is the modifier that will be applied to the next scene. The third parameter of load should be null if the next stage never animates. Modifier is the basic elements that add ability to animate your sprite and stage. The examples that shipped with source distribution use some modifiers so please check them out.

58

Supporting Multiple Devices


emo-framework runs on a lot of devices including iPhone, iPad, iPod touch and various Android devices. A variety of Android devices that have different spec are distributed in many countries. You have to take care of the difference across these devices especially against screen density and performance.

The Screen Density


emo runs on the devices that have difference screen densities. For example iPhone 4G has retina display that is a twice bigger than iPhoone 3G. In addition to that on Android devices the aspect rate varies across the devices. You have to take care of them if you would like to offer a same user experience in your games. emo has scaling function that scales stage size in order to provide similar images in different screen density. The example below shows how to scale your stage that is based on 320 pixel. stage.setContentScale(stage.getWindowWidth() / 320.0); In this example nothing is happened when the stage width equals 320. When the stage size equals 640 the scale equals 2 that makes the stage size by half. This example shows how to display similar images across retina and non-retina devices for iPhone. It is important to take care of the desired stage size if you use setContentScale. Changing sprite image texure against the screen size is also available. For example you can choose the bigger image when the device has bigger display. if (stage.getWindowWidth() > 320) filename = "blocks-hd.png"; Supporting a variety of devices must be the source of concern but it must be fun to get the most of them.

59

Difference in Performance
Today the performance of the devices have been improving so fast, you have to take care of the difference in performance among the devices. Let your game bring similar user experience in any devices as much as possible. The difference in performance can be measured by calculating FPS (frame per second). function onLoad() { // calculate fps on every 5 seconds emo.Event().enableOnFpsCallback(5000); } // display fps on console function onFps(fps) { print(format("FPS: %4.2f", fps)); } enableOnFpsCallback enables onFps callback. FPS is a short for Frame Per Second, and it shows how many times the frame is drawn to the screen in one second. Most of commercial games that renders smoothly runs on 60 fps or 30 fps, and the retro classical game like Nintendo entertainment system takes fps around 15. Too few fps gives negative impact to user experience. The interval of drawing can be changed. The code below shows how to change your fps about 30. // Change interval of the draw (milliseconds) emo.Stage.interval(33); The Stage interval is the wait time between draw. This means that the actual interval between draw varies because of the processing time to draw the stage and actual load usage of the device.

60

For More Information


If you have any suggestions and/or questions about emo-framework, please join the discussion forum of emo-framework: http://groups.google.com/group/emo-discuss. If you have found any issues about emo, please post new issue to the Google Code project page with the working code attached: http://code.google.com/p/emo-framework/issues/list. Have fun! Kota Iguchi: twitter: @infosia

61

62

You might also like