I submitted a patch a while back (http://code.google.com/p/cocos2d-iphone/issues/detail?id=590) and am wondering what I can do to get it sped up for inclusion into the main distribution. Previous discussion of this patch is located at: http://www.cocos2d-iphone.org/forum/topic/2318 .
The following bit of code makes it very easy to specify actions in an external plist (or wherever) without having to define them in your code. What I'm using it for is having different levels where for every sort of sprite it has events (tapped, collision, dragged, dropped, etc) and an associated action that is executed. It has really cut down on the development time having it all outside of the code.
Here's an example code snippet of what I'm using the no arg inits for:
-(void) initAction:(Action*) action withDescriptor:(ActionDescriptor*)actionToCreate {
NSMutableSet *processedSymbols = [[NSMutableSet alloc] init];
for (NSString *propertyName in [actionToCreate.attributes allKeys]) {
// TODO: remove positionX code
if(![propertyName isEqualToString:@"name"] && ![propertyName isEqualToString:@"positionX"] && ![propertyName isEqualToString:@"positionY"]) {
BOOL isSet = [self setValue: [actionToCreate.attributes valueForKey:propertyName] forProperty: propertyName onInstance: action];
if (!isSet) {
// Check to see if the property name is actually specifying a struct.
NSRange foundRange;
foundRange = [propertyName rangeOfString:@"."];
if (foundRange.location == NSNotFound) {
// The property is not multipart (eg. it is not 'delta.x'), so ignore & continue
NSAssert2(NO, @"Property '%@' is not a ivar of %@", propertyName, action);
NSLog(@"Property '%@' is not a ivar of %@", propertyName, action);
} else {
NSString *property = [propertyName substringToIndex:foundRange.location];
if (![processedSymbols containsObject:property]) {
[self setProperty:property forAction:action withAttributes:[actionToCreate attributes]];
[processedSymbols addObject:property];
} else {
// We've already processed this property
}
}
} else {
// The field was set we are fine.
}
}
}
[processedSymbols release];
}
/*
Sets the CGPoint property on the specified action.
*/
- (void) setProperty:(NSString *)property forAction:(Action *) action withAttributes:(NSDictionary *) attributes {
// Obtain the symbol, including its delimiter, e.g. 'delta'
NSString *symbol = property;
// Filter the attributes to those whose keys begin with the symbol
NSArray *allKeys = [attributes allKeys];
NSPredicate *contains = [NSPredicate predicateWithFormat:@"SELF contains %@", symbol];
NSArray *keysForSymbol = [allKeys filteredArrayUsingPredicate:contains];
// Create the struct & set the action
NSString *x = [symbol stringByAppendingString:@".x"];
NSAssert1([keysForSymbol containsObject:x], @"The property specified by '%@' is missing its x field.", property);
NSString *y = [symbol stringByAppendingString:@".y"];
NSAssert1([keysForSymbol containsObject:y], @"The property specified by '%@' is missing its y field.", property);
CGPoint point = CGPointMake([[attributes valueForKey:x] floatValue], [[attributes valueForKey:y] floatValue]);
[action setValue:[NSValue valueWithCGPoint:point] forKey:property];
}
-(BOOL) setValue:(id) value forProperty:(NSString*) property onInstance:(id) object {
BOOL isSuccessful = YES;
// Try setting as a property
objc_property_t hasProperty = class_getProperty([object class], [property UTF8String]);
if (hasProperty) {
[object setValue: value forKey: property];
} else {
// Try modifying the iVar directly
Ivar ivar = object_setInstanceVariable(object, [property UTF8String], value);
if (!ivar) isSuccessful = NO;
}
return isSuccessful;
}
If any of that is unclear feel free to ask for clarification!