I started to learn Objective-C and use cocos2D about 1 month ago.
I want to replace three different layers by tapping buttons.
At first, I tried to use "CCLayerMultiplex." Then, use "if sentence." But then the layers just overlap or crash when the buttons are tapped. I want the previous layer to disappear when the new layer appears, but the old layer remains with my code now.
I think using "CCLayerMultiplex" is my best option, but I can't make it work as I want it to.
Below is my code. I'm afraid that there're some poor sentences...
#interface GSLayout : CCLayer {
// button items
CCMenuItemImage *file1;
CCMenuItemImage *file1Pushed;
...
// Layer (replace)
CCLayer *layer1;
CCLayer *layer2;
CCLayer *layer3;
// replace layers
CCLayerMultiplex* mpLayer;
}
#end
#implementation GSLayout
-(id) init{
if( (self=[super init])) {
CCLOG(#"%#: %#", NSStringFromSelector(_cmd), self);
self.isTouchEnabled = YES;
// buttons
file1 = [CCMenuItemImage itemFromNormalImage:#"Icon-Small-50.png"
selectedImage: #"Icon-Small.png"
target:nil
selector:nil];
file1Pushed = [CCMenuItemImage itemFromNormalImage:#"Icon-Small.png"
selectedImage:#"Icon-Small-50.png"
target:nil
selector:nil];
CCMenuItemToggle *toggleFile1 = [CCMenuItemToggle itemWithTarget:self
selector:#selector(selectOne:)
items:file1,file1Pushed, nil];
toggleFile1.anchorPoint = CGPointMake(0.5f, 0.5f);
file2 = [[CCMenuItemImage itemFromNormalImage:#"Icon-Small-50.png"
selectedImage: #"Icon-Small.png"
target:nil
selector:nil]retain];
file2Pushed = [[CCMenuItemImage itemFromNormalImage:#"Icon-Small.png"
selectedImage:#"Icon-Small-50.png"
target:nil
selector:nil]retain];
CCMenuItemToggle *toggleFile2 = [CCMenuItemToggle itemWithTarget:self
selector:#selector(selectTwo:)
items:file2,file2Pushed, nil];
toggleFile2.anchorPoint = CGPointMake(0.5f, 0.5f);
...
CCMenu *toggleMenu = [CCMenu menuWithItems:toggleFile1,toggleFile2,toggleFile3, nil];
[toggleMenu alignItemsHorizontally];
toggleMenu.anchorPoint = CGPointMake(0, 1.0f);
CGSize screenSize = [[CCDirector sharedDirector] winSize];
toggleMenu.position = CGPointMake(screenSize.width/2, screenSize.height);
[self addChild:toggleMenu];
// create layers
layer1 = [GameFile1 node];
layer2 = [GameFile2 node];
layer3 = [GameFile3 node];
mpLayer = [CCLayerMultiplex layerWithLayers:layer1,layer2,layer3, nil];
}
return self;
}
- (void) selectOne: (CCMenuItem*) menuItem
{
NSLog(#"The first menu was called");
if([layer1 isRunning])
{
nil;
NSLog(#"The layer1 is running");
} else if([layer2 isRunning]) {
[mpLayer switchTo:0];
NSLog(#"The layer2 was replaced");
}else if([layer3 isRunning]) {
[mpLayer switchTo:0];
NSLog(#"The layer3 was replaced");
} else{
[self addChild:layer1];
NSLog(#"The layer1 was called");
}
}
- (void) selectTwo: (CCMenuItem*) menuItem
{
NSLog(#"The second menu was called");
if([layer2 isRunning])
{
nil;
NSLog(#"The layer2 is running");
} else if([layer1 isRunning]) {
[mpLayer switchTo:1];
NSLog(#"The layer1 was replaced");
} else if([layer3 isRunning]) {
[mpLayer switchTo:1];
NSLog(#"The layer3 was replaced");
}else{
[self addChild:layer2];
NSLog(#"The layer2 was called");
}
}
- (void) selectThree: (CCMenuItem*) menuItem
{
NSLog(#"The third menu was called");
...
}
Please give me some advice!
Thank you in advance!
I'll add some codes.
#interface GameFile1 : CCLayer {
CCSprite* sprite;
}
#implementation GameFile1
-(id) init{
if( (self=[super init])) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CCMenuItemImage *soundItem1 = [CCMenuItemImage itemFromNormalImage:#"button1.png"
selectedImage: #"Icon.png"
target:self
selector:#selector(doSomethingOne:)];
CCMenuItemImage *soundItem2 = [CCMenuItemImage itemFromNormalImage:#"button2.png"
selectedImage: #"Icon.png"
target:self
selector:#selector(doSomethingTwo:)];
...
CCMenu * myMenu = [CCMenu menuWithItems:soundItem1, soundItem2,soundItem3,soundItem4, soundItem5,soundItem6,soundItem7, soundItem8,soundItem9,soundItem10,soundItem11,soundItem12, nil];
[myMenu alignItemsInRows:[NSNumber numberWithInt:4],[NSNumber numberWithInt:4],[NSNumber numberWithInt:4] ,nil];
myMenu.position = CGPointMake(370, 120);
[self addChild:myMenu];
sprite = [CCSprite spriteWithFile:#"o0400026611355530621.jpg"];
sprite.scale = 0.5f;
sprite.position = CGPointMake(screenSize.width/2, screenSize.height/2);
sprite.anchorPoint = CGPointMake(1.0f, 0);
[self addChild:sprite];
- (void) doSomethingOne: (CCMenuItem *) menuItem
{
NSLog(#"The first menu was called");
[[SimpleAudioEngine sharedEngine] playEffect:#"one.wav"];
[sprite setTexture:[[CCTextureCache sharedTextureCache] addImage: #"one.jpg"]];
}
- (void) doSomethingTwo: (CCMenuItem *) menuItem
{
NSLog(#"The second menu was called");
[[SimpleAudioEngine sharedEngine] playEffect:#"two.wav"];
[sprite setTexture:[[CCTextureCache sharedTextureCache] addImage: #"one.jpg"]];
}
...
#end
Since you have already loaded the textures for all three layers, you might as well have all three sitting in separate CCLayers where two are hidden at any given state using a method similar to:
- (void) setLayer:(uint)show {
layerOne.visible = (show == 0);
layerTwo.visible = (show == 1);
layerThree.visible = (show == 2);
}
Related
I tried to play video advertisements using the Custom Vast tag in the Google IMA integration application on macOS 12.0.1 and Xcode 13.1 but it gives the below error. I tried somany ways to but couldn't fix it. info.plist file I have shown below.
AdvancedExample[1476:21763] Error loading ads: Ads cannot be requested
because this AdsLoader failed to load
info.plist
VideoViewController.m
#import "VideoViewController.h"
#import AVFoundation;
#import "Constants.h"
typedef enum { PlayButton, PauseButton } PlayButtonType;
#interface VideoViewController () <AVPictureInPictureControllerDelegate, IMAAdsLoaderDelegate,
IMAAdsManagerDelegate, UIAlertViewDelegate>
// Tracking for play/pause.
#property(nonatomic) BOOL isAdPlayback;
// Play/Pause buttons.
#property(nonatomic, strong) UIImage *playBtnBG;
#property(nonatomic, strong) UIImage *pauseBtnBG;
// PiP objects.
#property(nonatomic, strong) AVPictureInPictureController *pictureInPictureController;
#property(nonatomic, strong) IMAPictureInPictureProxy *pictureInPictureProxy;
// Storage points for resizing between fullscreen and non-fullscreen
/// Frame for video player in fullscreen mode.
#property(nonatomic, assign) CGRect fullscreenVideoFrame;
/// Frame for video view in portrait mode.
#property(nonatomic, assign) CGRect portraitVideoViewFrame;
/// Frame for video player in portrait mode.
#property(nonatomic, assign) CGRect portraitVideoFrame;
/// Frame for controls in fullscreen mode.
#property(nonatomic, assign) CGRect fullscreenControlsFrame;
/// Frame for controls view in portrait mode.
#property(nonatomic, assign) CGRect portraitControlsViewFrame;
/// Frame for controls in portrait mode.
#property(nonatomic, assign) CGRect portraitControlsFrame;
/// Option for tracking fullscreen.
#property(nonatomic, assign) BOOL fullscreen;
/// Option for tracking load event
#property(nonatomic, assign) BOOL didRequestAds;
/// Gesture recognizer for tap on video.
#property(nonatomic, strong) UITapGestureRecognizer *videoTapRecognizer;
// IMA objects.
#property(nonatomic, strong) IMAAdsManager *adsManager;
#property(nonatomic, strong) IMACompanionAdSlot *companionSlot;
// Content player objects.
#property(nonatomic, strong) AVPlayer *contentPlayer;
#property(nonatomic, strong) AVPlayerLayer *contentPlayerLayer;
#property(nonatomic, strong) id playHeadObserver;
#end
#implementation VideoViewController
#pragma mark Set-up methods
// Set up the new view controller.
- (void)viewDidLoad {
[super viewDidLoad];
[self.topLabel setText:self.video.title];
// Set the play button image.
self.playBtnBG = [UIImage imageNamed:#"play.png"];
// Set the pause button image.
self.pauseBtnBG = [UIImage imageNamed:#"pause.png"];
self.isAdPlayback = NO;
self.fullscreen = NO;
self.didRequestAds = NO;
// Fix iPhone issue of log text starting in the middle of the UITextView
self.automaticallyAdjustsScrollViewInsets = NO;
// Set up CGRects for resizing the video and controls on rotate.
CGRect videoViewBounds = self.videoView.bounds;
self.portraitVideoViewFrame = self.videoView.frame;
self.portraitVideoFrame =
CGRectMake(0, 0, videoViewBounds.size.width, videoViewBounds.size.height);
CGRect videoControlsBounds = self.videoControls.bounds;
self.portraitControlsViewFrame = self.videoControls.frame;
self.portraitControlsFrame =
CGRectMake(0, 0, videoControlsBounds.size.width, videoControlsBounds.size.height);
// Set videoView on top of everything else (for fullscreen support).
[self.view bringSubviewToFront:self.videoView];
[self.view bringSubviewToFront:self.videoControls];
// Check orientation, set to fullscreen if we're in landscape
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft ||
[[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight) {
[self viewDidEnterLandscape];
}
// Set up content player and IMA classes, then request ads. If the user selected "Custom",
// get the ad tag from the pop-up dialog.
[self setUpContentPlayer];
[self setUpIMA];
}
// Makes the request on first appearance only.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.didRequestAds) {
return;
}
self.didRequestAds = YES;
if ([self.video.tag isEqual:#"custom"]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Tag"
message:#"Enter your test tag below"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
} else {
[self requestAdsWithTag:self.video.tag];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[self.contentPlayer pause];
// Don't reset if we're presenting a modal view (for example, in-app clickthrough).
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
if (self.adsManager) {
[self.adsManager destroy];
self.adsManager = nil;
}
[self removeObservers];
self.contentPlayer = nil;
}
[super viewWillDisappear:animated];
}
//Remove ContentPlayer Observer
- (void)removeObservers {
if (self.playHeadObserver) {
[self.contentPlayer removeTimeObserver:self.playHeadObserver];
self.playHeadObserver = nil;
}
#try {
[self.contentPlayer removeObserver:self forKeyPath:#"rate"];
[self.contentPlayer removeObserver:self forKeyPath:#"currentItem.duration"];
} #catch (NSException *exception) { }
}
// If pop-up dialog was shown, request ads with provided tag on dialog close.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
[self requestAdsWithTag:[[alertView textFieldAtIndex:0] text]];
}
// Initialize the content player and load content.
- (void)setUpContentPlayer {
// Load AVPlayer with path to our content.
NSURL *contentURL = [NSURL URLWithString:self.video.video];
self.contentPlayer = [AVPlayer playerWithURL:contentURL];
// Playhead observers for progress bar.
__weak VideoViewController *controller = self;
self.playHeadObserver = [controller.contentPlayer
addPeriodicTimeObserverForInterval:CMTimeMake(1, 30)
queue:NULL
usingBlock:^(CMTime time) {
CMTime duration = [controller
getPlayerItemDuration:controller.contentPlayer.currentItem];
[controller updatePlayHeadWithTime:time duration:duration];
}];
[self.contentPlayer addObserver:self forKeyPath:#"rate" options:0 context:#"contentPlayerRate"];
[self.contentPlayer addObserver:self
forKeyPath:#"currentItem.duration"
options:0
context:#"playerDuration"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(contentDidFinishPlaying:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:self.contentPlayer.currentItem];
// Set up fullscreen tap listener to show controls.
self.videoTapRecognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(showFullscreenControls:)];
[self.videoView addGestureRecognizer:self.videoTapRecognizer];
// Create a player layer for the player.
self.contentPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.contentPlayer];
// Size, position, and display the AVPlayer.
self.contentPlayerLayer.frame = self.videoView.layer.bounds;
[self.videoView.layer addSublayer:self.contentPlayerLayer];
// Set ourselves up for PiP.
self.pictureInPictureProxy =
[[IMAPictureInPictureProxy alloc] initWithAVPictureInPictureControllerDelegate:self];
self.pictureInPictureController =
[[AVPictureInPictureController alloc] initWithPlayerLayer:self.contentPlayerLayer];
self.pictureInPictureController.delegate = self.pictureInPictureProxy;
if (![AVPictureInPictureController isPictureInPictureSupported] && self.pictureInPictureButton) {
self.pictureInPictureButton.hidden = YES;
}
}
// Handler for keypath listener that is added for content playhead observer.
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if (context == #"contentPlayerRate" && self.contentPlayer == object) {
[self updatePlayHeadState:(self.contentPlayer.rate != 0)];
} else if (context == #"playerDuration" && self.contentPlayer == object) {
[self
updatePlayHeadDurationWithTime:[self getPlayerItemDuration:self.contentPlayer.currentItem]];
}
}
#pragma mark UI handlers
// Handle clicks on play/pause button.
- (IBAction)onPlayPauseClicked:(id)sender {
if (!self.isAdPlayback) {
if (self.contentPlayer.rate == 0) {
[self.contentPlayer play];
} else {
[self.contentPlayer pause];
}
} else {
if (self.playHeadButton.tag == PlayButton) {
[self.adsManager resume];
[self setPlayButtonType:PauseButton];
} else {
[self.adsManager pause];
[self setPlayButtonType:PlayButton];
}
}
}
// Updates play button for provided playback state.
- (void)updatePlayHeadState:(BOOL)isPlaying {
[self setPlayButtonType:isPlaying ? PauseButton : PlayButton];
}
// Sets play button type.
- (void)setPlayButtonType:(PlayButtonType)buttonType {
self.playHeadButton.tag = buttonType;
[self.playHeadButton setImage:buttonType == PauseButton ? self.pauseBtnBG : self.playBtnBG
forState:UIControlStateNormal];
}
// Called when the user seeks.
- (IBAction)playHeadValueChanged:(id)sender {
if (![sender isKindOfClass:[UISlider class]]) {
return;
}
if (self.isAdPlayback == NO) {
UISlider *slider = (UISlider *)sender;
// If the playhead value changed by the user, skip to that point of the
// content is skippable.
[self.contentPlayer seekToTime:CMTimeMake(slider.value, 1)];
}
}
// Used to track progress of ads for progress bar.
- (void)adDidProgressToTime:(NSTimeInterval)mediaTime totalTime:(NSTimeInterval)totalTime {
CMTime time = CMTimeMakeWithSeconds(mediaTime, 1000);
CMTime duration = CMTimeMakeWithSeconds(totalTime, 1000);
[self updatePlayHeadWithTime:time duration:duration];
self.progressBar.maximumValue = totalTime;
}
// Get the duration value from the player item.
- (CMTime)getPlayerItemDuration:(AVPlayerItem *)item {
CMTime itemDuration = kCMTimeInvalid;
if ([item respondsToSelector:#selector(duration)]) {
itemDuration = item.duration;
} else {
if (item.asset && [item.asset respondsToSelector:#selector(duration)]) {
// Sometimes the test app hangs here for ios 4.2.
itemDuration = item.asset.duration;
}
}
return itemDuration;
}
// Updates progress bar for provided time and duration.
- (void)updatePlayHeadWithTime:(CMTime)time duration:(CMTime)duration {
if (CMTIME_IS_INVALID(time)) {
return;
}
Float64 currentTime = CMTimeGetSeconds(time);
if (isnan(currentTime)) {
return;
}
self.progressBar.value = currentTime;
self.playHeadTimeText.text =
[[NSString alloc] initWithFormat:#"%d:%02d", (int)currentTime / 60, (int)currentTime % 60];
[self updatePlayHeadDurationWithTime:duration];
}
// Update the current playhead duration.
- (void)updatePlayHeadDurationWithTime:(CMTime)duration {
if (CMTIME_IS_INVALID(duration)) {
return;
}
Float64 durationValue = CMTimeGetSeconds(duration);
if (isnan(durationValue)) {
return;
}
self.progressBar.maximumValue = durationValue;
self.durationTimeText.text = [[NSString alloc]
initWithFormat:#"%d:%02d", (int)durationValue / 60, (int)durationValue % 60];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
switch (interfaceOrientation) {
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
[self viewDidEnterPortrait];
break;
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationPortraitUpsideDown:
[self viewDidEnterLandscape];
break;
case UIInterfaceOrientationUnknown:
break;
}
}
- (void)viewDidEnterLandscape {
self.fullscreen = YES;
CGRect screenRect = [[UIScreen mainScreen] bounds];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
self.fullscreenVideoFrame = CGRectMake(0, 0, screenRect.size.height, screenRect.size.width);
self.fullscreenControlsFrame =
CGRectMake(0, (screenRect.size.width - self.videoControls.frame.size.height),
screenRect.size.height, self.videoControls.frame.size.height);
} else {
self.fullscreenVideoFrame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
self.fullscreenControlsFrame =
CGRectMake(0, (screenRect.size.height - self.videoControls.frame.size.height),
screenRect.size.width, self.videoControls.frame.size.height);
}
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
[[self navigationController] setNavigationBarHidden:YES];
self.videoView.frame = self.fullscreenVideoFrame;
self.contentPlayerLayer.frame = self.fullscreenVideoFrame;
self.videoControls.frame = self.fullscreenControlsFrame;
self.videoControls.hidden = YES;
}
- (void)viewDidEnterPortrait {
self.fullscreen = NO;
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
[[self navigationController] setNavigationBarHidden:NO];
self.videoView.frame = self.portraitVideoViewFrame;
self.contentPlayerLayer.frame = self.portraitVideoFrame;
self.videoControls.frame = self.portraitControlsViewFrame;
}
- (IBAction)videoControlsTouchStarted:(id)sender {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(hideFullscreenControls)
object:self];
}
- (IBAction)videoControlsTouchEnded:(id)sender {
[self startHideControlsTimer];
}
- (void)showFullscreenControls:(UITapGestureRecognizer *)recognizer {
if (self.fullscreen) {
self.videoControls.hidden = NO;
self.videoControls.alpha = 0.9;
[self startHideControlsTimer];
}
}
- (void)startHideControlsTimer {
[self performSelector:#selector(hideFullscreenControls) withObject:self afterDelay:3];
}
- (void)hideFullscreenControls {
[UIView animateWithDuration:0.5
animations:^{
self.videoControls.alpha = 0.0;
}];
}
- (IBAction)onPipButtonClicked:(id)sender {
if ([self.pictureInPictureController isPictureInPictureActive]) {
[self.pictureInPictureController stopPictureInPicture];
} else {
[self.pictureInPictureController startPictureInPicture];
}
}
#pragma mark IMA SDK methods
// Initialize ad display container.
- (IMAAdDisplayContainer *)createAdDisplayContainer {
// Create our AdDisplayContainer. Initialize it with our videoView as the container. This
// will result in ads being displayed over our content video.
if (self.companionView) {
// MOE:strip_line [START ad_display_container_init]
return [[IMAAdDisplayContainer alloc] initWithAdContainer:self.videoView
viewController:self
companionSlots:#[ self.companionSlot ]];
// [END ad_display_container_init] MOE:strip_line
} else {
return [[IMAAdDisplayContainer alloc] initWithAdContainer:self.videoView
viewController:self
companionSlots:nil];
}
}
// Register companion slots.
- (void)setUpCompanions {
// MOE:strip_line [START companion_slot_declaration]
self.companionSlot =
[[IMACompanionAdSlot alloc] initWithView:self.companionView
width:self.companionView.frame.size.width
height:self.companionView.frame.size.height];
// [END companion_slot_declaration] MOE:strip_line
}
// Initialize AdsLoader.
- (void)setUpIMA {
if (self.adsManager) {
[self.adsManager destroy];
}
[self.adsLoader contentComplete];
self.adsLoader.delegate = self;
if (self.companionView) {
[self setUpCompanions];
}
}
// Request ads for provided tag.
- (void)requestAdsWithTag:(NSString *)adTagUrl {
[self logMessage:#"Requesting ads"];
// Create an ad request with our ad tag, display container, and optional user context.
IMAAdsRequest *request = [[IMAAdsRequest alloc]
initWithAdTagUrl:adTagUrl
adDisplayContainer:[self createAdDisplayContainer]
avPlayerVideoDisplay:[[IMAAVPlayerVideoDisplay alloc] initWithAVPlayer:self.contentPlayer]
pictureInPictureProxy:self.pictureInPictureProxy
userContext:nil];
[self.adsLoader requestAdsWithRequest:request];
}
// Notify IMA SDK when content is done for post-rolls.
- (void)contentDidFinishPlaying:(NSNotification *)notification {
// Make sure we don't call contentComplete as a result of an ad completing.
if (notification.object == self.contentPlayer.currentItem) {
[self.adsLoader contentComplete];
}
}
#pragma mark AdsLoader Delegates
- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
// Grab the instance of the IMAAdsManager and set ourselves as the delegate.
self.adsManager = adsLoadedData.adsManager;
self.adsManager.delegate = self;
// Create ads rendering settings to tell the SDK to use the in-app browser.
IMAAdsRenderingSettings *adsRenderingSettings = [[IMAAdsRenderingSettings alloc] init];
adsRenderingSettings.linkOpenerPresentingController = self;
// Initialize the ads manager.
[self.adsManager initializeWithAdsRenderingSettings:adsRenderingSettings];
}
- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
// Something went wrong loading ads. Log the error and play the content.
[self logMessage:#"Error loading ads: %#", adErrorData.adError.message];
self.isAdPlayback = NO;
[self setPlayButtonType:PauseButton];
[self.contentPlayer play];
}
#pragma mark AdsManager Delegates
/*- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
[self logMessage:#"AdsManager event (%#).", event.typeString];
// When the SDK notified us that ads have been loaded, play them.
switch (event.type) {
case kIMAAdEvent_LOADED:
if (![self.pictureInPictureController isPictureInPictureActive]) {
[adsManager start];
}
break;
case kIMAAdEvent_PAUSE:
[self setPlayButtonType:PlayButton];
break;
case kIMAAdEvent_RESUME:
[self setPlayButtonType:PauseButton];
break;
case kIMAAdEvent_TAPPED:
[self showFullscreenControls:nil];
break;
default:
break;
}
}*/
- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
[self logMessage:#"AdsManager event (%#).", event.typeString];
switch (event.type) {
case kIMAAdEvent_LOADED:
[adsManager start];
break;
//case kIMAAdEvent_STARTED: {
break;
case kIMAAdEvent_PAUSE:
[self setPlayButtonType:PlayButton];
break;
case kIMAAdEvent_RESUME:
[self setPlayButtonType:PauseButton];
break;
case kIMAAdEvent_TAPPED:
[self showFullscreenControls:nil];
break;
default:
break;
}
}
- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdError:(IMAAdError *)error {
// Something went wrong with the ads manager after ads were loaded. Log the error and play the
// content.
[self logMessage:#"AdsManager error: %#", error.message];
self.isAdPlayback = NO;
[self setPlayButtonType:PauseButton];
[self.contentPlayer play];
}
- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager {
// The SDK is going to play ads, so pause the content.
self.isAdPlayback = YES;
[self setPlayButtonType:PauseButton];
[self.contentPlayer pause];
}
- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager {
// The SDK is done playing ads (at least for now), so resume the content.
self.isAdPlayback = NO;
[self setPlayButtonType:PauseButton];
[self.contentPlayer play];
}
#pragma mark Utility methods
- (void)logMessage:(NSString *)log, ... {
va_list args;
va_start(args, log);
NSString *s = [[NSString alloc] initWithFormat:[[NSString alloc] initWithFormat:#"%#\n", log]
arguments:args];
self.consoleView.text = [self.consoleView.text stringByAppendingString:s];
NSLog(#"%#", s);
va_end(args);
if (self.consoleView.text.length > 0) {
NSRange bottom = NSMakeRange(self.consoleView.text.length - 1, 1);
[self.consoleView scrollRangeToVisible:bottom];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I'm making my second game on XCode and there seems to be something wrong with the code. It's a space shooter game where the playership follows your finger and you tap to release the missile. The problem is... when I press 'start game', everything is hidden and will not popup. Here is my viewcontroller.h and viewcontroller.m
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
int score;
int lives;
int enemyAttackOccurence;
int enemyPosition;
int randomSpeed;
float enemySpeed;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
#implementation PlayViewController
-(void)viewDidAppear:(BOOL)animated {
// Images that are to be hidden
playerShip.hidden = YES;
enemyShip.hidden = YES;
missile.hidden = YES;
earth.hidden = YES;
// Hidden Labels
scoreLabel.hidden = YES;
livesLabel.hidden = YES;
// Set score and lives remaining
score = 0;
lives = 0;
// Strings
scoreString = [NSString stringWithFormat:#"Score: 0"];
liveString = [NSString stringWithFormat:#"Lives: 0"];
// Initial Label Text
scoreLabel.text = scoreString;
livesLabel.text = liveString;
// Image starting positions
playerShip.center = CGPointMake(150, 658);
enemyShip.center = CGPointMake(175, 20);
missile.center = CGPointMake(playerShip.center.x, playerShip.center.y);
}
-(IBAction)startGame:(id)sender {
// Hide buttons
startButton.hidden = YES;
exitButton.hidden = YES;
// Images to show
playerShip.hidden = NO;
enemyShip.hidden = NO;
earth.hidden = NO;
// Labels
scoreLabel.hidden = NO;
livesLabel.hidden = NO;
[self positionEnemy];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];
playerShip.center = CGPointMake(point.x, playerShip.center.y);
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[missileMovementTimer invalidate];
missile.hidden = NO;
missile.center = CGPointMake(playerShip.center.x, playerShip.center.y);
missileMovementTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(missileMovement) userInfo:nil repeats:YES];
}
-(void)positionEnemy {
// Random enemy position
enemyPosition = arc4random() % 249;
enemyPosition = enemyPosition + 20;
// Enemy Image Location
enemyShip.center = CGPointMake(enemyPosition, -40);
// Set enemy speed
randomSpeed = arc4random() % 3;
switch (randomSpeed) {
case 0:
enemySpeed = 0.03;
break;
case 1:
enemySpeed = 0.02;
break;
case 2:
enemySpeed = 0.01;
default:
break;
}
enemyAttackOccurence = arc4random() % 5;
[self performSelector:#selector(enemyMovementTimerMethod) withObject:nil afterDelay:enemyAttackOccurence];
}
-(void)enemyMovementTimerMethod {
enemyMovementTimer = [NSTimer scheduledTimerWithTimeInterval:enemySpeed target:self selector:#selector(enemyMovement) userInfo:nil repeats:YES];
}
-(void)enemyMovement {
enemyShip.center = CGPointMake(enemyShip.center.x, enemyShip.center.y + 2);
if (CGRectIntersectsRect(enemyShip.frame, earth.frame)) {
lives = lives - 1;
liveString = [NSString stringWithFormat:#"Lives: %i", lives];
livesLabel.text = liveString;
// Stop Enemy Moving
[enemyMovementTimer invalidate];
if (lives > 0) {
[self positionEnemy];
}
if (lives == 0) {
[self gameOver];
}
}
}
-(void)missileMovement {
missile.hidden = NO;
missile.center = CGPointMake(missile.center.x, missile.center.y - 2);
if (CGRectIntersectsRect(missile.frame, enemyShip.frame)) {
score = score + 1;
scoreString = [NSString stringWithFormat:#"Score: %i", score];
scoreLabel.text = scoreString;
// Stop missile
[missileMovementTimer invalidate];
// Position missile to be at the playerShip's center
missile.center = CGPointMake(playerShip.center.x, playerShip.center.y);
missile.hidden = YES;
// Stop enemy movement
[enemyMovementTimer invalidate];
[self positionEnemy];
}
}
-(void)gameOver {
[enemyMovementTimer invalidate];
[missileMovementTimer invalidate];
[self performSelector:#selector(gameReplay) withObject:nil afterDelay:3];
}
-(void) gameReplay {
// Images that are to be hidden
playerShip.hidden = YES;
enemyShip.hidden = YES;
missile.hidden = YES;
earth.hidden = YES;
// Hidden Labels
scoreLabel.hidden = YES;
livesLabel.hidden = YES;
// Set score and lives remaining
score = 0;
lives = 0;
// Strings
scoreString = [NSString stringWithFormat:#"Score: 0"];
liveString = [NSString stringWithFormat:#"Lives: 0"];
// Initial Label Text
scoreLabel.text = scoreString;
livesLabel.text = liveString;
// Image starting positions
playerShip.center = CGPointMake(150, 658);
enemyShip.center = CGPointMake(175, 20);
missile.center = CGPointMake(playerShip.center.x, playerShip.center.y);
}
#end
ViewController.h (Just for backup)
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
IBOutlet UIButton *startGame;
}
#end
#interface PlayViewController : UIViewController {
IBOutlet UIImageView *playerShip;
IBOutlet UIImageView *enemyShip;
IBOutlet UIImageView *missile;
IBOutlet UIImageView *earth;
IBOutlet UILabel *livesLabel;
IBOutlet UILabel *scoreLabel;
IBOutlet UIButton *startButton;
IBOutlet UIButton *exitButton;
UITouch *touch;
NSString *liveString;
NSString *scoreString;
NSTimer *enemyMovementTimer;
NSTimer *missileMovementTimer;
}
-(IBAction)startGame:(id)sender;
#end
I am watching a tutorial for this game, the person who created doesn't reply. Please help -- I cannot be any more specific. It just must be a weird gap in the code. Thanks.
Also, you have an IBOutlet and IBAction set for your StartGame button. The IBOutlet you never seem to use. You could be confusing your compiler by having the same name for the UIButton's IBOutlet and IBAction. Remove the IBOutlet, or change the name properly and see if that changes anything.
I'd recommend messing with your lines of code where you are setting object.hidden = YES and object.hidden = NO and see what happens. Often times tampering and testing your code is a good way to see what is going on. Make sure images are set for your UIImageViews. I'm assuming they are set in your interface builder because i don't see where you set them in your code. If there is no image set for the UIImageViews they will be see-through unless given a specific color. If tampering with the code doesn't work it won't hurt to re-watch the tutorial and make sure you didn't mess anything up. Often times the tutorials we watch are out-dated and we are left to solve a small problem ourselves and this may or may not be one of those instances. Again though, test your code and see if things are actually being set to hidden or not when you press that button.
How can I reset an scene (restart the countdown and set the score to 0) the second time I start it? The second time I load the scene both initWithParameters and onStart are not called.
Cocos2D Game:
-(id) initWithParameters:(NSArray *) parameters
{
NSLog(#"init TheButton with parameters");
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
gameParameters = parameters;
// Enable touch handling on scene node
[self setIsTouchEnabled:YES];
// Create a colored background (Dark Grey)
//CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0.6f green:0.6f blue:0.6f alpha:1.0f]];
//[self addChild:background];
CCMenuItem *starMenuItem = [CCMenuItemImage
itemFromNormalImage:#"ButtonStar.png" selectedImage:#"ButtonStarSel.png"
target:self selector:#selector(increasePoints:)];
CGSize size = [[CCDirector sharedDirector] winSize];
starMenuItem.anchorPoint = ccp(0.5f,0.5f);
starMenuItem.position = ccp(size.width/2, size.height/2);
CCMenu *starMenu = [CCMenu menuWithItems:starMenuItem, nil];
starMenu.position = CGPointZero;
[self addChild:starMenu];
timeLabel = [CCLabelTTF labelWithString:#"0.00" fontName:#"Arial" fontSize:18.0f];
//timeLabel.positionType = CCPositionTypeNormalized;
timeLabel.position = ccp(30,size.height-10);
// Add the time label
[self addChild:timeLabel];
NSLog(#"time: %#", [gameParameters objectAtIndex:0]);
clicksLabel = [CCLabelTTF labelWithString:#"0" fontName:#"Arial" fontSize:18.0f];
//clicksLabel.positionType = CCPositionTypeNormalized;
clicksLabel.position = ccp(size.width - 20,size.height-10);
// Add the time label
[self addChild:clicksLabel];
[self startGame];
return self;
}
-(void) startGame
{
clicks = 0;
myTime = [[gameParameters objectAtIndex:0] intValue];
[self schedule:#selector(update:)];
}
The scene (a cocos2d game) is integrated in a storyboard project. When it finishes (the countdown arrives to 0) it loads a new viewcontroller. From this viewcontroller I would like to load the game again when when the user press the "Play Again" Button. What happens is the scene is loading (I implemented it with an unwind segue) but both the countdown and the score are not reseted, how can I do this?
EDIT:
I finally get to reload and reset the scene from the CocosViewController but when I call performSegueWithIdentifier when the game finishes it does not load the viewcontroller. Method viewdidload is called but it does not show anything.
Cocos2dGame:
-(void) onExit
{
[super onExit];
//Send parameters
self.gameTracking = [[NSMutableArray alloc] initWithObjects:#"THE",#"QUICK", #"BROWN", #"FOX",#"FOO", nil];
NSDictionary * userInfo = [[NSMutableDictionary alloc] initWithObjectsAndKeys: [NSString stringWithFormat:#"%d",clicks], #"score", self.gameTracking, #"gameTracking", nil];
//Send a notification to the CocosViewController when the game is finished to load the new view controller
[[NSNotificationCenter defaultCenter] postNotificationName:#"GameEndedNotification" object:self userInfo:userInfo];
NSLog(#"game exit");
//[[CCDirector sharedDirector] end];
}
Cocos2DViewController
//Receive notification when the game finished
-(void)receiveNotificationFromGame:(NSNotification *) notification
{
if ([[notification name] isEqualToString:#"GameEndedNotification"])
{
NSLog (#"Successfully received the test notification! %#", [self class]);
NSLog(#"score: %d", [notification.userInfo[#"score"] intValue]);
//get variables
try.score = [notification.userInfo[#"score"] intValue];
NSLog(#"score: %d", try.score);
try.gameTracking = notification.userInfo[#"gameTracking"];
//show the next view
[self performSegueWithIdentifier:#"sg_showScore" sender:self];
}
}
I have created a custom class LevelScoreCard:CCNode which have some CCMenuItemImages.
Here are the interface and implementation details
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface LevelScoreCard : CCNode {
#private CCSprite *levelScoreBackGround;
#private CGSize winSize;
}
-(id)initForLevelNo:(int)levelNo withWiningStatus:(BOOL)won;
#end
and
#import "LevelScoreCard.h"
#import "TestLayer3.h"
#implementation LevelScoreCard
-(id)initForLevelNo:(int)levelNo withWiningStatus:(BOOL)won
{
if( (self=[super init]) ) {
winSize=[CCDirector sharedDirector].winSize;
//Adding the BackGround
levelScoreBackGround=[CCSprite spriteWithFile:#"levelScoreBackGround.png"];
self.contentSize=levelScoreBackGround.contentSize;
[self addChild:levelScoreBackGround ];
//Adding the Game Level-Wining Status
CCSprite *winingStatus;
if (won) {
winingStatus=[CCSprite spriteWithFile:#"levelCompleted.png"];
}
else{
winingStatus=[CCSprite spriteWithFile:#"levelFailed.png"];
CCSprite *skull=[CCSprite spriteWithFile:#"skull.png"];
skull.position=ccp(0,-self.contentSize.height*0.07);
[self addChild:skull];
}
winingStatus.position=ccp(0,self.contentSize.height*0.32);
[self addChild:winingStatus];
CCMenuItem *homeButton = [CCMenuItemImage itemWithNormalImage:#"home1.png"
selectedImage:#"home1.png"
block:^(id sender) {
printf("\nHome button clicked");
}];
CCMenuItem *replayButton = [CCMenuItemImage itemWithNormalImage:#"replay.png"
selectedImage:#"replay.png"
block:^(id sender) {
printf("\nReplay button clicked");
}];
CCMenuItem *nextButton;
CCMenu *menu;
NSDictionary *nextLevelInfo=[self gameInformationForLevel:levelNo+1];
//Create a menu from the button and center it on the screen
if (![[nextLevelInfo objectForKey:#"isLocked"] intValue]) {
nextButton = [CCMenuItemImage itemWithNormalImage:#"next.png"
selectedImage:#"next.png"
block:^(id sender) {
printf("\nNext button clicked");
}];
menu = [CCMenu menuWithItems:homeButton, replayButton,nextButton, nil];
[menu alignItemsHorizontallyWithPadding:60];
}
else
{
menu = [CCMenu menuWithItems:homeButton, replayButton, nil];
[menu alignItemsHorizontallyWithPadding:20];
}
menu.position = ccp(0,-self.contentSize.height*0.35);
//Add the menu as a child to this layer
[self addChild:menu];
}
return self;
}
-(NSDictionary*)gameInformationForLevel:(int)levelNo
{
//---Retrieving Information About Levels----
NSMutableDictionary *gameInfo=[[NSUserDefaults standardUserDefaults] objectForKey:#"gameInfo"];
NSString *levelKey=[NSString stringWithFormat:#"level%dInfo",levelNo];
return [[gameInfo objectForKey:levelKey] copy];
}
#end
When i am using this LevelScoreCard from simple CCLayer which is loaded directly from the IntroLayer,the blocks associated with the MenuItems are working perfectly.
But when I am using it in another CCLayer which is loaded conditionally from a second CCLayer, StartLayer with the following code,MenuItems are not responding
-(void)loadLevelAfterDelay:(ccTime)dt
{
#warning Game has 4 levels, implement game layer 2,3,4 after fixing the story
switch (levelSelected) {
case 1:
{
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.50 scene:[Level1 scene] ]];
break;
}
case 2:
{
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.50 scene:[TestLayer2 scene] ]];
break;
}
case 3:
{
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.50 scene:[Level1 scene] ]];
break;
}
case 4:
{
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:0.50 scene:[Level1 scene] ]];
break;
}
default:
break;
}
}
The problem was that the previous layer StartLayer:CCLayer had a SettingsMenu:CCNode which was registered to to the touchDispatcher as
[[CCDirector sharedDirector].touchDispatcher addTargetedDelegate:self priority:INT_MIN+2 swallowsTouches:YES];
This was the culprit to swallow touches before they are delivered to CCMenuItemImages.So ,i learned a great lesson which says never register any CCNode type item which will swallow touch.
It's good habit not to swallow touches while registering with touchDispatcher with the following piece of code
[[CCDirector sharedDirector].touchDispatcher addTargetedDelegate:self priority:INT_MIN+2 swallowsTouches:NO];
I have this Class:
//Interface
#interface SavingDataPlist : SimpleTimedGameRecipe
{
NSMutableArray *moles;
int tagCount;
int moleCount;
CCSprite *mallet;
CGPoint malletPosition;
}
-(CCLayer*) runRecipe;
-(void) step;
-(void) initBackground;
-(void) createMoleAtPosition:(CGPoint)point withZ:(float)z;
-(void) processMoleHit;
-(void) addHiScoresToMenu;
-(void) loadHiScores;
-(void) addHiScore;
-(void) deleteHiScores;
-(void) startNewGame;
-(void) gameOver;
-(void) step:(ccTime)delta;
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
which in its reunRecipe method calls this:
[self createMoleAtPosition:ccp(50,205) withZ:0];
and that call corresponds to this method:
-(void) createMoleAtPosition:(CGPoint)point withZ:(float)z {
CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSprite *back = [CCSprite spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_back.png"]];
back.position = ccp(point.x, point.y);
[self addChild:back z:z tag:tagCount];
tagCount++;
Mole *mole = [Mole spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_normal.png"]];
[mole setDownPosition:ccp(point.x,point.y-30)];
[self addChild:mole z:z tag:tagCount];
[moles addObject:mole];
NSLog(#"moles.count %d", moles.count);
tagCount++;
CCSprite *front = [CCSprite spriteWithSpriteFrame:[cache spriteFrameByName:#"mole_front.png"]];
front.position = ccp(point.x, point.y);
[self addChild:front z:z tag:tagCount];
tagCount++;
}
The Mole Class init method looks like this:
-(id)init {
NSLog(#"moleinit");
self = [super init];
if (self != nil) {
state = MOLE_DOWN;
CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
//
//MEVPCHANGE
//Create framenumber array to populate ccanimation later
NSMutableArray *animationFramesArray = [[NSMutableArray alloc] init];
NSMutableArray *animationFramesArray2 = [[NSMutableArray alloc] init];
//MEVPCHANGE - add frames to array
[animationFramesArray addObject:[cache spriteFrameByName:#"mole_normal.png"]];
[animationFramesArray2 addObject:[cache spriteFrameByName:#"mole_hit.png"]];
normalAnim = [[CCAnimation alloc] initWithSpriteFrames:animationFramesArray delay:1.0f];
hitAnim = [[CCAnimation alloc] initWithSpriteFrames:animationFramesArray2 delay:1.0f];
//MEVPCHANGE - create animation
[animationFramesArray release];
[animationFramesArray2 release];
//
[self runAction:[CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:normalAnim]]];
}
return self;
}
Now in cocos2d v1.0 this code works fine. The Mole's get created and they pop up and down when they get whacked. But in v2.0, I only get the front facing moles but the NSLog in the Mole init method doesnt even get called (as evidenced by the lack of NSLog in the console).