Cocos2d scene loaded with wrong orientation - objective-c

I'm trying to make a cocos2d scene on top of some UIKit views. I understand that the cocos2d 2.0 CCDirector is a subclass of UIViewController so that I can just add that as a subview.
I've written this function to handle switching to a scene in my appDelegate (currently thats
the delegate of my MainWindow.xib following http://www.raywenderlich.com/4817/how-to-integrate-cocos2d-and-uikit):
- (void)switchToScene
{
self.viewController = [CCDirector sharedDirector];
[[CCDirector sharedDirector] view].center = self.window.center;
[self.window addSubview:[self.viewController view]];
[[CCDirector sharedDirector] runWithScene:[CCTransitionSlideInL transitionWithDuration:1 scene:[BattleLayer scene]]];
}
So I'm missing quite a bit from this code. But with this, I get some resemblance of a scene to load http://i.stack.imgur.com/pubWE.png
My question is:
1: If I'm going in the right direction
2: If it is, is the next step to manually adjust the orientation of the scene?
2.1: How do I do this :)

I'm not sure how you want it to look but it seems that the CCDirector's view is rotated 90 degrees CW. This may be because of a few reasons:
you add the view wrong (i.e. rotated 90 degrees CW)
you rotated the device and the CCDirector didn't rotate (in which case you should look at orientation parameters and who and what rotates. It may be that the app rotates but CCDirector doesn't receive the rotation flag).
you can rotate the CCDirector view with CGAffineTransformRotate (i'm not sure..but because CCDirector is a subclass of UIViewController..it should work).

I solved the issue by creating a UINavigationController
- (void)switchToScene:(CCScene *)sceneObj
{
navController_ = [[UINavigationController alloc] initWithRootViewController:director_];
[window_ setRootViewController:navController_];
[[CCDirector sharedDirector] pushScene:sceneObj];
}

Related

SpriteKit: Presenting the initial scene wth a transition

I've created multiple transitions from between my game scenes, so I'm unsure why this code is not working.
In my GameViewController, I am simply setting up my TitleScene to appear as the next scene, but I would like it to fade in. I've done this in my touchesBegan succesfully.
Here is the code:
#implementation GameViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = YES;
// Create and configure the scene.
SKScene * scene = [TitleScene sceneWithSize:skView.frame.size];
scene.scaleMode = SKSceneScaleModeResizeFill;
// Present the scene.
SKTransition *transition = [SKTransition fadeWithColor:[SKColor blackColor] duration:3.6];
[skView presentScene:scene transition:transition];
}
You can't use SpriteKit to present the initial scene with a transition because the SKView is (by definition) not showing any scene before the initial scene, so from its perspective there's nothing for it to transition from.
Presumably, from your point of view, you want to fade into your scene from whatever the user is seeing before SpriteKit gets started — the launch screen of your app, maybe? A common strategy for that is to have the initial storyboard scene contain a UIImageView containing the same image as your launch screen, layered on top of your SKView. When you're ready to start the game, use UIView animateWithDuration:animations:completion: to fade out the image view and remove it from the view hierarchy, and your SKView will be revealed beneath.

How can I set Background image on MyScene in ios7

When I am setting a background image on a SKScene. I have written the code below:
#import "JTEDMyScene.h"
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#interface MyScene()
#property BOOL isContentCreated;
#end
#implementation MyScene
-(void) didMoveToView:(SKView *)view
{
if(!self.isContentCreated)
{
self.isContentCreated = YES;
[self createSceneContent];
}
}
-(void)createSceneContent
{
[self addChild:[self createBackground]];
}
-(SKSpriteNode *)createBackground
{
SKSpriteNode *backgroundSprite;
SKTexture *textureImage;
if (IS_IPAD) {
textureImage = [SKTexture textureWithImageNamed:#"home_ipad1.jpg"];
backgroundSprite = [SKSpriteNode spriteNodeWithTexture:textureImage];
}
backgroundSprite.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
return backgroundSprite;
}
Device orientation modes are only Landscape left and landscape right. My image size is width = 1024 and height= 768 and 264 dpi. But the image is not showing fully a portion of image is showing.
Maq has the right idea. I think what he's saying is, the problem lies in your view controller .m file, instead of in your Scene. Instead of creating your SKView and SKScene and presenting the SKScene from within the viewDidLoad method of your VC, put that code in the viewWillLayoutSubviews method instead. Something along the lines of this:
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
SKView * skView = (SKView *)self.view;
SKScene * scene = [YourScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
Apparently, viewWillLayoutSubviews gets called later than viewDidLoad. When viewDidLoad is called, the view hasn't even been added to the view hierarchy yet.
Ray Wenderlich's Sprite Kit Tutorial for Beginners quotes this answer from SO as to why this happens.
Try to present and create MyScene in viewWillLayoutSubviews - if you haven't done it already.
It may work if you just rename viewDidLoad to viewWillLayoutSubviews and rename the super call too.
I started a blank project and copy-pasted your code into it and it works fine. I know you said you set your device orientation, but did you do that in your project settings? That's the only problem I can think of. Select your project, general tab, and under Deployment Info, there's a "Devices" drop-down box. Select iPad and make sure "Landscape Left" and "Landscape Right" are the only two checked. My guess is that the project thinks it's supposed to be starting in portrait mode, so it's stretching your 768-tall image vertically to 1024 at start; then when your app determines that it's in landscape orientation, it just rotates that stretched image accordingly, which would result in the image being cut off.
yes, to control and resize background image (in my case) correspond to device orientation, you have to use -(void)viewWillLayoutSubviews
but don't forget, it will start from first scene by default, so you need to use some "sceneNumber" selector in this function to point to actual scene

UITapGestureRecognizer every value the same

I'm a newbie to this and remaking an app. I am trying to use UITapGestureRecognizer. It works in the initial project file but not the new one. The only difference is that the old one uses a navigational controller but mine doesn't.
In the new one the self distance:location to:centre is stuck at 640 no matter where you press on the screen.
Can anyone help? I have no idea why it isn't working.
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
CGPoint centre = CGPointMake(512,768 / 2);
NSInteger msg = [self distance:location to:centre];
NSLog(#"location to centre: %d", msg);
if ([self distance:location to:centre] < 330)
The part that looks suspicious to me is [recognizer.view superview].
When the gesture recognizer was added to self.view in a UIViewController that is not inside a container controller (e.g. a Navigation Controller) that view does not have a superview. If you send the superview message to self.view without a container view controller it will return nil.
So your message looked basically like this
CGPoint location = [recognizer locationInView:nil];
This will return the location in the window, which is also a valid CGPoint that tells you were you tapped the screen.
Since this didn't work I guess in [self distance:location to:centre] you do something that does only work with coordinates relative to the view. Maybe it's related to rotation, because the coordinates of the window don't rotate when you rotate the device.
Without knowing your code I'm not sure what the problem is, but it probably doesn't matter.
Just replace [recognizer.view superview] with recognizer.view.
Refer below Link, You may get your answer. It's an example if Gesture Recognition.
http://www.techotopia.com/index.php/An_iPhone_iOS_6_Gesture_Recognition_Tutorial

Is it possible to use cocos2d transitions on a CCNode?

Every example I see on how to use transitions is with CCScene like this:
[[CCDirector sharedDirector] replaceScene:[CCTransitionCrossFade transitionWithDuration:0.5f scene:[NewScene scene]]];
My app is setup with a GameScene, MenuScene ..etc. Within the GameScene I setup the DPad and the HUD and under that I have the hero moving to different levels which are of type CCNode. I want to use the native transitions to move from one level to the next.
I found a question similar to what I need here but that user was essentially told to build the transitions himself.
The confusing part to me is that CCNode contains a method called:
- (void) onEnterTransitionDidFinish
So, is there a way to use transitions with CCNode that I'm missing? Is my app setup incorrectly and the levels should be CCScene? If so how to I keep the HUD and Dpad over the transition?
Thanks in advance for any help.
CCTransitions are specifically for scenes. CCNodes contain onEnterTransitionDidFinish, as it gets called on every CCNode child of a CCScene. Fortunately, you can just check the CCTransition code and see how they are implemented and then roll your own for layers (many have done and shared this).
For example, I wrote a simple little method which will use blocks to give the same fade-in, fade-out effect as a scene transition, but for an individual layer (along with some added features). Just pass in the layer you want to cover up, the speed of the fade out and fade in, the color to fade to, and the block you wish to execute while the layer is hidden.
-(void)fadeLayer:(CCLayer*)layer withOutDuration:(float)outTime inDuration:(float)inTime color:(ccColor3B)color withBlock: (void(^)())block
{
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCLayerColor *toplayer = [CCLayerColor layerWithColor:ccc4(color.r, color.g, color.b, 0) width:winSize.width height:winSize.height];
[layer addChild:toplayer z:INT_MAX];
[toplayer runAction:
[CCSequence actions:
[CCFadeIn actionWithDuration:outTime],
[CCCallBlock actionWithBlock:block],
[CCFadeOut actionWithDuration:inTime],
[CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
}],
nil]
];
}

Trouble with tap detection on CCLayer subclass

I have a CCLayer subclass MyLayer in which I handle touch events:
(BOOL) ccTouchBegan:(UITouch *) touch withEvent:(UIEvent *) event
I set the content size of MyLayer instances like this:
`myLayer.contentSize = CGSizeMake(30.0, 30.0);`
I then add MyLayer instances as children of ParentLayer. For some reason I can tap anywhere on the screen and a MyLayer instance will detect the tap. I want to only detect taps on the visible portion/content size. How can I do this?
Are the MyLayer instances somehow inheriting a "tappable area" from somewhere else? I've verified that the contentSize of the instance just tapped is (30, 30) as expected. Perhaps the contentSize isn't the way to specify the tappable area of CCLayer subclass.
When the touch is enabled on a particular CCLayer, it receives all of the touch events in the window. That being said, if there are multiple layers, all layers will receive the same touches.
To alleviate this, obtain the location from the UITouch, convert it to Cocos2d coordinates, then check to see if it is within the bounds of the Layer you are concerned with.
Here's some code to work with:
CCLayer * ccl = [[CCLayer alloc] init];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
if (CGRectContainsPoint(CGRectMake(ccl.position.x - ccl.contentSize.width/2, ccl.position.y - ccl.contentSize.height/2, ccl.contentSize.width, ccl.contentSize.height), location)) {
//continue from there...
}