January 4, 2013 0

Endless loop on background thread

By admin in iOS

There are times when for whatever reason, you need to have a thread run in the background an extended period of time.
Here’s a simple way of accomplishing that.

In the .h ( Note that we have set the variable to atomic, this is required to prevent one thread from writing while the other one is reading

@interface TestViewController : UIViewController {
	BOOL _shouldContinue;
}
@property(atomic, assign)BOOL shouldContinue;

In the .m

- (void)viewDidLoad {
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
	[self startQueue];
}
 
-(void)startQueue {
	self.shouldContinue  = true;
 
	dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
	dispatch_async(aQueue, ^{
		while( self.shouldContinue ) {
			NSLog(@"Do some work here");
			[NSThread sleepForTimeInterval: 1.0/60.0];
		}
    });
}
December 7, 2012 5

Using Cinder in an iOS project

By admin in iOS

One of the problems when using Cinder in an iOS project, is that the default template essentially wants to take over the entire application. No more Objective-C, or UIKit. Which you might think, Oh no! I don’t want to re-implement all those UI elements people are accustomed to on iOS.

Luckily there islibrary out currently which allows you to use Cinder in an iOS project.
CCGLTouch Is a great library from smalllab.org, the repository is located at
https://github.com/smallab/CCGLTouch-XCode-Templates

Currently there are two bugs in it, which will cause the application to crash in an ARC project.
However they’re both simple fixes, just modify these two functions in the project:

MyAppDelegate.mm Remove duplicate allocation of MyCCGLView

- (void)launch {    
	// our CCGLTouchView being added as a subview
	ccglView = [[MyCCGLView alloc] initWithFrame:CGRectMake(0.0, 0.0, (float)[UIScreen mainScreen].bounds.size.width, (float)[UIScreen mainScreen].bounds.size.height-70.0)];
	[[viewController view] addSubview:ccglView];
    // set our view controller's prop that will hold a pointer to our newly created CCGLTouchView
    [viewController setCCGLView:ccglView];
 
    // viewController as the root view for our window
    super.window.rootViewController = viewController;
}

CCGLTouchView.mm Prevent application crash on dealloc by invalidating CADisplaylink

- (void)dealloc {
    [super stopAnimation];
 
    if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];
    [context release];
    context = nil;
    sharegroup = nil;
    [ccglCapture release];
    ccglCapture = nil;
    [super dealloc];
}

It’s a really great library, works wonderfully under iOS with no hiccups when the view is removed from the display hierarchy !

Tags: , ,

March 18, 2011 11

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 7

Cocos2D Forced Kerning

By admin in iOS

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:


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!

Update for Cocos2D 1.0.x, update by orninn

 
//  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;
 
	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 = [self kerningAmountForFirst:prev second:c];
 
        ccBMFontDef *fontDef = NULL;
        unsigned int charKey = c;
        HASH_FIND_INT(configuration_->BMFontHash_,&charKey, fontDef);
 
		if(fontDef) {	
			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];
			}
			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 += fontDef->xAdvance + kerningAmount;
			nextFontPositionX += [self forcedKerning];
 
			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

Original version (left for reference)

// 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 iOS

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 1

Better NSLog – Adding function name / line number to NSLog

By admin in iOS

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 iOS

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 2

Parsing Delimited String from XMLNode on iOS using GDataXMLNode

By admin in iOS

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 7

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 iOS
-(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: