Firstly, I would like to say how I really appreciate the whole cocos2d develop team. Your high performance package helped me finish an impossible mission. Our cocos2d package is pretty easy to manage and code with very little bugs. Specially when we want to use some animations, it is really perfect.
I want to use cocos2d lib as my root develop platform instead of UIView family. But the problem here is that UIKit cannot be managed by CocosNode family, it can only be managed manually.
But there's still some simple view & component that can be used for game development. Specially UITextView, UIProgressbar and so on.
I am thinking about how to merge these 2 families into 1, and let UIView family be easily managed by CCDirector.
Here is my point (I need to verify it by testing it later):
-(BOOL)initOpenGLViewWithView:(UIView *)view withFrame: (CGRect)rect
After that, I think it is ok to show 'UIView' on Cocos2D games. I couldn't solve the following bug (take care while coding):
[scene addChild : [SubLayer1 node] z:0]; [scene addChild : [SubUIViewNode node] z:0]; [scene addChild : [SubLabel node] z:0];
Below is the final source code for the 'UIKitLayer' class.
@interface UIKitLayer : CocosNode { UIView * pView; } -(void) addChild : (UIView *) subView; -(void) setFrame : (CGRect) frame; -(void) setBackgroundColor : (UIColor *)color; @end @implementation UIKitLayer -(id) init { self = [super init]; pView = [[UIView alloc]initWithFrame : CGRectMake(0,0,1,1)]; [pView setBackgroundColor: [UIColor clearColor]]; [pView setCenter: cpv(0,0)]; [super setPosition: cpv(0,0)]; [[[Director sharedDirector] openGLView] addSubview:pView]; NSLog(@"pView inserted"); return self; } -(void) dealloc { if(pView) { NSLog(@"pView deallocing"); [pView removeFromSuperview]; [pView release]; } [super dealloc]; } -(void) addChild : (UIView *) subView { NSAssert(pView,@"subView must be valid"); [pView addSubview: subView]; } -(id) addChild: (CocosNode*)node z:(int)z { NSAssert(false,@"This function is not allowed!"); return nil; } -(id) addChild: (CocosNode*)node z:(int)z tag:(int)tag { NSAssert(false,@"This function is not allowed!"); return nil; } -(id) addChild: (CocosNode*)node z:(int)z parallaxRatio:(cpVect)c { NSAssert(false,@"This function is not allowed!"); return nil; } -(void) insertChild:(CocosNode*) child z:(int)z { NSAssert(false,@"This function is not allowed!"); } -(void) reorderChild:(CocosNode*) child z:(int)z { NSAssert(false,@"This function is not allowed!"); } -(void) setVisible : (bool) agv { super.visible = agv; pView.hidden = !agv; } -(void) setPosition : (CGPoint) point { [super setPosition: point]; [pView setCenter: point]; } -(void) setFrame : (CGRect) frame { [pView setFrame: frame]; } -(void) setBackgroundColor : (UIColor *)color { [pView setBackgroundColor: color]; } @end
There are some key points that we need to be aware of.
1. If we want to use landscape mode, we need to customize our View Coordinate System from the View Controller. In this situation, no need to call [Director setLandscape]. I have created a viewController view based on a custom coordinate. You can get a reference from the iPhone Sample “Which Way is Up”.
Below is a customized applicationDidFinishLaunching.
//auto load viewController & window in MainWindow.XIB @interface CocosDetectiveViewController : UIViewController { } @end @interface CocosDetectiveAppDelegate : NSObject { CocosDetectiveViewController * viewController; UIWindow *window; } @property (nonatomic, retain) UIWindow *window; @property (nonatomic, retain) CocosDetectiveViewController *viewController; @implementation CocosDetectiveAppDelegate @synthesize window; @synthesize viewController; - (void)applicationDidFinishLaunching:(UIApplication *)app{ app.statusBarHidden = YES; // Override point for customization after app launch [window addSubview: viewController.view ]; // show FPS [[Director sharedDirector] setDisplayFPS:YES]; // frames per second [[Director sharedDirector] setAnimationInterval:1.0/60]; // attach cocos2d to a window, if we need play game under landscape mode,don't call attachInWindow // and no need to call [Director setLandscape] function anymore [[Director sharedDirector] attachInView: viewController.view withFrame: CGRectMake(0,0,480,320)]; [[Director sharedDirector] runWithScene: [MenuScene node]]; } -(void) dealloc{ [viewController release]; [window release]; [super dealloc]; } // getting a call, pause the game -(void) applicationWillResignActive:(UIApplication *)application { [[Director sharedDirector] pause]; } // call got rejected -(void) applicationDidBecomeActive:(UIApplication *)application { [[Director sharedDirector] resume]; } // purge memroy - (void)applicationDidReceiveMemoryWarning:(UIApplication *) application { [[TextureMgr sharedTextureMgr] removeAllTextures]; } // next delta time will be zero -(void) applicationSignificantTimeChange:(UIApplication *)application { [[Director sharedDirector] setNextDeltaTimeZero:YES]; } @end @implementation CocosDetectiveViewController - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation { //turn iphone to landscape mode return interfaceOrientation == UIInterfaceOrientationLandscapeRight; } @end
2. How to implement a UIKitLayer’s subclass.
// subView need be manually released while dealloc to avoid memory leak. @interface AboutScene : Scene{ } @end @interface AboutLayer : UIKitLayer{ UITextView *contentView; } @end @implementation AboutScene - (id) init { self = [super init]; //create images Sprite * bg = [Sprite spriteWithFile:@"liuqianru.png"]; [bg setPosition:cpv(100, 160)]; [self addChild:bg z:0]; //create button [MenuItemFont setFontSize:24]; [MenuItemFont setFontName:@"Helvetica"]; MenuItem *back = [MenuItemFont itemFromString:@"Back" target:self selector:@selector(tapBack:)]; Menu *menu = [Menu menuWithItems:back, nil]; [menu alignItemsVertically]; [self addChild:menu]; [back setPosition: cpv(100,20)]; [menu setPosition: cpv(0,0)]; //create title Label * title = [Label labelWithString : @"About" fontName : @"Helvetica" fontSize : 20]; [title setRGB: 0xFF : 0xFF :0x00]; [self addChild : title]; [title setPosition: cpv(240,300)]; //create content [self addChild : [AboutLayer node]]; return self; } -(void) tapBack : (id) sender { [[Director sharedDirector]replaceScene:[MenuScene node]]; } @end @implementation AboutLayer -(id) init { self = [super init]; //very important, need set same size or larger than subviews. [self setFrame: CGRectMake(0, 0, 280, 260)]; [self setPosition: cpv(320,170)]; UITextView *view = [[UITextView alloc] initWithFrame:CGRectMake(0,0, 280, 260)]; view.font = [UIFont systemFontOfSize:12.0]; view.textColor = [UIColor whiteColor]; view.backgroundColor = [UIColor clearColor]; view.textAlignment = UITextAlignmentLeft; view.editable = FALSE; view.text = NSLocalizedStringFromTable(@"AboutContent",@"resource",nil); [self addChild: view]; contentView = view; return self; } -(void) dealloc { //need manual release subviews [contentView removeFromSuperview]; [contentView release]; [super dealloc]; } @end
3. Please notice that the UIKitLayer's setFrame method is used to define the echo rect. All subview’s rects must be contained in the UIKeyLayer rect.
[self setBackgroundColor:[UIColor greenColor]] to double check, otherwise UIKit tap/touch action can not be caught by UIKitLayer. @implementation AboutLayer -(id) init { self = [super init]; //This action is very important, and also spent me very long time //to find the root cause why system can not receive scroll action. [self setFrame: CGRectMake(0, 0, 280, 260)]; UITextView *view = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 280, 260)]; }
There are still somethings I couldn't solve.