最烦每次都要代码去绑定 ccb 里面的属性和方法了,有时候因为大小写的错误很烦。
所以找了 cocosbuilder 的源码,在它基础上生成 .h , .cpp 代码文件。
- (BOOL) publishDirectory:(NSString*) dir subPath:(NSString*) subPath { CocosBuilderAppDelegate* ad = [CocosBuilderAppDelegate appDelegate]; ResourceManager* resManager = [ResourceManager sharedManager]; NSArray* resIndependentDirs = [resManager resIndependentDirs]; NSFileManager* fm = [NSFileManager defaultManager]; // Path to output directory for the currently exported path NSString* outDir = NULL; if (projectSettings.flattenPaths && projectSettings.publishToZipFile) { outDir = outputDir; } else { outDir = [outputDir stringByAppendingPathComponent:subPath]; } // Check for generated sprite sheets BOOL isGeneratedSpriteSheet = NO; NSDate* srcSpriteSheetDate = NULL; if ([projectSettings.generatedSpriteSheets objectForKey:subPath]) { isGeneratedSpriteSheet = YES; srcSpriteSheetDate = [self latestModifiedDateForDirectory:dir]; // Clear temporary sprite sheet directory [fm removeItemAtPath:[projectSettings tempSpriteSheetCacheDirectory] error:NULL]; } // Create the directory if it doesn't exist if (!isGeneratedSpriteSheet) { BOOL createdDirs = [fm createDirectoryAtPath:outDir withIntermediateDirectories:YES attributes:NULL error:NULL]; if (!createdDirs) { [warnings addWarningWithDescription:@"Failed to create output directory %@" isFatal:YES]; return NO; } } // Add files from main directory NSMutableSet* files = [NSMutableSet setWithArray:[fm contentsOfDirectoryAtPath:dir error:NULL]]; // Add files from resolution depentant directories for (NSString* publishExt in publishForResolutions) { NSString* resolutionDir = [dir stringByAppendingPathComponent:publishExt]; BOOL isDirectory; if ([fm fileExistsAtPath:resolutionDir isDirectory:&isDirectory] && isDirectory) { [files addObjectsFromArray:[fm contentsOfDirectoryAtPath:resolutionDir error:NULL]]; } } // Add files from the -auto directory NSString* autoDir = [dir stringByAppendingPathComponent:@"resources-auto"]; BOOL isDirAuto; if ([fm fileExistsAtPath:autoDir isDirectory:&isDirAuto] && isDirAuto) { [files addObjectsFromArray:[fm contentsOfDirectoryAtPath:autoDir error:NULL]]; } // Iterate through all files for (NSString* fileName in files) { if ([fileName hasPrefix:@"."]) continue; NSString* filePath = [dir stringByAppendingPathComponent:fileName]; BOOL isDirectory; BOOL fileExists = [fm fileExistsAtPath:filePath isDirectory:&isDirectory]; if (fileExists && isDirectory) { NSString* childPath = NULL; if (subPath) childPath = [NSString stringWithFormat:@"%@/%@", subPath, fileName]; else childPath = fileName; // Skip resource independent directories if ([resIndependentDirs containsObject:fileName]) continue; // Skip generated sprite sheets if (isGeneratedSpriteSheet) continue; // Skip the empty folder if ([[fm contentsOfDirectoryAtPath:filePath error:NULL] count] == 0) continue; // Skip the fold no .ccb files when onlyPublishCCBs is true if(projectSettings.onlyPublishCCBs && ![self containsCCBFile:filePath]) continue; [self publishDirectory:filePath subPath:childPath]; } else { // Publish file // Copy files for (NSString* ext in copyExtensions) { // Skip non png files for generated sprite sheets if (isGeneratedSpriteSheet && ![ext isEqualToString:@"png"]) continue; if ([[fileName lowercaseString] hasSuffix:ext] && !projectSettings.onlyPublishCCBs) { // This file should be copied NSString* dstFile = [outDir stringByAppendingPathComponent:fileName]; // Use temp cache directory for generated sprite sheets if (isGeneratedSpriteSheet) { dstFile = [[projectSettings tempSpriteSheetCacheDirectory] stringByAppendingPathComponent:fileName]; } // Make conversion rules for audio NSString* newFormat = NULL; if ([ext isEqualToString:@"wav"]) { if (targetType == kCCBPublisherTargetTypeIPhone) { newFormat = @"caf"; } else if (targetType == kCCBPublisherTargetTypeHTML5) { newFormat = @"mp3"; } else if (targetType == kCCBPublisherTargetTypeAndroid) { newFormat = @"ogg"; } } /* else if ([ext isEqualToString:@"mp3"]) { if (targetType == kCCBPublisherTargetTypeAndroid) { newFormat = @"ogg"; } } */ if (newFormat) { // Set new name dstFile = [[dstFile stringByDeletingPathExtension] stringByAppendingPathExtension:newFormat]; // Add to conversion table NSString* localName = fileName; if (subPath) localName = [subPath stringByAppendingPathComponent:fileName]; [self addRenamingRuleFrom:localName to:[[localName stringByDeletingPathExtension] stringByAppendingPathExtension:newFormat]]; } // Copy file (and possibly convert) if (![self copyFileIfChanged:filePath to:dstFile forResolution:NULL isSpriteSheet:isGeneratedSpriteSheet outDir:outDir srcDate: srcSpriteSheetDate]) return NO; if (publishForResolutions) { for (NSString* res in publishForResolutions) { if (![self copyFileIfChanged:filePath to:dstFile forResolution:res isSpriteSheet:isGeneratedSpriteSheet outDir:outDir srcDate: srcSpriteSheetDate]) return NO; } } } } // Publish ccb files if ([[fileName lowercaseString] hasSuffix:@"ccb"] && !isGeneratedSpriteSheet) { NSString* strippedFileName = [fileName stringByDeletingPathExtension]; NSString* dstFile = [[outDir stringByAppendingPathComponent:strippedFileName] stringByAppendingPathExtension:publishFormat]; //处理 g_pTempOutPutPath { NSString* strPath = [NSString stringWithFormat:@"%@",dstFile]; NSArray* ary = [dir componentsSeparatedByString:@"/"]; NSMutableString* outPutPath = [NSMutableString stringWithString:@""]; for (int iii=0;iii<[ary count]-1 ;iii++ ) { NSString* str = [ary objectAtIndex:iii ]; [outPutPath appendFormat:@"/%@",str]; } g_pTempRootPath = outPutPath;//root path NSString* strOutPathDirect = [NSString stringWithFormat:@"%@/codeOutPut/",outPutPath]; outPutPath = [NSMutableString stringWithFormat:@"%@/%@" , strOutPathDirect ,strippedFileName]; if(1 ) { NSError* error = nil; [[NSFileManager defaultManager] createDirectoryAtPath:strOutPathDirect withIntermediateDirectories:NO attributes:nil error:&error]; if (error != nil) { NSLog(@"error = %@",error); } } g_pTempOutPutClassName = strippedFileName; g_pTempOutPutPath = [NSString stringWithString:outPutPath]; } // Add file to list of published files NSString* localFileName = [dstFile relativePathFromBaseDirPath:outputDir]; [publishedResources addObject:localFileName]; if ([dstFile isEqualToString:filePath]) { [warnings addWarningWithDescription:@"Publish will overwrite files in resource directory." isFatal:YES]; return NO; } NSDate* srcDate = [CCBFileUtil modificationDateForFile:filePath]; NSDate* dstDate = [CCBFileUtil modificationDateForFile:dstFile]; //if (![fm fileExistsAtPath:dstFile] || [self srcFile:filePath isNewerThanDstFile:dstFile]) if (![srcDate isEqualToDate:dstDate]) { [ad modalStatusWindowUpdateStatusText:[NSString stringWithFormat:@"Publishing %@...", fileName]]; // Remove old file [fm removeItemAtPath:dstFile error:NULL]; // Copy the file BOOL sucess = [self publishCCBFile:filePath to:dstFile]; if (!sucess) return NO; [CCBFileUtil setModificationDate:srcDate forFile:dstFile]; } g_pTempOutPutPath = nil; } } } if (isGeneratedSpriteSheet) { // Sprite files should have been saved to the temp cache directory, now actually generate the sprite sheets NSString* spriteSheetDir = [outDir stringByDeletingLastPathComponent]; NSString* spriteSheetName = [outDir lastPathComponent]; ProjectSettingsGeneratedSpriteSheet* ssSettings = [projectSettings smartSpriteSheetForSubPath:subPath]; // Check if sprite sheet needs to be re-published for (NSString* res in publishForResolutions) { NSArray* srcDirs = [NSArray arrayWithObjects: [projectSettings.tempSpriteSheetCacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"resources-%@", res]], projectSettings.tempSpriteSheetCacheDirectory, nil]; NSString* spriteSheetFile = NULL; if (publishToSingleResolution) spriteSheetFile = outDir; else spriteSheetFile = [[spriteSheetDir stringByAppendingPathComponent:[NSString stringWithFormat:@"resources-%@", res]] stringByAppendingPathComponent:spriteSheetName]; // Skip publish if sprite sheet exists and is up to date NSDate* dstDate = [CCBFileUtil modificationDateForFile:[spriteSheetFile stringByAppendingPathExtension:@"plist"]]; if (dstDate && [dstDate isEqualToDate:srcSpriteSheetDate] && !ssSettings.isDirty) { continue; } Tupac* packer = [Tupac tupac]; packer.outputName = spriteSheetFile; packer.outputFormat = TupacOutputFormatCocos2D; if (targetType == kCCBPublisherTargetTypeIPhone) { packer.imageFormat = ssSettings.textureFileFormat; packer.compress = ssSettings.compress; packer.dither = ssSettings.dither; } else if (targetType == kCCBPublisherTargetTypeAndroid) { packer.imageFormat = ssSettings.textureFileFormatAndroid; packer.compress = NO; packer.dither = ssSettings.ditherAndroid; } else if (targetType == kCCBPublisherTargetTypeHTML5) { packer.imageFormat = ssSettings.textureFileFormatHTML5; packer.compress = NO; packer.dither = ssSettings.ditherHTML5; } // Update progress [ad modalStatusWindowUpdateStatusText:[NSString stringWithFormat:@"Generating sprite sheet %@...", [[subPath stringByAppendingPathExtension:@"plist"] lastPathComponent]]]; // Pack texture packer.directoryPrefix = subPath; packer.border = YES; [packer createTextureAtlasFromDirectoryPaths:srcDirs]; // Set correct modification date [CCBFileUtil setModificationDate:srcSpriteSheetDate forFile:[spriteSheetFile stringByAppendingPathExtension:@"plist"]]; } [publishedResources addObject:[subPath stringByAppendingPathExtension:@"plist"]]; [publishedResources addObject:[subPath stringByAppendingPathExtension:@"png"]]; if (ssSettings.isDirty) { ssSettings.isDirty = NO; [projectSettings store]; } } return YES; }
//
- (void) writeDocument:(NSDictionary*)doc { NSDictionary* nodeGraph = [doc objectForKey:@"nodeGraph"]; jsControlled = [[doc objectForKey:@"jsControlled"] boolValue]; [self outputAssginedMemberAndSelector:nodeGraph];//输出绑定的变量和函数 [self cacheStringsForNode:nodeGraph]; [self cacheStringsForSequences:doc]; [self transformStringCache]; [self writeHeader]; [self writeStringCache]; [self writeSequences:doc]; [self writeNodeGraph:nodeGraph]; } NSString* g_pTempOutSuperClassName;//父类头文件的类名字 NSString* g_pTempOutSubClassName;//子类头文件的类名字 NSString* g_pWantSaveCodeFilePath = nil;//希望存储代码的位置 -(void)searchMemberAndAppend:(NSDictionary*)node saveInMemberString:(NSMutableString*)strMembers saveInMemberInitString:(NSMutableString*)strMembersInit strMembersBind:(NSMutableString*)strMembersBind saveMenuBind:(NSMutableString*)strMenuBinds saveMenuHead:(NSMutableString*)strMenuHead saveMenuCPP:(NSMutableString*)strMenuCpp saveMenuCallBackFun_SuperHead:(NSMutableString*)strMenuCallBackFun_SuperHead { NSString* baseClass = [node objectForKey:@"baseClass"]; NSString* customClass = [node objectForKey:@"customClass"]; NSArray* aryChildren = [node objectForKey:@"children" ]; NSString* displayName = [node objectForKey:@"displayName"]; NSString* memberVarAssignmentName = [node objectForKey:@"memberVarAssignmentName"]; NSNumber* memberVarAssignmentType = [node objectForKey:@"memberVarAssignmentType"]; //检查生成代码的目录 if ([displayName isEqualToString:@"code_save_path"]) { g_pWantSaveCodeFilePath = memberVarAssignmentName; return; } //成员 if ([memberVarAssignmentType intValue] == 2 && [memberVarAssignmentName length] > 0) { NSString* classnames = [customClass length] == 0 ? baseClass : customClass; NSString* comentStr = [displayName isEqualToString:baseClass] ? @"" : displayName; //owner // 类型* 成员名;//注释 NSString* oneMember = [NSString stringWithFormat:@"\t%@* %@;//%@\r\n",classnames,memberVarAssignmentName ,comentStr]; [strMembers appendString:oneMember]; //初始化代码 NSString* strInit = [NSString stringWithFormat:@"\t\t%@ = NULL;\r\n",memberVarAssignmentName]; [strMembersInit appendString:strInit]; //绑定成员 NSString* strBind = [NSString stringWithFormat:@"\t\tCCB_MEMBERVARIABLEASSIGNER_GLUE(this, \"%@\", %@*, this->%@);\r\n",memberVarAssignmentName,classnames,memberVarAssignmentName]; [strMembersBind appendString:strBind]; } //绑定菜单项 if ([baseClass rangeOfString:@"CCMenuItem"].length > 0) { //菜单项的绑定 NSArray* aryProperties = [node objectForKey:@"properties"]; for (NSDictionary* dic in aryProperties) { NSString* proname = [dic objectForKey:@"name"]; NSString* protype = [dic objectForKey:@"type"]; if ([proname rangeOfString:@"block"].length > 0 && [protype rangeOfString:@"Block"].length > 0 ) { NSArray* aryTheValue = [dic objectForKey:@"value"]; if ([aryTheValue count] == 1) { continue; } NSString* funName = [aryTheValue objectAtIndex:0]; if ([funName isKindOfClass:[NSString class]] == NO || [funName length] == 0) { break; } //绑定 NSString* newBind = [NSString stringWithFormat:@"\t\tCCB_SELECTORRESOLVER_CCMENUITEM_GLUE(this, \"%@\", %@::%@);\r\n", funName ,g_pTempOutSuperClassName, funName ]; if ([strMenuBinds rangeOfString:newBind].length == 0) { [strMenuBinds appendString:newBind]; //头文件函数 [strMenuHead appendFormat:@"\tvirtual void %@(cocos2d::CCObject* pSender);\r\n",funName]; //cpp 文件 [strMenuCpp appendFormat:@"void %@::%@(cocos2d::CCObject* pSender)\r\n{\r\n\r\n}\r\n",g_pTempOutSubClassName,funName]; //父类头文件里面的函数声明 必须给子类来实现 [strMenuCallBackFun_SuperHead appendFormat:@"\tvirtual void %@(cocos2d::CCObject* pSender)=0;\r\n",funName]; } break; } } } //检查 child for (NSDictionary* subNode in aryChildren) { if ([subNode isKindOfClass:[NSDictionary class]]) { [self searchMemberAndAppend:subNode saveInMemberString:strMembers saveInMemberInitString:(NSMutableString*)strMembersInit strMembersBind:strMembersBind saveMenuBind:strMenuBinds saveMenuHead:strMenuHead saveMenuCPP:strMenuCpp saveMenuCallBackFun_SuperHead:strMenuCallBackFun_SuperHead]; } } } extern NSString* g_pTempOutPutPath; extern NSString* g_pTempOutPutClassName; extern NSString* g_pTempRootPath; -(void)outputAssginedMemberAndSelector:(NSDictionary*)nodeGraph { //输出方式是 父类一个头文件,子类一个头文件+一个CPP文件.每次publish都重新生成父类的头文件,然后判断子类的头文件和cpp文件是否存在,如果已经存在,则不再做生成操作 g_pTempOutSuperClassName = [NSString stringWithFormat:@"%@_ccbHead",g_pTempOutPutClassName]; g_pTempOutSubClassName = g_pTempOutPutClassName; g_pWantSaveCodeFilePath = nil; //存储成员 NSMutableString* strMembers = [NSMutableString stringWithString:@"\r\n"];//成员定义 NSMutableString* strMembersInit = [NSMutableString stringWithString:@"\r\n"];//成员初始化 NSMutableString* strMembersBind = [NSMutableString stringWithString:@"\r\n"];//成员绑定 NSMutableString* strMenuBinds = [NSMutableString stringWithString:@"\r\n"];//菜单事件绑定 NSMutableString* strMenuHead = [NSMutableString stringWithString:@"\r\n"];//菜单函数头 NSMutableString* strMenuCpp = [NSMutableString stringWithString:@"\r\n"];//菜单函数 cpp NSMutableString* strMenuCallBackFun_SuperHead = [NSMutableString stringWithString:@"\r\n"]; [self searchMemberAndAppend:nodeGraph saveInMemberString:strMembers saveInMemberInitString:(NSMutableString*)strMembersInit strMembersBind:strMembersBind saveMenuBind:strMenuBinds saveMenuHead:strMenuHead saveMenuCPP:strMenuCpp saveMenuCallBackFun_SuperHead:strMenuCallBackFun_SuperHead]; // NSLog(@"%@",strMembers); // NSLog(@"%@",strMenuBinds); // NSLog(@"%@",strMenuHead); // NSLog(@"%@",strMenuCpp); //写文件存储 if (g_pTempOutPutPath != nil) { NSError* error = nil; [strMembers writeToFile:[NSString stringWithFormat:@"%@__member.txt",g_pTempOutPutPath] atomically:NO encoding:4 error:&error]; if (error != nil) { NSLog(@"error = %@",error); error = nil; } [strMenuBinds writeToFile:[NSString stringWithFormat:@"%@__menuBind.txt",g_pTempOutPutPath] atomically:NO encoding:4 error:&error]; if (error != nil) { NSLog(@"error = %@",error); error = nil; } [strMenuHead writeToFile:[NSString stringWithFormat:@"%@__menuH.txt",g_pTempOutPutPath] atomically:NO encoding:4 error:&error]; if (error != nil) { NSLog(@"error = %@",error); error = nil; } [strMenuCpp writeToFile:[NSString stringWithFormat:@"%@__menuCPP.txt",g_pTempOutPutPath] atomically:NO encoding:4 error:&error]; if (error != nil) { NSLog(@"error = %@",error); error = nil; } } //自动生成 .h 文件 和子类的 .h .cpp文件 if (g_pWantSaveCodeFilePath.length > 0) { NSString* templatePath1 = [[NSBundle mainBundle] pathForResource:@"TemplateCCB_CodeFile_Head_h" ofType:@"txt"]; //得到写父类头文件的路径 NSString* pathHeadSuper = [NSString stringWithFormat:@"%@/%@/%@.h",g_pTempRootPath,g_pWantSaveCodeFilePath , g_pTempOutSuperClassName ]; NSLog(@"Head file path = %@",pathHeadSuper); //首先替换父类模板的内容 NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); NSError* error = nil; NSString* strContenTemplateH = [NSString stringWithContentsOfFile:templatePath1 encoding:enc error:&error];//父类模板本地读取 if (error) { NSLog(@"error = %@",error); } strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"TemplateCCB_CodeFile_Head" withString:g_pTempOutSuperClassName]; strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"//input properties here." withString:strMembers];//成员定义 strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"//input init here." withString:strMembersInit];//变量初始化 strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"//input memberBind here." withString:strMembersBind];//成员绑定 strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"//input menuItemSelector shengming here." withString:strMenuCallBackFun_SuperHead];//函数声明绑定 strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"//input menuItemSelector here." withString:strMenuBinds];//函数绑定 strContenTemplateH = [strContenTemplateH stringByReplacingOccurrencesOfString:@"//input ccb file name here." withString:[NSString stringWithFormat:@"strCCBFileName = \"%@.ccbi\";",g_pTempOutSubClassName ]];//ccb文件 error = nil; [strContenTemplateH writeToFile:pathHeadSuper atomically:NO encoding:enc error:&error]; if (error) { NSLog(@"error = %@",error); } } //替换子类的头文件的内容 if (g_pWantSaveCodeFilePath.length > 0) { NSString* pathHeadSub = [NSString stringWithFormat:@"%@/%@/%@.h",g_pTempRootPath,g_pWantSaveCodeFilePath , g_pTempOutSubClassName ]; NSLog(@"Head file path = %@",pathHeadSub); bool isAllReadyExist = [[NSFileManager defaultManager] fileExistsAtPath:pathHeadSub]; if (!isAllReadyExist) { NSString* templatePath2 = [[NSBundle mainBundle] pathForResource:@"TemplateCCB_CodeFile_h" ofType:@"txt"]; //首先替换父类模板的内容 NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); NSError* error = nil; NSString* strContenTemplateH_sub = [NSString stringWithContentsOfFile:templatePath2 encoding:enc error:&error];//子类 .h 模板 if (error) { NSLog(@"error = %@",error); } strContenTemplateH_sub = [strContenTemplateH_sub stringByReplacingOccurrencesOfString:@"TemplateCCB_CodeFile_Head" withString:g_pTempOutSuperClassName]; strContenTemplateH_sub = [strContenTemplateH_sub stringByReplacingOccurrencesOfString:@"TemplateCCB_CodeFile" withString:g_pTempOutSubClassName]; strContenTemplateH_sub = [strContenTemplateH_sub stringByReplacingOccurrencesOfString:@"//input subclass menu shengming here." withString:strMenuHead]; error = nil; [strContenTemplateH_sub writeToFile:pathHeadSub atomically:NO encoding:enc error:&error]; if (error) { NSLog(@"error = %@",error); } } } //替换子类的cpp 文件的内容 if (g_pWantSaveCodeFilePath.length > 0) { NSString* pathCppSub = [NSString stringWithFormat:@"%@/%@/%@.cpp",g_pTempRootPath,g_pWantSaveCodeFilePath , g_pTempOutSubClassName ]; NSLog(@"Cpp file path = %@",pathCppSub); bool isAllReadyExist = [[NSFileManager defaultManager] fileExistsAtPath:pathCppSub]; if (!isAllReadyExist) { NSString* templatePath3 =[[NSBundle mainBundle] pathForResource:@"TemplateCCB_CodeFile_cpp" ofType:@"txt"]; //首先替换父类模板的内容 NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); NSError* error = nil; NSString* strContenTemplateCPP_sub = [NSString stringWithContentsOfFile:templatePath3 encoding:enc error:&error];//子类 .cpp 模板 if (error) { NSLog(@"error = %@",error); } strContenTemplateCPP_sub = [strContenTemplateCPP_sub stringByReplacingOccurrencesOfString:@"TemplateCCB_CodeFile_Head" withString:g_pTempOutSuperClassName]; strContenTemplateCPP_sub = [strContenTemplateCPP_sub stringByReplacingOccurrencesOfString:@"TemplateCCB_CodeFile" withString:g_pTempOutSubClassName]; strContenTemplateCPP_sub = [strContenTemplateCPP_sub stringByReplacingOccurrencesOfString:@"//input menuItemSelector dingyi here." withString:strMenuCpp]; error = nil; [strContenTemplateCPP_sub writeToFile:pathCppSub atomically:NO encoding:enc error:&error]; if (error) { NSLog(@"error = %@",error); } } } }
模板文件暂不提供