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...
Related
So I have added iAds to my application and I have done this very simply. By importing iAds into the ViewController.h and putting the following code into the ViewController.m file:
self.canDisplayBannerAds = YES;
This works, however, when I the add loads the screen is squished. Where all of the images and sprites become shorter.
Is there any way the add can just be overlaid on top of the SKScene? so that is does not affect the elements below – so that it stops the squishing?
Also, is there a way to only have the banner ads run in certain SKScenes or when a BOOL is changed from YES to NO?
UPDATED
Code from my project:
#import "XYZViewController.h"
#import "XYZMenuScene.h"
#import <iAd/iAd.h>
#implementation XYZViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [XYZMenuScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
//iAds Enabled
self.canDisplayBannerAds = YES;
// Present the scene.
[skView presentScene:scene];
}
This is all I have in terms of the iAds. It makes the entire scene push upwards to make room for the ad banner. Where I want it to just be over the scene and not push anything. So it covers, instead of pushes.
To overlay you can set the Z position of the banner higher than the rest of the content by default it's 0.
eg:
banner.layer.zPosition=2;
but I believe the iAd framework has built in method thats you can override to control when the ads must display and when they shouldn't and give you much more control.
Specific methods are called when the ad is available,and like you said you make the ads appear only when a boolean value is 1 or 0.
eg:
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
if(showADS==1)
{
if (!self.bannerIsVisible)
{
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
// Assumes the banner view is just off the bottom of the screen.
banner.frame = CGRectOffset(banner.frame, 0, -banner.frame.size.height);
[UIView commitAnimations];
self.bannerIsVisible = YES;
}
}
else
{NSlog(#"No ads");}
}
check apple's documentation regarding this,they are really helpful
https://developer.apple.com/library/ios/documentation/userexperience/Conceptual/iAd_Guide/WorkingwithBannerViews/WorkingwithBannerViews.html
But let give a complete example.
The banner instance is only available in you iAd Methods not outside them.
In your view did load method:
- (void)viewDidLoad
{
self.canDisplayBannerAds=YES;
}
This method is called when the ad is loaded,in this method specify the position of the ad
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
banner.layer.zPosition=2;
/*do all the additional like checking is the boolean is 1 or 0 etc.*/
}
If you are working with iAd and sprite kit,you need to call methods in your view controller from the scene class to do all the ad work.
Suppose you have a method named checkAD in your view controller that checks if the ad should shown or not etc..
You can call this method from your scene class by using this code
if([self.delegate respondsToSelector:#selector(checkAD)]){
[self.delegate checkAD];
}
Add the SKSCene in a container View that might help. From my experience any Apple subclasses of UIViewController can do weird stuff when iAds are added through canDisplayBannerAds.
I have a scene where the user chooses level in a game, then i want to switch to a game scene with the level the user chose. I want to create the game scene with the right level but to do this i need to pass an integer which is the level-number to the game scene so i know which level to load.
My question is, how do i accomplish this? I have looked at the userdata property of nodes but could not figure out how to use it to accomplish what i want. Any help would be deeply appreciated.
When you call [self.view presentScene:scene transition:transition] inside of your level selection scene, first set up your new scene with the level number. SO:
//GameScene.h
//This is the public interface for your game scene
#import SpriteKit;
#interface GameScene : SKScene
#property (nonatomic, assing)NSInteger levelNumber;
#end
And then
//Level Selection Scen
//Select.m
#import "GameScene.h"
... Rest of your code
User selects level and you prepare for transition and call
- (void)transitionToLevel:(NSInteger)level{
GameScene *destinationScene = [[GameScene alloc] initWithSize:self.size];
destinationScene.levelNumber = level;
SKTransition *transition = //Set up transition here
[self.view presentScene:destinationScene transition:transition];
}
And in your game scene's implementation
//GameScene.m
#import "GameScene.h"
#implementation GameScene
-(id)initWithSize:(CGSize){
if (self.levelNumber == 1){
[self playLevelOne]; //Where this is where you play your game
}
else if (self.levelNumber == 2){
[self playLevelTwo];
}
}
- (void)playLevelOne{
//Level Implementation
}
- (void)playLevelTwo{
//Level Implementation
}
#end
You would do this for each level you plan to support
// First Scene
NSUserDefaults.standardUserDefaults().setInteger(12345, forKey:"SCORE")
// Second Scene
if let myScore: AnyObject = NSUserDefaults.standardUserDefaults().objectForKey("SCORE") {
println(myScore)
finalScore = myScore as IntegerLiteralType
}
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 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];
Situation:
I'm getting some mysterious crashing shortly after a CCCallFunc. In short, we have a button. The button has a tag to identify it later. When the button is pressed, we run some actions to animate it, and when the animation is done, we CCCallFunc another method to transition to another scene. We crash shortly after the CCCallFunc. Source and errors below.
Point Of Crash (in cocos2d source):
// From CCActionInstant.m of cocos2d
-(void) execute
{
/*** EXC_BAD_ACCESS on line 287 of CCActionInstant.m ***/
[targetCallback_ performSelector:selector_];
}
#end
Snapshot of Thread 1:
My Code:
Below is some source taken from MenuLayer.m (a simple menu to display a button).
// from MenuLayer.m
// …
#implementation MenuLayer
-(id) init{
if((self=[super init])) {
/****** Create The Play Button (As a CCMenu) ********/
CCSprite *playSprite = [CCSprite spriteWithFile:#"playbutton.png"];
CCMenuItemSprite *playItem = [CCMenuItemSprite itemFromNormalSprite:playSprite selectedSprite:nil target:self selector:#selector(animateButton:)];
playItem.tag = 3001;
playItem.position = ccp(160.0f, 240.0f);
CCMenu *menu = [CCMenu menuWithItems:playItem, nil];
menu.position = ccp(0.0f, 0.0f);
[self addChild:menu z:0];
}
}
// ...
- (void)animateButton:(id)sender{
/*** Run an animation on the button and then call a function ***/
id a1 = [CCScaleTo actionWithDuration:0.05 scale:1.25];
id a2 = [CCScaleTo actionWithDuration:0.05 scale:1.0];
id aDone = [CCCallFunc actionWithTarget:self selector:#selector(animationDone:)];
[sender runAction:[CCSequence actions:a1,a2,aDone, nil]];
}
- (void)animationDone:(id)sender{
/*** Identify button by tag ***/
/*** Call appropriate method based on tag ***/
if([(CCNode*)sender tag] == 3001){
/*** crashes around here (see CCActionInstant.m) ***/
[self goGame:sender];
}
}
-(void)goGame:(id)sender{
/*** Switch to another scene ***/
CCScene *newScene = [CCScene node];
[newScene addChild:[StageSelectLayer node]];
if ([[CCDirector sharedDirector] runningScene]) {
[[CCDirector sharedDirector] replaceScene:newScene]];
}else {
[[CCDirector sharedDirector] runWithScene:newScene];
}
}
Use CCCallFuncN instead of CCCallFun.
CCCallFuncN passes the Node as parameter, the problem with CCCallFun is that you are loosing reference of the node.
I test your code with CCCallFuncN and works ok.
Just a hunch. Besides checking for memory leaks, try to schedule a selector with a 0 second interval instead of directly sending the goGame message. I have a suspicion that director's replaceScene causes a cleanup of the scene and all objects associated with it. That in turn could leave the CCCallFunc action in an undefined state. Although normally it works fine - which is to say that this is just another indication about something sketchy, memory- respectively object-lifetime-management-wise.
Btw, if you support iOS 4 as a minimum, use CCCallBlock instead of CCCallFunc. That's safer and cleaner.