March 18, 2011 7

Combining Cocos2D with UIKit and UIToolbar

By admin in Uncategorized

Cocos2D is an awesome 2D iphone game engine, it’s just really really good and the code inside is nicely organized.
However, to a beginner using Cocos2D it would seem that it does not work with UIKit based applications, this impression is largely Cocos2D’s fault.

I recently started a new game, and my plan is to use UIKit for some of the level-creation and imo there’s no need to use Cocos2D to simulate UIKit when UIKit is already an amazing UIKit simulator and readily available.

Last time I posted a similar idea, a lot of people found it useful, I started doing a write-up but to be honest it involves many steps that need explaining, and i’m not great at it.

So this time i’m instead providing it as a xcode project which you can open and compile and just start using!

Download / Repository

https://github.com/onedayitwillmake/Cocos2D-UIToolbar

Preview

Slight detail

  • Cocos2D lives in side a EAGLView, and EAGLView is just a view that you can insert into other views!
  • Especially in recent versions of iOS it plays very very nicely with other UIView’s occupying the screen at the same time
  • I started off with Cocos2D Box2D template, put the default logic in RootViewController inside of a new UIViewController and made sure Cocos2D was not attaching itself to the window.

Tags: ,

January 30, 2011 1

Cocos2D Forced Kerning

By admin in Uncategorized

In Cocos2D you display text, any number of ways. A popular method for displaying text is to use BitmapFont, that is – a font created in a program which outputs two files. A bitmap (say a png for example), and a plain text ‘.fnt’ file, containing information regarding where each character is in that file.

There are many programs that do this well, I use Heiro which is a free java based bitmap font creator.
A benefit of these programs as well, is that can ‘bake’ in certain effects such as an inset/glow/drop shadow – on to the text so it doesn’t have to be calculated every frame.

The problem with that however, is that it requires a lot of ‘padding’ on the font so the glow from the letter ‘A’ doesn’t spill to the letter ‘B’.

So you end up with something that looks like this

However what you would really like is something like this:

<hr>

Much better!

So how do we get that, well my method was to implement a iVar ‘forcedKerning’ variable into the bitmap font class – CCLabelBMFont .

This left me with a problem, when i upgraded Cocos2D, i over wrote my changes, and also for a while before that i was afraid to upgrade Cocos2D library version because of what i would break. So i started trying to figure out a different way to implement it using Categories.

Storing a variable using categories:

The Main problem, was that I needed to store the variable ‘forcedKerning’ for each instance of the class, however I did not want to create a global dictionary or the like, and you cannot create iVars in a category.

Since iOS 3.1, and OSX 10.6 there is something called ‘objc_getAssociatedObject‘ and ‘objc_setAssociatedObject
Which allows you to, essentially create a dynamic property to an existing class.

The ‘get’ takes two parameters, the object itself (the class instance), and a void UNIQUE pointer. Because that is used as the key. So the other bit of trickiery was figuring out a pointer, i can use that i can then access in a different method. Namely the setter.

The trick was to use @selector(setMyKey) as the pointer to the property!

Putting it together, how to force extra kerning with Cocos2D Bitmap font!

// Create a file called CCLabelBMFont+Kerning.m

//
//  CCLabelBMFont+Kerning.m
//  Junny
//
//  Created by Mario Gonzalez on 1/30/11.
//  Copyright 2011 Whale Island Games. All rights reserved.
//
#import <objc/runtime.h>
 
@interface CCLabelBMFont (kerning)
-(void) createFontChars;
@property (nonatomic, assign) float forcedKerning;
@end
 
@implementation CCLabelBMFont (kerning)
-(float) forcedKerning {
	return [objc_getAssociatedObject(self, @selector(forcedKerning)) floatValue];
}
-(void) setForcedKerning:(float)aValue {
	NSNumber *aNumber = [NSNumber numberWithFloat:aValue];
	objc_setAssociatedObject(self, @selector(forcedKerning), aNumber, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
	[self createFontChars];
}
 
-(void) createFontChars
{
	int nextFontPositionX = 0;
	int nextFontPositionY = 0;
	unichar prev = -1;
	int kerningAmount = 0;
 
	CGSize tmpSize = CGSizeZero;
 
	int longestLine = 0;
	int totalHeight = 0;
 
	int quantityOfLines = 1;
	float localForcedKerning = [self forcedKerning];
	NSUInteger stringLen = [string_ length];
	if( ! stringLen )
		return;
 
	// quantity of lines NEEDS to be calculated before parsing the lines,
	// since the Y position needs to be calcualted before hand
	for(NSUInteger i=0; i < stringLen-1;i++) {
		unichar c = [string_ characterAtIndex:i];
		if( c=='\n')
			quantityOfLines++;
	}
 
	totalHeight = configuration_->commonHeight_ * quantityOfLines;
	nextFontPositionY = -(configuration_->commonHeight_ - configuration_->commonHeight_*quantityOfLines);
 
	for(NSUInteger i=0; i<stringLen; i++) {
		unichar c = [string_ characterAtIndex:i];
		NSAssert( c < kCCBMFontMaxChars, @"BitmapFontAtlas: character outside bounds");
 
		if (c == '\n') {
			nextFontPositionX = 0;
			nextFontPositionY -= configuration_->commonHeight_;
			continue;
		}
 
		kerningAmount = (int) [self kerningAmountForFirst:prev second:c];
 
		ccBMFontDef fontDef = configuration_->BMFontArray_[c];
 
		CGRect rect = fontDef.rect;
 
		CCSprite *fontChar;
 
		fontChar = (CCSprite*) [self getChildByTag:i];
		if( ! fontChar ) {
			fontChar = [[CCSprite alloc] initWithBatchNode:self rectInPixels:rect];
			[self addChild:fontChar z:0 tag:i];
			[fontChar release];
		}
		else {
			// reusing fonts
			[fontChar setTextureRectInPixels:rect rotated:NO untrimmedSize:rect.size];
 
			// restore to default in case they were modified
			fontChar.visible = YES;
			fontChar.opacity = 255;
		}
 
		float yOffset = configuration_->commonHeight_ - fontDef.yOffset;
		fontChar.positionInPixels = ccp( (float)nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width*0.5f + kerningAmount,
										(float)nextFontPositionY + yOffset - rect.size.height*0.5f );
 
		// update kerning
 
		nextFontPositionX += configuration_->BMFontArray_[c].xAdvance + kerningAmount;
		nextFontPositionX += localForcedKerning;
 
		prev = c;
 
		// Apply label properties
		[fontChar setOpacityModifyRGB:opacityModifyRGB_];
		// Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
		[fontChar setColor:color_];
 
		// only apply opacity if it is different than 255 )
		// to prevent modifying the color too (issue #610)
		if( opacity_ != 255 )
			[fontChar setOpacity: opacity_];
 
		if (longestLine < nextFontPositionX)
			longestLine = nextFontPositionX;
	}
 
	tmpSize.width = longestLine;
	tmpSize.height = totalHeight;
 
	[self setContentSizeInPixels:tmpSize];
}
@end

For now i’m duplicating the original createFontChars method, via copy paste, this is a big nono – but im looking to undo that, and it’s still much better than modifying the Libraries class file and being stuck to it forever.

Tags: , , ,

January 27, 2011 0

New Stanford course is online

By admin in Uncategorized

I learned a lot by watching the original course, nothing like having someone explain in lecture form, after reading about these concepts for a while. And now it looks like, they’ve updated the course.

The new instructor has a more calm style, seems like it will be good.
http://itunes.apple.com/us/itunes-u/developing-apps-for-ios-sd/id395631522

This is from the first few minutes of the first lecture.

Tags:

October 30, 2010 0

Better NSLog – Adding function name / line number to NSLog

By admin in Uncategorized

When tracking down a bug, the most useful way to start checking things is to NSLog something. I’m a heavy user of breakpoints and the debugger. I can’t live without it, and it’s saved me countless hours. However I usually see if i can NSLog something first perhaps the problem was an obvious one.

A problem that frequently occurs is that when trying to track down a bug, you end up with many NSLog statements in the console and it’s difficult to know which is which. Often you’ll see coders start adding things like “>>>” or “#”, to differentiate this NEW NSLog statement from the ones already showing up.

An easy solution for this, is to use a better logging function one that can tell you the function from which it was called, and the line number.
The compiler has certain special variables you can use that give you this information. With that knowledge, creating a macro for a better log function becomes very simple.

#define VERBOSE_DEBUG_ENABLED_DEBUG 1 // Set to 0 to turn off
#if !defined(VERBOSE_DEBUG_ENABLED) || VERBOSE_DEBUG_ENABLED == 0 
#define LOGVERBOSE(...) do{}while(0)
#else
#define LOGVERBOSE(__FORMAT__, ...) NSLog(@"%s-Line: %d->%@", __func__, __LINE__, [NSString stringWithFormat:__FORMAT__, __VA_ARGS__])
#endif

Here we are using the special compiler directives (i’m not sure what their proper terms are), __func__, and __LINE__ to create a new NSLog statement that then uses, stringWithFormat: to wrap the user’s log call so that it behaves exactly like NSLog.

In practice it is used like this

#include SOME_HEADER_FILE_WITH_ABOVE_CODE
...
LOGVERBOSE(@"someVar: %0.2f", someVar);
// Outputs
// -[SomeViewControllerSubclass myFunction:]-Line:32->someVar: 4.34

That’s all there is to it. Very useful.

Tags:

October 26, 2010 4

The best form submission class (asi-http-request)

By admin in Uncategorized

Small but quick snippet here.

Sending multi-part form with image data:

        NSString *imagePath = 	NSString *imagePath = [NSString stringWithFormat:@"%@/%@",
						   [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
						   @"junny.png"];
 
        UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
        NSData * imageData = UIImageJPEGRepresentation(image, 0.75)
 
	ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:http://example.com/form.php]];
	[request setPostValue:@"I like brains!" forKey:@"title"];
	[request setPostValue:[NSString stringWithFormat:@"%@", [NSDate date]] forKey:@"session"];l
	[request setPostValue:@"image.png" forKey:@"Filename"];
	[request setData:imageData forKey:@"Filedata"]; // Get image, convert to JPG, get data
	[request setDelegate:self];
	[request startAsynchronous];

The ASIFormDataRequest, is the BEST class for handling POST/GET/Multi-Part http request. It has a lot of classes, and its a little bulkier because it does what it does amazingly well. I’ve tried a few other implementations and this thing saved my life at 4am when I was about to start crying on this project

Tags:

October 14, 2010 0

Parsing Delimited String from XMLNode on iOS using GDataXMLNode

By admin in Uncategorized

Often when you work with XML, you need to put a bunch of values into a node, maybe positioning information for example.
The best way to do that is to create a “Delimited String”, that is “ABC|123|XYZ|987″, is delimited by the | character.

Here’s how you get that back in iOS into an array, that you can then loop through and make use of:

Btw I’m using GDataXML, which is googles Objective-C xml reading/writing library. Needless to say it’s very good, and very fast.

Ok, so let’s turn this into an array:

<pos>297.00,30.00</pos>
// Broken into multiple lines to fit, it's a long one!
NSArray *myPositionList = [[[[[xmltree elementsForName:@"pos" ] objectAtIndex:0] stringValue]
     stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] 
           componentsSeparatedByString:@","];

Tags:

October 10, 2010 2

Reading / Creating XML in iOS

By admin in Uncategorized

As I’ve mentioned previously, this blog serves as a kind of social-bookmarker, and exist somewhat in order for me to chronologically log my learning experience with iOS programming. So not everything I post is always a how-to or a tip, but sometimes I will share something which I read that I found useful that people learning as I learn might find useful, not to mention I often reference my own blog to remember stuff.

Anyway, this is a great write up on using GDataXML for reading/creating XML in iOS.
http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml

Tags: , ,

October 6, 2010 0

Post-A-Day #10 UIViewController’s views

By admin in Uncategorized
-(void) someEventDidOccur
EditOptionsViewController *anEditOptionsViewController = [modalViewControllers_ objectForKey:@"someName"];
 
	// A little note about retain/release
	//	views are not aware of their UIViewController
	//		When they don't have one, and .view is requested UIViewController will simply create a new one.
	//	In the code below, if the order were reversed, "anEditOptionsViewController" would be dealloced
	//
	//	After wich the subsequent .view call, or '[anEditOptionsViewController view]' would create a new view, Havoc ensues
	[anEditOptionsViewController.view removeFromSuperview];
	[modalViewControllers_ removeObjectForKey:@"someName"];

Tags:

October 5, 2010 0

Post-A-Day #9 – Blocks Part 1

By admin in Uncategorized

In objective-C a Block is a type of closure.
A closure, is a method that contains state information, using free variables. It binds the variables for you on the stack, so in that sense it “closes” the expression.

To give an example in javascript you could call setTimeout this way:

function callLater(first, second, third)
{
    return (
		function()
		{
			/* This inner function is to be executed with - setTimeout
			   - and when it is executed it can read, and act upon, the
			   parameters passed to the outer function:-
			*/
			total = 0;
			for(i = 0; i < third; i++
			{
				total += first * second;
			}
 
			return total;
		}
    );
}
 
 
a = 3;
b = 4;
c = 5;
functionReference = callLater(a, b, c);
setTimeout(functionReference, 2500);

A closure allows you to bind free variables, it “closes” the encapsultation.
Pretty useful stuff…

In Objective-C this can be accomplished using a language feature called Blocks, this is what one looks like

Objective-C and the Foundation framework make heavy usage of Blocks, for things like sorting arrays – performing things on threads, etc.

I’ll talk more about that later, but with the above you can at least create a Block and get started, in understanding their somewhat cryptic looking syntax.

Tags:

October 3, 2010 1

Post-A-Day #8 – Allow superview to recieve events caught by subview.

By admin in Uncategorized

I had a problem in my current project related to this, and it was a good opportunity, to learn a little bit more about how touches are handled in iOS.

Enter UIResponder

UIResponder is the Class any objects that which to receive events must Subclass, if they wish to receive (among other types) TouchEvents from the application.
UIView and UIViewController are two distinct Subclasses of UIResponder. However keep in mind that UIViewController is not a subclass of UIView, nor is UIView a subclass of UIViewController. Each is distinct.

For the purposes of this discussion, just know that it implements these four methods.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

The responder chain

All active UIResponders are actually part of the ‘ResponderChain‘ . In other words; each one knows about the next one in the ResponderChain. This is probably done this way to to run as fast as possible during RunTime.

The tail of the responder chain, for applications running on iOS is the UIWindow.
When a user taps the screen, the device figures out who to call ‘touchesBegan‘ on by calling –hitTest:withEvent: on all active responders. This function in turn calls, –pointInside:withEvent: on of that views subviews.

So if you had objectA, inside of objectB, which is inside of objectC. Actually let’s use a more concrete example: imagine you had Person, inside of a House, inside of Block.
In our pseudo real world example the responder chain might look like this: Person->House->Block->…->Universe.
When a user touches the screen, PersonA is the head of the responder chain, he checks if the tap happened on him by checking ‘pointInside:withEvent:’, if the response is NO. The next object in the ResponderChain, in our case House does the same check. Eventually if no one caught the TouchEvent, the universe receives it and can do something with it or nothing.

The way apple has implemented the ResponderChain actually makes it much simpler to ‘bubble up’ a touch event however.
To bubble up a touch event from a subView to it’s parentView, you simply call -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; you simply call on super. For example:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
     // Forward this message up the responder chain
     [super touchesBegan:touches withEvent: event];
}

Tags: