martes, febrero 10, 2009

Tales of updating the GCC4 port of Haiku

In the Haiku Blog Michael Lotz shows all the problems he had and how he solved them. It's a long read, and certainly lists some confusing concepts. If you were at all curious what it would take, going from a GCC2-built Haiku to a GCC4-built Haiku with its own native compiler check this link here.

miércoles, febrero 04, 2009

Cocos2d Iphone Dynamically Touch Detection

After searching on the web, on how to detect touches in sprites in Cocos2d, I found a Blog, that helped me a lot on how to implement the touching detection system of sprites in Cocos 2d.

The Simple but usefull Input system didnt fit my needs, because I needed a System that could handle the Touch Detection Selectively and dinamically, So I took the system proposed (the top-down global input management.) if you checked the Blog, and modified it.

Generally the aproach allows a very high level of control over handling input, but is prone to creating a monolithic method that handles all input management for the application.

First, it requires that you have references to all Sprite objects that you are interested in detecting input for.

So we can setup a subclass of Sprite to track all instances, I'm gonna name it TSprite from now on (as Touch Sprite).

The idea of this method is having a Subclass of Sprite, wich has an array of all the Sprites that we want to handle Input Detection, and aditionally we would have a boolean flag that would tell us if each Sprite in the Array can be tracked or not in a certain moment.

In more or less words, here's the class:


@interface TSprite : Sprite {
BOOL canTrack; //tell us if a Sprite in the Array can be tracked.
}

+(NSMutableArray *)allMySprites;
+(void)track: (TSprite *)aSprite;
+(void)untrack: (TSprite *)aSprite;
+(BOOL)SomethingWasTouched:(CGPoint) pos;
+ (TSprite *) FindByTag:(int) tagVar;
- (CGRect) rect;
- (void) SetCanTrack:(BOOL) val;
- (BOOL) GetCanTrack;

@end


and the implementation:


@implementation TSprite


static NSMutableArray * allMySprites = nil;

+(NSMutableArray *)allMySprites {
@synchronized(allMySprites) {
if (allMySprites == nil)
allMySprites = [[NSMutableArray alloc] init];
return allMySprites;
}
return nil;
}

- (CGRect) rect {
float x = [self absolutePosition].x - [self contentSize].width/2;
float y = [self absolutePosition].y - [self contentSize].height/2;
float h = [self contentSize].height;
float w = [self contentSize].width;
return CGRectMake(x,y,w,h);
}

+(void)track: (TSprite *)aSprite {
@synchronized(allMySprites) {
NSUInteger i, count = [allMySprites count];
for(i = 0; i < count ; i++){
TSprite * obj = (TSprite *)[allMySprites objectAtIndex:i];
if(obj == aSprite){
return;
}
}
[[TSprite allMySprites] addObject:aSprite];
}
}

+(void)untrack: (TSprite *)aSprite {
@synchronized(allMySprites) {
[[TSprite allMySprites] removeObject:aSprite];
}
}

+(BOOL)SomethingWasTouched:(CGPoint) pos {
NSUInteger i, count = [allMySprites count];
for (i = 0; i < count; i++) {
TSprite * obj = (TSprite *)[allMySprites objectAtIndex:i];
if (CGRectContainsPoint([obj rect], pos) && [obj GetCanTrack]) {
return YES;
}
}
return NO;
}

+ (TSprite *) FindByTag:(int) tagVar{
NSUInteger i, count = [allMySprites count];
for(i = 0; i < count ; i++){
TSprite * obj = (TSprite *)[allMySprites objectAtIndex:i];
if([obj tag] == tagVar){
return obj;
}
}
return nil;

}
-(id)init {
self = [super init];
if (self){
[TSprite track:self];
[self SetCanTrack:YES];
}
return self;
}

- (void) SetCanTrack:(BOOL) val{
canTrack = val;
}
- (BOOL) GetCanTrack{
return canTrack;
}

-(void)dealloc {
[TSprite untrack:self];
[super dealloc];
}
@end


Then in the scene you implement the touch detection.


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];

NSArray * mySprites = [MySprite allMySprites];
NSUInteger i, count = [mySprites count];
for (i = 0; i < count; i++) {
MySprite * obj = (MySprite *)[mySprites objectAtIndex:i];
if (CGRectContainsPoint([obj rect], location) && [obj GetCanTrack]) {
// code here is only executed if obj has been touched
}
}
}


Now, a simple way of initiating this class can be:


TSprite *ez = [TSprite spriteWithFile:@"Sprite.png"];
[ez SetCanTrack:YES];//The sprite can be tracked.
[TSprite track:ez];

TSprite *asd= [TSprite spriteWithFile:@"AnotherSprite.png"];
[asd SetCanTrack:NO];
[TSprite track:asd];


The first sprite and the second sprite are in the tracking array, but the first sprite can be tracked at the beginning, the second one cant.

This Input System is usefull if you are prototyping, and have a simple application, the problem again, is that is prone to be a monolithic Input Management System, and if you are not careful enough with the architecture of your app, the code can be extremely hard to understand.

If you want a XCode project that shows how this Input System works, you can found it here.

Any comments are welcome.