My spriteKit game work fine at 60fps but when enabling iAd it drops to 15, sometimes 10 or even lower.. and it's a pain, when I die sometimes it takes a while to reset the scene.
I've ran the analyzer on x-code 6 and I get a lot of low importance warnings:
but also this message:
I've added iAd in the implementation of my viewController.m file like this:
#implementation XYZViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//AUDIO BACKground
NSError *error;
NSURL * backgroundMusicURL = [[NSBundle mainBundle] URLForResource:#"spaceprueba160kbps" withExtension:#"mp3"];
self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
self.backgroundMusicPlayer.numberOfLoops = -1;
[self.backgroundMusicPlayer prepareToPlay];
[self.backgroundMusicPlayer play];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
//iAd
ADBannerView* adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
// adView.delegate = self;
[adView setFrame:CGRectMake(0, 0, 1024, 768)]; // set to your screen dimensions
[adView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:adView];
// self.canDisplayBannerAds = YES;
// Create and configure the scene.
SKScene * scene = [XYZWorld1 sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
I know I should un-comment that line -> // self.canDisplayBannerAds = YES;
but it work fine like this and if I un-comment this line of code, I get a screen without iAdd and with my main camera looking a bit upper than the main screen.
My game don't run in this file but in an instance of SKScene.
So my question is if anybody know how I can get back my 60 fps while keeping iAd on my screen.. ?
Related
Good day!
I do have a problem with performSegueWithIdentifier: in my game.
There are two view controllers "MainMenu" and "GameViewContoller".
My game starts with MainMenu like this:
- (void)viewDidLoad {
[super viewDidLoad];
// Configure the view.
SKView *skView = (SKView *)self.view;
skView.multipleTouchEnabled = NO;
// Create and configure the scene.
self.scene = [Menu sceneWithSize:skView.bounds.size];
self.scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:self.scene];
UILabel *startButton = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.view.frame), CGRectGetMidY(self.view.frame), 100, 40)];
startButton.text = #"Start";
startButton.font = [UIFont fontWithName:#"out" size:20];
// startButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
startButton.textColor = [UIColor yellowColor];
startButton.userInteractionEnabled = YES;
// startButton.fontSize = 20;
// startButton.name = #"Start";
[self.view addSubview: startButton];
UITapGestureRecognizer *startTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(start)];
[startButton addGestureRecognizer: startTap];
// Do any additional setup after loading the view.
}
-(void) start{
UIViewController *vc = self.view.window.rootViewController;
[vc performSegueWithIdentifier:#"Game" sender:nil];
}
so my game is shutting down when [vc performSegueWithIdentifier:#"Game" sender:nil];
my segues configured correct, there is a segue name "Game". Game is running if is not in test mode from Xcode if so i have an error and second controller is not presented.
Any ideas?
I have a game I made using sprite kit and I have added a 30 second audio file to loop infinitely as background music for my game using av audio player. When the game switches from a certain state i want to stop and start the music from the my scene file.
This is my view controller.m file where I have added a stop music method
#implementation ViewController
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
NSError *error;
NSURL *backgroundMusicUrl = [[NSBundle mainBundle] URLForResource:#"game" withExtension:#"wav"];
_backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicUrl error:&error];
_backgroundMusicPlayer.numberOfLoops = -1;
[_backgroundMusicPlayer prepareToPlay];
[_backgroundMusicPlayer play];
SKView * skView = (SKView *)self.view;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
-(void)stopMusic
{
[_backgroundMusicPlayer pause];
}
and then in my my scene.m file I have tried to call the stop music method however the background music does not stop playing.
-(void)switchToTutorial{
[[ViewController alloc] stopMusic];
_gameState = GameStateTutorial;
//remove unwatnted nodes
for (int i = 0; i < _mainMenu.count; i++)
{
SKSpriteNode *chosenNode = [_mainMenu objectAtIndex:i];
[chosenNode removeFromParent];
}
for (int i = 0; i < _mainMenuButtons.count; i++)
{
SKSpriteNode *chosenNode = [_mainMenuButtons objectAtIndex:i];
[chosenNode removeFromParent];
}
[self setupTutorial];
}
The problem is this line:
[[ViewController alloc] stopMusic];
You are creating a new instance of ViewController, but should send the stopMusic message to the current used one.
A way to achieve this, would be to have a property of type ViewController in your scene and set the viewController to it.
In MyScene.h
#class ViewController; //below the #import
...
#property(weak) ViewController *viewController;
In MyScene.m
#import "ViewController.h"
...
[self.viewController stopMusic]
In ViewController.m
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.viewController = self;
The problem of this approach is you will have to pass the ViewController for each scene. Maybe it would be easier to have a static AVAudioPlayer and two static methods to start and stop the music, then you could just call
[ViewController stopMusic];
If you have arrived in that stage, you could think about creating an extra class, i.e. MusicPlayer to handle all music for you. So you would call something like
// in ViewControllers viewDidLoad
[MusicPlayer initializePlayer];
//where needed
[MusicPlayer playMusic];
[MusicPlayer stopMusic];
I'm trying to integrate "admobs" into an scene. I'm trying to do that by doing it viewWillLayoutSubviews in the viewController. I'm trying it out in a blank scene with 0 nodes, so there is nothing that can cause problems in the scene.
The problem is that the ad is not showing in my scene. I'm getting following log message:
To get test ads on this device, call: request.testDevices = #[ GAD_SIMULATOR_ID ];
but i am creating the request in createRequest method.
This is my code:
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
if (!skView.scene) {
self.bannerView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerLandscape];
self.bannerView.adUnitID = #"ca-app-pub-AdId";
self.bannerView.rootViewController = self;
self.bannerView.delegate = self;
self.bannerView.center = CGPointMake(skView.bounds.size.width / 2, skView.bounds.size.height - (bannerView_.frame.size.height / 2));
[self.view addSubview:self.bannerView];
[self.bannerView loadRequest:[GADRequest request]];
// Create and configure the scene.
SKScene * scene = [Menu sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
}
-(GADRequest *)createRequest {
GADRequest *request = [GADRequest request];
request.testDevices = [NSArray arrayWithObjects:GAD_SIMULATOR_ID, nil];
return request;
}
-(void)adViewDidReceiveAd:(GADBannerView *)adView {
NSLog(#"Ad Reveived");
[UIView animateWithDuration:1.0 animations:^{
adView.frame = CGRectMake(0.0, 0.0, adView.frame.size.width, adView.frame.size.height);
}];
}
You need to replace the following code;
[self.bannerView loadRequest:[GADRequest request]];
with:
GADRequest *r = [[GADRequest alloc] init];
r.testing = YES;
[self.bannerView loadRequest:r];
Hope this works for you.
I have added iAds to my Sprite Kit game with the following code:
In the viewController.h file
#property (strong, nonatomic) IBOutlet ADBannerView * adBannerView;
In the viewController.m file
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
if (!skView.scene) {
// Create and configure the scene.
SKScene * scene = [MenuScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
_adBannerView = [[ADBannerView alloc] initWithFrame:CGRectZero];
_adBannerView.delegate = self;
[_adBannerView setFrame:CGRectMake(0, 0, 460, 320)];
[self.view addSubview:_adBannerView];
// Present the scene.
[skView presentScene:scene];
}
}
This shows the iAd in every scene. Is there a way to hide the iAd in some of the scenes?
Apple's iAd Programming Guide says:
Only create a banner view when you intend to display it to the user. Otherwise, it may cycle through ads and deplete the list of available advertising for your application.
Is this at all possible with scenes?
yes there is a way to hide the iAd in some of the scenes.
- (void)viewDidLoad
{
[super viewDidLoad];
//Add view controller as observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"hideAd" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"showAd" object:nil];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
self.canDisplayBannerAds = YES;
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.frame = CGRectOffset(adView.frame, 0, 0.0f);
adView.delegate=self;
[self.view addSubview:adView];
self.bannerIsVisible=NO;
}
//Handle Notification
- (void)handleNotification:(NSNotification *)notification
{
if ([notification.name isEqualToString:#"hideAd"]) {
[self hidesBanner];
} else if ([notification.name isEqualToString:#"showAd"]) {
[self showBanner];
}
}
And in your scene in which you want to hide banner...
[[NSNotificationCenter defaultCenter] postNotificationName:#"showAd" object:nil];
//Sends message to viewcontroller to show ad.
[[NSNotificationCenter defaultCenter] postNotificationName:#"hideAd" object:nil];
//Sends message to viewcontroller to hide ad.
Well, In your specific scene follow the Apple's guide(same place as your question) on this issue at the link below, look at the section that says "banner view best practices":
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/iAd_Guide/WorkingwithBannerViews/WorkingwithBannerViews.html#//apple_ref/doc/uid/TP40009881-CH4-SW3
In Summary they say: "remove the banner view from the view hierarchy, set its delegate to nil"
The most clean solution is to declare and implement a protocol to let the UIViewController know from the scene that it should hide the ad.
#protocol MySceneDelegate <NSObject>
- (void)hideAd;
#end
#interface MyScene : SKScene
#property (weak) id <MySceneDelegate> delegate;
#end
View controller that shows the scene should implement a hideAd method and set itself as a delegate of the scene. Example:
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Set the delegate
[scene setDelegate:self];
// Present the scene.
[skView presentScene:scene];
}
Then in the scene you can call the hideAd method of the view controller which was set as a delegate:
if ([_delegate respondsToSelector:#selector(closeScene)])
{
[_delegate performSelector:#selector(hideAd)];
}
And remove the banner in hideAd method.
To hide the banner view, you should:
Resize your banner view's frame to be offscreen Resize your content
view's frame to cover the space originally hosting the banner
Hope it helps.
I read two questions here about that, both with the same answer. The suggested solution was to create the UIScrollView object, and then add it to the parent view of the SKScene in the target scene's didMoveToView:, removing it in willMoveFromView:.
And that is the target scene code I implemented:
#interface MQSSMakerScene ()
#property BOOL contentCreated;
#property MQSSMakerWorkspaceLayer *workspaceLayer;
#property MQSSMakerDockLayer *dockLayer;
#property UIScrollView *scrollView;
#end
#implementation MQSSMakerScene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
CGSize layerSize = CGSizeMake(944, 140);
CGPoint layerPosition = CGPointMake(40, 768-(140+30));
CGRect viewFrame = CGRectMake(layerPosition.x, layerPosition.y, layerSize.width, layerSize.height);
_scrollView = [[UIScrollView alloc] initWithFrame:viewFrame];
_scrollView.contentSize = CGSizeMake(2000, 120);
_scrollView.scrollEnabled = YES;
_scrollView.showsHorizontalScrollIndicator = YES;
_scrollView.backgroundColor = [UIColor brownColor];
}
return self;
}
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
if(!self.contentCreated) {
[self createSceneContents];
self.contentCreated = YES;
}
[self.view addSubview:_scrollView]; // --> WHERE IT'S BEING ADDED
}
- (void)willMoveFromView:(SKView *)view
{
[super willMoveFromView:view];
[_scrollView removeFromSuperview]; // --> WHERE IT'S BEING REMOVED
}
- (void)createSceneContents
{
self.backgroundColor = [UIColor colorWithHue:.237 saturation:.56 brightness:.46 alpha:1];
self.scaleMode = SKSceneScaleModeAspectFill;
[self addChild:[self newMakerLayout]];
}
- (SKNode *)newMakerLayout
{
SKNode *mainLayout = [[SKNode alloc] init];
self.workspaceLayer = [[MQSSMakerWorkspaceLayer alloc] init];
self.dockLayer = [[MQSSMakerDockLayer alloc] init];
[mainLayout addChild:self.workspaceLayer];
[mainLayout addChild:self.dockLayer];
MQSSStoryObject *ob1 = [[MQSSStoryObject alloc] initWithImageNamed:#"maker-1.png"];
[self.workspaceLayer addChild:ob1];
return mainLayout;
}
#end
Please note that the user should go to this scene from the home scene when clicking on a button. The problem now is that once I add the line:
[self.view addSubview:_scrollView];
to add the UIScrollView object to this scene, the application no more goes to this scene and instead add the UIScrollView to the home scene I am transitioning from. It also doesn't remove it when transitioning to another scene. Once I comment out this line, everything works just as expected, clearly without presenting the UIScrollView.
I am stuck. Any help or advice is highly appreciated. Thanks!
I finally figured out what the problem was for me. I was using the -(void)willLayoutSubviews method of the viewController to ensure I had the correct bounds, but I had forgotten to see if my SKScene was already presented. That resulted in a new welcomeScene being presented each time the view was laid out on top of the old one.
-(void)willLayoutSubviews
{
if(!self.didPresentScene)
{
// Present scene here
....
self.didPresentScene = YES;
}
}