I want to add a CCSprite on my UIView, is it possible to do that? What I found were the ways to add UIKit on Cocos2D, but I want the its reverse. I want to add Cocos2D on UIKit.
Any help will be appreciated. Thanks!
You can do this by setting following method in your uiviewcontroller class
- (void)setupCocos2D {
CCGLView *glView = [CCGLView viewWithFrame:CGRectMake(100, 100, 200, 200)
pixelFormat:kEAGLColorFormatRGB565 // kEAGLColorFormatRGBA8
depthFormat:0 // GL_DEPTH_COMPONENT16_OES
];
glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view insertSubview:glView atIndex:0];
[[CCDirector sharedDirector] setView:glView];
CCScene *scene = [StarVideoView scene];
[[CCDirector sharedDirector] runWithScene:scene];
}
and calling this method in your viewDidLoad method as
[self setupCocos2D];
here startVideoView is my ccscene class and ofcourse you have to add cocos2d.h library in your uiviewcontroller class :)
Cocos2D does its drawings inside of a EAGLView class, which is just a wrapper for a CAEAGLLayer. So, you might try creating a director with its associated EAGLView, thendo this to add the cocos2d open gl layer to your view:
[myView.layer addSublayer:[[CCDirector sharedDirector] openGLView].layer];
Related
I am having an issue getting the correct coordinates from a UITouch on an SKScene after the SKScene is presented the second time. I've written a simplified app to demonstrate the issue located here:
https://github.com/JenDobson/SKSceneCoordinatesIssue
In this simplified app there is 1 scene. The scene has a single SKNode. When the scene is touched, if the UITouch location intersects with the SKNode, the touchesEnded:withEvent method calls back to the ViewController to present the scene a second time. But when the scene is presented a second time, when I attempt to touch the SKNode, the coordinates of the UITouch are reversed (i.e. the x value reports the y value and vice versa). They thus don't intersect with the SKNode, and the scene is not presented again. (If I touch at the location on the screen that is the SKNode's position reflected over the line x=y, then I can get the scene to be presented again.)
I've tried playing around with "ViewWillLayoutSubviews", but in this sample app the view is only loaded once, so I believe that ViewWillLayoutSubviews is not called repeatedly and therefore cannot affect the scene coordinates.
To illustrate the issue, here is the output from touchesEnded:withEvent the first time the scene is presented:
2014-07-21 17:57:06.908 TestTouchCoordinatesInSKScene[5476:60b] scene frame size:1024.000000,768.000000
2014-07-21 17:57:06.911 TestTouchCoordinatesInSKScene[5476:60b] location:685.000000,105.500000
2014-07-21 17:57:06.912 TestTouchCoordinatesInSKScene[5476:60b] navNode Position:700.000000,100.000000
And here is the output from touchesEnded:withEvent the second time the scene is presented:
2014-07-21 17:57:14.724 TestTouchCoordinatesInSKScene[5476:60b] scene frame size:1024.000000,768.000000
2014-07-21 17:57:14.725 TestTouchCoordinatesInSKScene[5476:60b] location:107.000000,632.500000
2014-07-21 17:57:14.726 TestTouchCoordinatesInSKScene[5476:60b] navNode Position:700.000000,100.000000
Note that "location" has the x- and y- coordinates reversed for the second listing.
Below is what I think the relevant code is.
In "MyViewController.m"
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
SKView* skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
CGSize contentSize = CGSizeMake(skView.bounds.size.width,skView.bounds.size.height);
_mainMenuScene = [MyMainMenuScene sceneWithSize:contentSize];
_mainMenuScene.controller = self;
_mainMenuScene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:_mainMenuScene];
}
-(void)loadView
{
CGRect viewFrame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
SKView* view = [[SKView alloc] initWithFrame:viewFrame];
self.view = view;
}
-(void)returnToMainMenu
{
[(SKView*)self.view presentScene:_mainMenuScene transition:[SKTransition moveInWithDirection:SKTransitionDirectionRight duration:.3]];
}
#end
In "MyMainMenuScene.m"
-(CGPoint)navNodePosition
{
return CGPointMake(700,100);
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
_navNode = [SKLabelNode node];
_navNode.position = [self navNodePosition];
_navNode.text = #"Return to Main Menu";
_setupLabel.fontColor = [UIColor whiteColor];
_setupLabel.fontSize = 24;
[self addChild:_navNode];
}
return self;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
BOOL shouldSegueToMainMenu = NO;
NSLog(#"scene frame size:%f,%f",self.frame.size.width,self.frame.size.height);
for (UITouch* touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
NSLog(#"location:%f,%f",touchLocation.x,touchLocation.y);
NSLog(#"navNode Position:%f,%f",self.navNode.position.x,self.navNode.position.y);
if ([self.navNode containsPoint:touchLocation]) {
shouldSegueToMainMenu = YES;
break;
}
}
if (shouldSegueToMainMenu)
{
[self.controller returnToMainMenu];
}
}
Thanks very much!
After playing around more, I believe this is a bug in the SKView method presentScene:transition. In the returnToMainMenu method of MyViewController, if I use the plain old presentScene method rather than presentScene:transition, the problem goes away. I've filed this with Apple as bug 17770198.
In my application, I would like to show a movie on the first screen (the first time user opens an application) and when movie is finished running, the login screen should show.
I have two questions:
The way I am trying to do it, is to show the video on a separate controller and when movie is finished, perform segue to the login controller. Is this the correct way to do it?
I am doing performSegueWithIdentifier when I receive MPMoviePlayerPlaybackDidFinishNotification. The problem is that nothing happens. The video remains on the screen and the controller is not changed. I don't see any errors in the console. Is there a problem to perform segue from NSNotificationCenter notification?
A possible way to do this would be to reverse the viewController hierarchy.
Start off with the loginViewController, and have a flag that
determines whether it is the first login. If that is the case, then
have an introVideoViewController presented over the
loginViewController with the loginViewController as its delegate.
Place the code to initiate and present your introVideoViewController
in the viewDidLoad of loginViewController, so it appears that the app
has directly started in the introVideoViewController
With MPMoviePlayerPlaybackDidFinishNotification, perform something like: [self.delegate introVideoDidFinishPlaying];. This will transfer control back to loginViewController, which can then dismiss the presentedViewController.
I'm not familiar how to do it with storyboards, but this approach definitely works with nibs.
As I commented, in your .h file of your loginViewController...
#import <UIKit/UIKit.h>
#import "cocos2d.h"
#import "cocos2d.h"
#interface VPViewController : UIViewController<CCDirectorDelegate>
#property (nonatomic, strong) IBOutlet CCGLView *glView;
In your .m loginViewController...
#synthesize glView=glView_;
In your viewDidLoad method
CGRect glViewFrame = self.glView.frame;
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (screenBounds.size.height == IPHONE_5_SCREEN_SIZE) {
glViewFrame.size.height = 578;
}else{
glViewFrame.size.height = 490;
}
[self.glView setFrame:glViewFrame];
CCDirector *director = [CCDirector sharedDirector];
[director setDisplayStats:NO];
[director setView:glView_];
// Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
if( ! [director enableRetinaDisplay:YES] )
CCLOG(#"Retina Display Not supported");
// turn on multiple touches
[glView_ setMultipleTouchEnabled:YES];
CCScene *scene = [CCScene node];
glClearColor(0,0,0,0);
[scene setRotation:90.0f];
if([director enableRetinaDisplay:YES] && [self returnMaxTextureSize] == 2048){
// this is a device with 2.0 scale factor and a max texture size of 2048 pixels
NSLog(#"2048 only");
[scene setScale:2.0f];
}else{
[scene setScale:1.5f];
}
CCSprite * bg = [CCSprite spriteWithFile:#"login_background_white.png"];
[bg setRotation:-90.0f];
[bg setScale:0.8f];
[bg setPosition:ccp(155, 270)];
[scene addChild:bg z:-1];
[scene addChild: [VPAnimation node]];
[director pushScene:scene];
[director startAnimation];
And finally, in your xib...
So I have my main view where I can do things such as this:
player = [Hero spriteNodeWithImageNamed:#"player.png"];
player.position = CGPointMake(512, 384);
[self addChild:player];
This is done in the GameScene, which is my main scene, its loaded in the view controller like so:
-(void) presentFirstScene
{ // create and present first scene
GameScene* myScene = [GameScene sceneWithSize:self.view.bounds.size];
[self.kkView presentScene:myScene];
}
Now If I have a different class called A (an instance of this class can be found in GameScene) how can I add SKSpriteNodes in A to the main GameScene.
What is easiest/most efficient way of doing this?
Thanks,
Lewis
You can create method in your class A which returns SKSpriteNodes, for example:
// in .m
-(SKSpriteNode*)getHero {
SKSpriteNode *hero = [SKSpriteNode spriteWithImageNamed:#"player.png"];
// Add more customisation here
return hero;
}
And in your GameScene you can call it like that:
SKSpriteNode *hero = [a getHero];
hero.position = CGPointMake(512, 384);
[self addChild: hero];
Remember to add class declaration to .h file:
-(SKSpriteNode*)getHero;
Hope this what you are after.
If A is generating nodes without GameScene explicitly requesting them, then you could use the delegate pattern. Have A call a method on its delegate when it has a new node to add.
I want to load a Cocos3D Scene inside a UIViewController. Currently I have integrate Cocos3D in to my normal iOS project. How can I load Cocos3D scene on to RootViewController's view.
I found a way of using EAGLView. But I do not have a clue about EAGLView and CCDirector. Heres the code currently Im trying.
Is there any other way to do it? Please let me know
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
CCDirector * director = [CCDirector sharedDirector];
[self.view addSubview:[director openGLView]];
cc3Layer = [LR3DLayer layerWithColor:ccc4(100, 100, 100, 255) width:768 height:960];
[cc3Layer scheduleUpdate];
world = [LR3DScene scene];
cc3Layer.cc3Scene = world;
scene = [CCScene node];
[scene addChild: (ControllableCCLayer*)cc3Layer];
if([director runningScene])
[director replaceScene:scene];
else
[director runWithScene:scene];
}
Follow the examples in the AppDelegate implementations in the cocos3d CC3DemoMashUp demo app, or the cocos3d hello, world template app.
cocos3d requires you to use a subclass of CC3UIViewController. The controller will automatically create and use the required CC3GLView view.
I'm pretty new to coding on Xcode (or objective-c in general) and I can't seem to get rid of these errors:
//
// HelloWorldLayer.m
// FirstGame
//
// Created by Kostas on 1/14/12.
// Copyright __MyCompanyName__ 2012. All rights reserved.
//
// Import the interfaces
#import "HelloWorldLayer.h"
#import "GamePlay.h"
// HelloWorldLayer implementation
#implementation HelloWorldLayer
+(id) scene {
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init {
if( (self=[super init] )) {
[CCMenuItemFont setFontName:#"Marker Felt"];
[CCMenuItemFont setFontSize:35];
CCMenuItem *Play = [CCMenuItemFont itemFromString:#"PLAY"
target:self
selector:#selector(gotoGameplay:)];
CCMenu *menu = [CCMenu menuWithItems: Play, nil];
menu.position = ccp(240, 160);
[menu alignItemsVerticallyWithPadding:10];
[self addChild:menu];
}
return self;
}
-(void) goToGameplay: (id) sender {
[[CCDirector sharedDirector]
replaceScene:[[CCTransitionFade
transitionWithDuration:1
scene:[GamePlay node]
]]; **<-----Here is my error it says "Expected identifier"**
}
- (void) dealloc {
[super dealloc];
}
#end
The expected identifier is just what X-Code came up with.
If you count your brackets, you'll see that you have two more opening brackets than closing brackets. I've indented them here so you can see the problem clearly.
-(void) goToGameplay: (id) sender {
[
[CCDirector sharedDirector]
replaceScene:
[ // <-- either this is extra
[CCTransitionFade transitionWithDuration:1
scene:[GamePlay node]
]
];
//]; <-- or this is missing
}
The compiler is trying to tell you that it wasn't expecting to find a semicolon in the middle of a message send expression. I'm not familiar enough with the Cocos2D framework to know what exactly you're trying to do, but at least you can see what problem is.
This line:
[[CCDirector sharedDirector]
replaceScene:[[CCTransitionFade
transitionWithDuration:1
scene:[GamePlay node]
]];
has 5 open brackets and only 4 close brackets. There needs to be the same number (and in the right places). Most likely you need to get rid of one of the two open brackets after replaceScene:.
BTW - why are you using such and old Xcode? You should use the latest - 4.5.1.
Change
[[CCDirector sharedDirector]
replaceScene:[[CCTransitionFade
transitionWithDuration:1
scene:[GamePlay node]
]];
to,
[[CCDirector sharedDirector] replaceScene:
[CCTransitionFade transitionWithDuration:1
scene:[GamePlay node]]];
That should fix the issue. You had an extra [ before [CCTransitionFade transitionWithDuration:1 scene:[GamePlay node]]