The dreaded “no new content” post

Well, it finally happened. Other obligations have kept me from writing so unfortunately this iDevBlogADay post will not have any new content, but I’d still like to take this chance to bring to light some older posts (from before iDevBlogADay) which contain useful code snippets:

Hope these are useful, and I’ll make sure to have some fresh spanking-new content for when our next turn comes up :)

What about GitHub?

On the last post I promised to have all of the sample code offered here up on our GitHub, but unfortunately I had no time to do that either. It should be there by the end of this week, if all goes well!

What’s cooking

Besides working on The Project, right now we are also putting the finishing touches on pretty big updates for Litho and Arte, so if you are interested in any of these products keep an eye on this blog and we’ll let you know as soon as the updates go live.

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two new posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

Posted in News, Programming | Tagged | Leave a comment

Java-style servlets in Obj-C using Mongoose Server

Continuing the series of code snippets, in this post I’ll introduce a wrapper class for the Mongoose web server which tries to emulate the concept of Servlets, common to Java developers. While this code was not written with our games in mind, I’ll point out later some creative ways you can use this in your games (and which I intend to use in our own games as well :P ). Since most of the code is just wrapping Mongoose functionality, in this post I’ll focus on the usage of the classes instead of the implementation details. Also note that while the sample project is aimed towards iOS devices, you should be able to use this wrapper in any Objective-C project.

Just what is a Servlet?

In the Java world, a Servlet is a class responsible for receiving HTTP requests through an URI mapped in the server and providing a response to the client. The class should implement a method for each HTTP method it intends to support (GET, POST, PUT, DELETE), where each one receives a Request object with all the details of the request (URI, parameters, etc.), and a Response object, which should be used to set all the attributes to be sent to the client (status code, headers, the response body itself, etc.). These servlets are then deployed to a servlet container (Apache Tomcat is a pretty popular one), which is responsible for receiving the requests and routing them to the appropriate servlets for processing. If you want to know more about Java servlets, check out the documentation on the Oracle website.

Cocoa Servlets

To create a similar scenario, in our code the wrapper around the Mongoose Server will act as the servlet container. We’ll then create Servlet implementations (by inheriting from the Servlet class) and map them to specific URI paths. All this is achieved using these 4 classes:

  • Servlet – an “abstract” class from which all servlets must inherit. Contains some utility methods for creating responses to the typical error situations (404, 500, etc.). There are 4 methods which should be overriden as necessary (doGet, doPost, doPut, doDelete), where each receives a ServletRequest object and must return a ServletResponse object.
  • ServletRequest – a class to represent all attributes of a HTTP request. It contains the path (URI) of the request, all the headers and parameters in easy-to-use NSDictionary form, and the request body wrapped in a NSData object. If needed, you can also access the underlying request structure from Mongoose for lower level interaction.
  • ServletResponse – contains all the attributes required to build a HTTP response, such as the statusCode (200 OK, 404 Not Found, etc.), the headers(Content-Type, Content-Length, etc.) and the response body itself. If you prefer, you can also tailor the response yourself by using the customResponse property. Instances of this class should be created and returned by the servlet methods.
  • MongooseServer – this is the class that brings it all together. When creating the server, you define the port it should listen on and if directory listing is enabled (if it is, the directory tree inside the app can be browsed by the client). For more control, the server can also be created by passing an array of Mongoose options. Once created, you map Servlets to their respective URI paths by using the addServlet:forPath method.

To illustrate, here is a sample servlet:

@implementation HelloWorldServlet

- (ServletResponse *)doGet:(ServletRequest *)request {

    NSString *name = [request.parameters valueForKey:@"name"];

    ServletResponse *response = [[[ServletResponse alloc] init] autorelease];
    response.statusCode = @"200 OK";

    NSString *strBody = [NSString stringWithFormat:@"<html>Hello %@, how are you?</html>", name];
    response.bodyString = strBody;
    [response addHeader:@"Content-Type" withValue:@"text/html"];

    return response;
}

- (ServletResponse *)doPost:(ServletRequest *)request {
    return [self doGet:request];
}
@end

You then create the server and map the servlet to an URI:

server = [[MongooseServer alloc] initWithPort:8080 allowDirectoryListing:YES];

HelloWorldServlet *servlet = [[HelloWorldServlet alloc] init];
[server addServlet:servlet forPath:@"/helloWorld"];
[servlet release];

That is all! The server will respond to requests like http://[server]:8080/helloWorld?name=Crocodella.

OK, now where do I use that?

There are many clever ways you can benefit from having a HTTP server running inside your app or game. You can inspect your game entities at runtime (this #AltDevBlogaDay post talks about this approach), interact with your scripting engine for tweaking or even upload assets on the fly. Get creative :)

The code

The project includes both the wrapper code and a sample app which provides three servlet implementations: the Hello World servlet shown above, an Image Servlet which responds with a PNG image (but could be used to return any binary content) and an Upload Servlet illustrating how you can upload files to the server. Feel free to use this code in your own projects as you like.

OK, where do you get the code? Well, this posts also marks the inauguration of our own GitHub repository! You can see this project here, and in the following days I intend to upload all the code that has been published here in the last few weeks. Enjoy :)

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two new posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

Posted in Programming | Tagged , , | 5 Comments

Positional audio with cocos2d and CocosDenshion

If you are creating a game project using the cocos2d XCode project template, there’s little reason not to use CocosDenshion for your audio needs. It’s already there, requires minimal configuration, it’s easy to use and it allows you to go as low-level as you need. One thing that CocosDenshion does not provide out of the box however is support for positional audio. Actually, the underlying audio API OpenAL does support full 3D audio, and you could get direct access to the API through CocosDenshion to take advantage of it, but for a 2D game this can be a major overkill. Positional audio can be simulated in 2D scenarios by simply manipulating the pan and gain of a sound source in relation to a listener, and that’s exactly what we’ll do in this piece of code that I’m about to share.

Where is this I hear?

The term itself is pretty self-explanatory, in that positional audio is the simulation of the ability that we humans have to judge the approximate distance and direction of a sound source, and also the physical properties of sound based on the environment. This effect is much better represented in surround sound systems with dedicated hardware but it can be “faked” in stereo systems using much simpler tricks.

CDXAudioNode

In keeping with the naming convention used in the CocosDenshion project, for our class we’ll use the CDX prefix to indicate that it depends on cocos2d (even though CocosDenshion comes with the cocos2d package, it’s entirely independent). We’ll be subverting the cocos2d API a little bit in order to use a CCNode to represent a sound source in our scene. This provides many advantages to us, such as adding the audio node as the child of a sprite, or even animating a sound source’s position using a CCAction, and you can also provide another CCNode to act as the listener position of a sound source (if none is provided, the default is the center of the screen). Another feature of the CDXAudioNode is to set a loop mode, including a “periodic” loop which can be very useful for ambient audio. We’ll see all of this in detail below.

/**
 Initializes the audio node with an already created sound buffer, identified by
 the sourceId.
 */
- (id)initWithSoundEngine:(CDSoundEngine *)se sourceId:(int)sId;

/**
 Initializes the audio node with an audio file, creating a sound buffer with the
 specified sourceId.
 */
- (id)initWithFile:(NSString *)file soundEngine:(CDSoundEngine *)se sourceId:(int)sId;

There are two ways to create a CDXAudioNode: you can either load the audio buffers yourself and just provide the source ID, or you can have the node load it’s own audio buffer by providing a file name. The former is useful in cases where you’re loading the audio buffers asynchronously or want to have more control over the loading process. Both of these constructors depend on having a CDSoundEngine already created and properly initialized.

- (void)visit {
    CGPoint realPos = [self convertToWorldSpace:CGPointZero];

    CGSize size = [[CCDirector sharedDirector] winSize];

    CGPoint earPos = ccp(size.width / 2, size.height / 2);
    if (earNode) {
        earPos = [earNode convertToWorldSpace:CGPointZero];
    }

    float dist = sqrt((realPos.x - earPos.x) * (realPos.x - earPos.x) + (realPos.y - earPos.y) * (realPos.y - earPos.y));

    float distX = realPos.x - earPos.x;

    sound.pan = distX / (size.width / 2);

    float gain = 1.0f - (dist * attenuation);

    if (gain < 0.0f) gain = 0.0f;     if (gain > 1.0f) gain = 1.0f;

    sound.gain = gain;

    [super visit];
}

All the magic happens in the visit method. This method is usually called every frame to perform drawing operations in a CCNode, but in this case we are hijacking it to calculate the distance between the ear node (or the center of the screen if it was not defined) and the sound source and then applying the necessary changes to the audio parameters.

Usage

// Sound initialization

[CDSoundEngine setMixerSampleRate:CD_SAMPLE_RATE_MID];
[CDAudioManager initAsynchronously:kAMM_FxPlusMusicIfNoOtherAudio];

// Waits for initialization (BAD way to do it, used here for simplicity's sake!)
while ([CDAudioManager sharedManagerState] != kAMStateInitialised) {}

am = [CDAudioManager sharedManager];
soundEngine = [CDAudioManager sharedManager].soundEngine;

...

CDXAudioNode *audioNode = [CDXAudioNode audioNodeWithFile:@"808_120bpm.caf" soundEngine:soundEngine sourceId:1];
audioNode.earNode = earSprite;
audioNode.playMode = kAudioNodeLoop;
[audioNode play];

After initializing the sound engine, you create your CDXAudioNode using one of the constructors mentioned before. Then you can define a listener using the earNode property and also set the play mode, which can have one of the following values:

  • kAudioNodeSinglePlay – the sound will be played once the play method is called.
  • kAudioNodeLoop – the sound will loop indefinitely, until the pause or stop methods are called.
  • kAudioNodePeriodicLoop – in this mode, the sound will play again every x seconds, where x is a random number between minLoopFrequency and maxLoopFrequency.

You can also play around with the attenuation property, which influences the maximum distance the sound source can be heard from.

Sample project

EDIT: the code is now available on GitHub

You can download a sample project containing all the code here.

In this sample project, there are 4 sprites which you can drag around, where one is the listener node and the others are sound sources illustrating each of the loop modes available. The code can probably be much inproved, so feel free to use it in your own projects or improve it as needed :)

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two new posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

Posted in Programming | Tagged , , | 6 Comments

Leveraging cocos2d actions for cutscenes

Hello iDevBlogADay

This is our first post in iDevBlogADay (thanks @mysterycoconut for all your hard work!), but I’ll not waste your time with lengthy introductions. If you want to know more about Crocodella Software, take a look at the 1-year anniversary post as it sums up quite nicely what we’ve been up to. I tend to prefer writing about technical subjects, so you can expect to see more posts like that in the future. Also, take a look at our older posts, there are some code snippets you may find useful. Enjoy! :)

Tell me a story

There’s much debate about the use of non-interactive scenes in games. Some people think they are a great aid in creating a cinematic feel (Metal Gear Solid series, Xenosaga), while others feel that they break the immersion and prefer to tell the story in-game through the use of dialogue and props (Half-Life). I tend to side more with the first group, even though I enjoy games using both approaches (or any mix in-between) as long as they’re good. Most games however require at least some form of presenting content that does not require direct interaction to the player, be it a tutorial or story scene.

As I’ve mentioned before, we are working on an old-style 2D top-down JRPG for the iPad (more on it soon!), and in this genre cutscenes are essential in moving the story forward. Therefore, we have been thinking of ways of creating these scenes with as little work from the programmer/designer as possible, while also allowing rapid modification and testing for quick iteration. And as always, cocos2d comes to the rescue!

Ready, set, CCAction!

Flash is the tool of choice for most animators, with its keyframe-based timeline aiding in the creation of complex sequences without having to draw each frame. We decided to build an editor tool with a similar approach, where the key points are:

  • Each object in a scene (sprite, camera, background) is represented by an entity
  • Each entity has its own timeline, with one or more keyframes.
  • A keyframe defines a state in time of an entity’s properties
  • Frames in-between keyframes are generated by tweening (interpolating) these properties
  • The editor should run on the device itself, to allow testing in a real environment

One of the most powerful features of the cocos2d engine is the action mechanism. With it, interpolating between values is very easy, and thus actions play a great part in our scene editor. Also note that any mechanism which allows tweening of graphic properties could be used, like UIView animations for instance.

The editor

The almighty scene editor! Also this is the game's first official screenshot :)

As mentioned, each object in the scene is described by an entity. Entities have a name, Z-Index (for depth ordering), any other parameters necessary for that specific entity (such as the image file for a sprite) and a timeline, which is nothing more than a NSArray containing keyframe objects. Each keyframe has a time in seconds at which it occurs and a list of the values for all the entity’s properties in that instant, such as position, scale, opacity and animation frame. A keyframe may also have a command, allowing it to hook into the script engine to perform an action.

The timeline is displayed in a popover, where the user can select any instant in time (in half second increments) and see the existing keyframes. Entities can be dragged around in the editor and if a keyframe at the selected instant does not exist a new one will be created with the new position of the entity. Keyframes can also be manually added or modified by double-tapping the timeline, when a modal dialog with all properties will be brought up for tweaking.

The player

After a scene has been created, it has to be put in motion. For that, there’s an implementation of CCScene which takes a list of entities (with their respective timelines) and creates cocos2d nodes as appropriate (CCSprite, CCTMXTiledMap, etc.). A game loop is established and at each tick it will loop through all the entities performing the following steps:

  1. Is the entity a visual object (sprite, tile map)? If so, grabs the node from the scenegraph
  2. At the current instant, is there a keyframe in the entity’s timeline? If so, sets all the node’s properties from the keyframe (this is only a safety measure, in theory the next step should guarantee the the properties already have the correct values).
  3. Looks for the next keyframe in the timeline. If one is found, the time interval between the current keyframe and the next is calculated and one or more CCActions (CCMoveTo, CCScaleTo) are triggered on the node, where the time interval is the duration of the action and the future values are the targets.
  4. Repeats the process until the end of the scene.

And that’s all there is to it!

The code

I intended to share a sample project so that you could use this approach in your own code, but currently the code is not entirely presentable. There’s no error checking so it crashes whenever you don’t do exactly what it expects, and the UI is extremely non user-friendly. For the moment the editor is just enough for our internal needs, but if we have some time in the future we may polish it up a bit and release it (not likely, but possible). In the meantime, this write-up should be enough for you to create your own cutscene engine, and if you have any questions or suggestions please leave a comment!

EDIT: after the public outcry (:D), I’m now making available the source code. It is a stripped-down version of the editor we use, illustrating all the points talked about in this post. Some important considerations:

- This is an internal tool, so we will not be able to keep improving it for the public. We will however be glad to help you with anything we can!

- When you are previewing a scene and it reaches the end (it is hard-coded at 30 seconds right now), the application will quit, instead of returning to the editor.

- When saving a scene you should always include the .scn extension, as the file browser will look for those files for loading.

You can download the project here.

This article is part of iDevBlogADay, a group of independent iPhone dev-related blogs showcasing a different topic each day. Check out the rest of the group here.

Posted in Programming | Tagged , | 6 Comments

Pocket Arte+ Promo codes!

We will be giving away Pocket Arte+ promo codes to some of our lucky followers on Twitter! To participate, retweet the message below and follow @crocodella. We will send direct messages to the winners next Monday, using Twitter.

“I want a Pocket Arte+ promo code from Crocodella: http://kingo.to/yq8 Retweet and follow @crocodella to participate”

Posted in News | Tagged , | Leave a comment

Crocodella is now 1 year old!

As of today, Crocodella Software completes its first year of existence! It has been a crazy ride in learning, frustration and excitement, but one which has quite definitely changed our lives. We now know more than ever that this is what we want to do and will keep at it until the end. In this post I’ll try to summarize some of the highlights of our first year as indie developers, but first an announcement.

Get Litho and Entrapped for free!

That’s right! Until April 4th you can get Litho and Entrapped, our first two games, for free on the App Store. Consider this a gift to all of you who supported and encouraged us! Now, back to the regular content.

Works of Arte

When we first released Arte, we had no idea what to expect. It originated from Finker, and soon grew into a full fledged application. It was our first app targeted exclusively for the iPad, and in a category that had already been experiencing some saturation. We never thought it would be our most popular app yet!

The response absolutely blew us away. Sales of the paid version were quite good, and the income from ads in the free version, although small, has been steady and helped us keep up with the costs of having a company in Brazil (it’s not cheap, I tell you), and even funded some art assets for our next project!

But more than that, what really surprised us was the community that formed around it. Arte allows you to upload your drawing to an online gallery where it can be seen and rated by other users, and as of right now there are over 900 drawings uploaded. We even received some threats in image form to speed up our approval process (sorry guys, we are from a different time zone and try to approve you drawings as regularly as we can :D ). We’d like to thank each and everyone of you who download Arte and helped to make it a success!

Here are some of our favorite artworks submitted so far:

Time is lacking

Let me tell you, it is QUITE hard to be an indie developer when you also have a day job. Our main challenge this past year has been to find time to work on our products. The fact that 2010 has been quite an eventful year (weddings, doctorates, etc.) has not made it any easier. There are lots of features we would like to add to our apps (better controls for Litho, Twitter and Facebook integration for Arte) but we simply cannot find the time to both work on these improvements and also create new apps (and we have a HUGE backlog of ideas, trust me). Here’s hoping that our next project will see at least moderate success so we can finally work solely on Crocodella and fulfill our true potential.

What the future holds

We are now trying to abide by the following mantra: work on games that YOU would want to play! When you apply your true passion to something, the results will always find an audience, even if the success is not in the same order of magnitude of, say, Angry Birds or Tiny Wings.

Our next game is the result of that. It has been 10 years in the making (on and off, it’s not Duke Nukem Forever :P ) and we might say it has been the first spark in the fire that lead us to create games. We’re pouring our hearts in this, even though it is a hugely complex and even risky project, and it will be our defining game; the first product that embodies the full soul of Crocodella Software. Hope to have more about it to share with you guys very soon!

You'll be seeing a lot more of this little guy very soon!

Finally, we’d like to thank everyone who supported us during these exciting times (wives, girlfriends, family members, friends) and allowed us to grow and follow our dreams. And I’ll end this post with a promise: you haven’t seen the best of Crocodella Software yet!

We were told there would be cake, but given past experiences there’s a fair chance that the cake is a lie, so we’ll not rely on that fact.

Posted in News | Tagged , | 2 Comments

Book review: Cocos2d for iPhone 0.99 Beginner’s Guide

Anyone in the iOS development scene knows: if someone is working on a 2D game, chances are that they are using cocos2d to do so. Ricardo Quesada has done an amazing job with this engine, so much that it has become a de facto standard for indie developers who want to get their feet wet in the iOS world, while not skimping on advanced features for more experienced developers. Also, it has been the engine we chose for all of our games so far. :)

Packt Publishing approached us kindly providing an ebook copy of the Cocos2d for iPhone 0.99 Beginner’s Guide by Pablo Ruiz, in exchange for a short review here. First off, as a disclaimer, I (Fabio) personally do not care much for technical books, as I prefer a more hands-on approach of working with tutorials and sample code and actively engaging in the community through forums and other means when I’m hopelessly stuck (by the way, the cocos2d community is one of the best I’ve ever known!), but I’ll try not to let that personal preference bias this review.

The book covers a lot of ground, from installing the cocos2d XCode template and working with sprites and scenes all the way to physics and online integration through OpenFeint, while working on 3 “complete” games using these concepts. Audio, accelerometer input and particle systems are also explained and illustrated. The chapters are well structured, and provide a logical progression through the cocos2d classes and features. The text is very well written and all the sample code provided is clear and explained thoroughly, giving beginners an easy time grasping all the building blocks of what is a game written using cocos2d.

This book suffers from a problem common to most books written about beta software: the API is in constant flux. Therefore, while cocos2d 0.99.1 is discussed, the engine is already up to 0.99.5, with the 1.0 release looming in the horizon. Many classes have also had their name or behavior changed (such as CCLabel), which can leave beginners scratching their heads if looking through the cocos2d forums or other online sources of help. Another point which I believe could be better explored is memory management. While the book assumes the reader has some knowledge of the Objective-C language, memory management using init, retain, release, autorelease is the number one problem beginners seem to face (just look at number of people online stuck at a EXC_BAD_ACCESS exception). Sure, it’s not exactly pertinent to a cocos2d focused book, but I feel that a short chapter on this topic could be a great help to people grabbing the book eager to code their first game.

All in all, the book is pretty complete and should prove to be a welcome addition to all new developers salivating to create their first iOS hit. :)

Posted in Books | Tagged | Leave a comment

RPG-like text box with Cocos2D

One of the most striking characteristics of classic JRPGS is the use of text boxes for conversations, where the characters appear one by one and the player can advance to the next page when the current one is finished.

The best RPG ever!

In this post we’ll implement a generic text box component based on the CCLayerColor class, which you can then further customize as needed. It only supports bitmap fonts (CCLabelBMFont) for now, so each character can be manipulated individually. The component supports touching it to display the whole page at once, as well as to advance pages. You can also implement the TextBoxDelegate protocol to receive notifications when the page changes or the text reaches the end. I’ll assume the reader is familiar with the cocos2d framework and the Objective-C language. If you want to get the sample project and code right away, skip to the end of the post.

The TextBoxLayer class

First, we’ll define the interface of the TextBoxLayer class as follows:

#define TEXT_SPEED 60
#define TEXT_FONT_FILE @"arial16.fnt"

@class TextBoxLayer;

@protocol TextBoxDelegate
- (void)textBox:(TextBoxLayer *)tbox
	didFinishAllTextWithPageCount:(int)pc;
@optional
- (void)textBox:(TextBoxLayer *)tbox didMoveToPage:(int)p;
@end

@interface TextBoxLayer : CCLayerColor {
	CCLabelBMFont *textLabel;
	NSString *text;
	NSMutableArray *lines;
	float progress;
	int linesPerPage;
	int currentPageIndex;
	NSMutableString *currentPage;
	int currentPageCharCount;
	int totalPages;
	id delegate;
	BOOL ended;
}
@property (readwrite,retain) id delegate;
- (id) initWithColor:(ccColor4B)color
			   width:(GLfloat)w
			  height:(GLfloat)h
			 padding:(GLfloat)padding
				text:(NSString *)txt;
- (void)update:(float)dt;
- (NSString *)nextPage;
- (int)calculateStringSize:(NSString *)txt;
@end

We create a TextBoxDelegate protocol, so your code can be notified when the page changes or the text reaches the end. You can then respond by hiding the text box or doing any other custom action specific to your game. The constants TEXT_SPEED and TEXT_FONT_FILE define the speed of text advance and the default font file. The initWithColor... method is pretty straight-forward, as it takes a color, the dimensions of the box, internal padding (which will also be added to the dimensions of the box) and the full text to display (without line-breaks). The update method should be called every frame, and will update the text according to the time elapsed since the last frame. The nextPage and calculateStringSize are used internally and will be detailed later.

Calculating the line breaks

In order to wrap the text correctly, we’ll need to insert line-breaks when the current line no longer fits horizontally in the box. To make this easier, we’ll create the calculateStringSize helper method, which takes a NSString as an argument and returns the string width based on the default font.

- (int)calculateStringSize:(NSString *)txt {
	CCBMFontConfiguration *conf = FNTConfigLoadFile(TEXT_FONT_FILE);
	int totalSize = 0;
	for (int i = 0; i < [txt length]; i++) {
		int c = [txt characterAtIndex:i];
		ccBMFontDef def = conf->BMFontArray_[c];
		totalSize += def.xAdvance;
	}
	return totalSize;
}

We then use this method during class initialization to implement an algorithm that will split the text into lines and places them into an array. The code also calculates some values we’ll use later such as the number of lines per page and the number of pages needed.

CCBMFontConfiguration *conf = FNTConfigLoadFile(TEXT_FONT_FILE);
linesPerPage = h / conf->commonHeight_;

NSArray *words = [txt componentsSeparatedByString:@" "];
NSMutableString *wrappedText = [NSMutableString string];
lines = [[NSMutableArray alloc] init];

for (NSString *word in words) {
	NSString *eval = [wrappedText stringByAppendingFormat:@" %@", word];
	int size = [self calculateStringSize:eval];

	// See if the text so far plus the new word fits the rect
	if (size > w) {
		// If not, closes this line and starts a new one
		[lines addObject:[NSString stringWithString:wrappedText]];
		[wrappedText setString:word];
	} else {
		[wrappedText appendFormat:@" %@", word];
	}
}
[lines addObject:[NSString stringWithString:wrappedText]];
totalPages = ceil((float)[lines count] / linesPerPage);

Finally, we obtain the first page of text and assign it to the CCLabelBMFont object. We then iterate through all its children (each character in the string is represented by a CCSprite) and hide each of them by setting its opacity to 0.

textLabel = [CCLabelBMFont labelWithString:[self nextPage] fntFile:TEXT_FONT_FILE];
textLabel.anchorPoint = ccp(0,1);
textLabel.position = ccp(padding, h + padding);

// Hides all characters in the label
for (CCNode *node in textLabel.children) {
	CCSprite *charSpr = (CCSprite *)node;
	charSpr.opacity = 0;
}

The code above uses the nextPage method to take the lines and assemble them into a page.

- (NSString *)nextPage {
	progress = 0;

	[currentPage release];
	currentPage = [[NSMutableString string] retain];

	currentPageCharCount = 0;

	int line = currentPageIndex * linesPerPage;

	int i = 0;
	while (i < linesPerPage && line < [lines count]) {
		[currentPage appendFormat:@"%@\n", [lines objectAtIndex:line]];
		currentPageCharCount += [[lines objectAtIndex:line] length];
		i++;
		line++;
	}
	currentPageIndex++;

	return currentPage;
}

Updating the text

The rest of the magic happens in the update method. It will calculate which characters should be displayed and set their opacity to 255.

- (void)update:(float)dt {

	progress += (dt * TEXT_SPEED);

	int visible = progress;

	if (visible > currentPageCharCount) {
		progress = visible = currentPageCharCount;
	}

	// Each character sprite is assigned a tag corresponding to its index in the string,
	// and even though line-breaks are skipped, they are still counted for tag purposes.
	// Therefore, we use an offset so that the tag is correct.
	int offset = 0;

	for (int i = 0; i < visible; i++) {

		if ([currentPage characterAtIndex:i + offset] == '\n') {
			offset++;
		}

		CCSprite *charSpr = (CCSprite *) [textLabel getChildByTag:i + offset];
		charSpr.opacity = 255;
	}
}

We'll also need a way for the player to skip the text animation as well as advance to the next pages. We do that using the ccTouchesEnded event, which will also call the delegate methods as appropriate. Please note that in our game the text box is modal, therefore a tap anywhere on the screen will be considered. It should be easy to restrict this to taps within the text box by checking if the touch is contained in the text box rectangle.

-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

	if (progress < currentPageCharCount) {

		for (CCNode *node in textLabel.children) {
			CCSprite *charSpr = (CCSprite *)node;
			charSpr.opacity = 255;
		}
		progress = currentPageCharCount;

	} else {

		if (currentPageIndex < totalPages) {
			[textLabel setString:[self nextPage]];

			for (CCNode *node in textLabel.children) {
				CCSprite *charSpr = (CCSprite *)node;
				charSpr.opacity = 0;
			}

			if ([delegate respondsToSelector:@selector(textBox:didMoveToPage:)]) {
				[delegate textBox:self didMoveToPage:currentPageIndex];
			}

		} else {

			if (!ended) {
				ended = YES;

				if ([delegate respondsToSelector:@selector(textBox:didFinishAllTextWithPageCount:)]) {
					[delegate textBox:self didFinishAllTextWithPageCount:totalPages];
				}
			}
		}
	}
}

That's it!

EDIT: the code is now available on GitHub

And our text box is done! To download the sample project containing the full source code, click here.

Posted in Programming | Tagged | 26 Comments

Using AVPlayer to play background music from library

With the release of iOS 4, Apple finally allowed some sort of multitasking for apps running under it. One of these (and for some, the most important) is background audio, so users can continue to listen to the audio your app produces even if it’s not in the foreground. What if you want to play songs from the user’s iPod music library? Well, iOS offers the simple to use MPMusicPlayerController. But there is a caveat: as soon as your app is sent to the background, the audio stops playing (actually, there is a way to make it keep playing, but then you relinquish all control of the audio to the iPod app).

Luckily, there is another method to do this that, while lower-level and not as easy to use, works perfectly, using the AVPlayer class (part of the AVFoundation framework, be sure to add it to your project). Please note however that this class is only available in iOS 4.0 or later, so if you are developing an app that should run on older versions, be sure to take the necessary precautions. AVPlayer seems to be target mostly at video, but it can be used to play media items from the iPod library.

The first step is to tell the OS your app supports background audio, by adding the UIBackgroundModes key to your info.plist file:

Next, it is necessary to actually get the media item you wish to play and obtain its URL, which can be done using the MPMediaQuery class, and then create a new AVPlayer instance:

MPMediaQuery *query = [MPMediaQuery albumsQuery]; //Queries for songs ordered by album
MPMediaItem *item = [query.items objectAtIndex:0]; //Gets the first song
NSURL *itemURL = [item valueForProperty:MPMediaItemPropertyAssetURL];

AVPlayer *avPlayer = [[AVPlayer alloc] initWithURL:itemURL];

You will also need to setup the Audio Session correctly so the audio can be played in the background:

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];

// This is necessary if you want to play a sequence of songs, otherwise your app will be
// killed after the first one finishes.
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

At last, all you need to do is start a new UIBackgroundTest and play:

UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;

[avPlayer play];
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];

if (newTaskId != UIBackgroundTaskInvalid && bgTaskId != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask: bgTaskId];

bgTaskId = newTaskId;

To check if music is playing, you can use the rate property on your AVPlayer instance. It is a float number, where 0.0 means paused/stopped and 1.0 means playing at normal speed.

Working with time

Time is represented in AVPlayer using the CMTime structure. It is composed of a value and a timescale. The simple way to look at that is the timescale value representing how many units of time are in a second and the value representing how many actual units there are. Therefore, to get a value in seconds, you simply divide the value by the timescale, as such:

CMTime cTime = avPlayer.currentTime;
UInt64 currentTimeSec = cTime.value / cTime.timescale;

If you want to display this value and continually update this value in the UI, you’ll need to poll using a NSTimer. AVPlayer also lacks the convenient MPMusicPlayerControllerDelegate methods that tell you when the player state is changed, so you’ll have to get creative. Here is a way to be notified when a songs has played to the end:

NSNumber *time = [item valueForProperty:MPMediaItemPropertyPlaybackDuration];
CMTime endTime = CMTimeMakeWithSeconds([time floatValue], 1);
timeObserver = [avPlayer addBoundaryTimeObserverForTimes:[NSArray arrayWithObject:
	[NSValue valueWithCMTime:endTime]] queue:NULL usingBlock:^(void) {
		[avPlayer removeTimeObserver:timeObserver];
		timeObserver = nil;
		// Here goes the code you wish to run
	}
];

Sample project

EDIT: the code is now available on GitHub

This is a pretty simple music player illustrating what has been discussed so far. The simulator does not support loading from the iPod library, so you’ll have to test this on a device. Download it here.

Posted in Programming | Tagged | 8 Comments

Arte Christmas contest results!

Thank you for those who sent their incredible artworks! We have chosen two winners, which you can see in the gallery below. Congratulations!

And we have good news! The Christmas spirit has prevailed here at Crocodella, so everyone who participated in the contest will get promocodes to our apps! Enjoy!

Posted in News | Tagged , | Leave a comment