I have two layers set up like so in one scene:
header file for scene:
#interface GameScene1 : CCScene {
GameLayer *gameLayer;
HUDLayer *hudLayer;
}
Main file for scene:
-(id)init {
self = [super init];
if (self != nil) {
gameLayer = [GameLayer node];
[self addChild:gameLayer];
hudLayer = [HUDLayer node];
[self addChild:hudLayer];
}
return self;
}
HUD layer header:
#interface HUDLayer : CCNode {
CCSprite *background;
CGSize screenSize;
}
-(void)updateMonstersSlayed:(NSString*)value;
HUD layer main:
#implementation HudLayer
-(id)init
{
self = [super init];
if (self)
{
CGSize viewSize = [[CCDirector sharedDirector] viewSize];
monstersSlayed = [CCLabelTTF labelWithString:#"Monsters Killed: 0" fontName:#"Arial" fontSize:15];
monstersSlayed.position = ccp(viewSize.width * 0.85, viewSize.height * 0.1 );
[self addChild:monstersSlayed];
}
return self;
}
-(void)updateMonstersSlayed:(NSString*)value
{
monstersSlayed.string = value;
}
Game Layer main
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair collisionPlayer:(CCNode *)user collisionMonster:(CCNode *)monster
{
if (holdingWeapon)
{
HudLayer *myHud = [[HudLayer alloc] init];
[myHud updateMonstersSlayed:#"Monsters Killed: 1"];
}
}
Simply trying to get it set to where I can set text from the Game Layer to show up in a Label in the Hud Layer.
How would I accomplish this in Cocos2d 3?
There are many ways you can do this. But for the sake of simplicity the easiest way you can do this is via notifications. For example in the hud add:
#implementation HudLayer
- (void)onEnter
{
[super onEnter];
NSNotificationCenter* notiCenter = [NSNotificationCenter defaultCenter];
[notiCenter addObserver:self
selector:#selector(onUpdateMonsterText:)
name:#"HudLayerUpdateMonsterTextNotification"
object:nil];
}
- (void)onExit
{
[super onExit];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)onUpdateMonsterText:(NSNotification *)notification
{
NSDictionary* userInfo = notification.userInfo;
if (userInfo)
{
NSString* text = userInfo[#"text"];
if (text)
{
[self updateMonstersSlayed:text];
}
else
{
CCLOG(#"Monster hud text param is invalid!.");
}
}
else
{
CCLOG(#"Monster hud user info invalid!");
}
}
#end
Then anywhere in your application where you want to update text you can just post the notification. Using your physics collision began example:
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair
*emphasized text*collisionPlayer:(CCNode *)user collisionMonster:(CCNode *)monster
{
if (holdingWeapon)
{
NSDictionary* userInfo = #{#"text" : #"Monsters Killed: 1"};
NSString* notiName = #"HudLayerUpdateMonsterTextNotification";
[[NSNotificationCenter defaultCenter] postNotificationName:notiName
object:self userInfo:userInfo];
}
}
Hope this helps.
You can use methods. Make a method in HUD layer class.
-(void) giveMeMyText:(NSString*)someText
{
do something with my someText
}
Don't forget to make the method visible in HUD.h -(void) giveMeMyText; Then import HUD layer class in GameScene1 #import "HUDlayer.h" and use it.
HUDLayer* myHud = [[HUDLayer alloc] init];
[myHud giveMeMyText:#"say hi!"];
You could use delegation, so your scene would implement GameLayerProtocol and the delegate of GameLayer. That way the scene would be notified of any changes the GameLayer has and act appropriately on the HudLayer.
For example:
// GameLayer class
#protocol GameLayerProtocol <NSObject>
- (void)someThingHappenedInGameLayer;
#end
#interface GameLayer : CCNode
#property (nonatomic, weak) id<GameLayerProtocol> delegate;
#end
#implementation GameLayer
- (void)someActionInGameLayer
{
[self.delegate someThingHappenedInGameLayer];
}
#end
// Scene class
#interface IntroScene : CCScene <GameLayerProtocol>
#end
#implementation IntroScene
// Implement protocol methods
- (void)someThingHappenedInGameLayer
{
//Do something with your HUDLayer here
}
#end
Related
I'm using a 2d game engine called Sprite kit within Xcode and i want to hide my ad banner in specific areas such as the game scene and then show it once it's game over for the player. But i'm having trouble trying to access the hidden property of the banner within other scenes/classes.
GameViewController.h
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#import <GoogleMobileAds/GoogleMobileAds.h>
#import <AVFoundation/AVFoundation.h>
#interface GameViewController : UIViewController
-(void) hideBanner;
#end
GameViewController.m
#implementation GameViewController
-(void) hideBanner {
self.bannerView.hidden = YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Create a banner ad and add it to the view hierarchy.
self.bannerView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
//TEST UNIT ID
self.bannerView.adUnitID = #"ca-app-pub-3940256099942544/2934735716";
self.bannerView.rootViewController = self;
[self.view addSubview:self.bannerView];
GADRequest *request = [GADRequest request];
request.testDevices = #[ #"*log id*" ];
[self.bannerView loadRequest:request];
}
GameScene.h
#class GameViewController;
#interface GameScene : SKScene <SKPhysicsContactDelegate>
#property (strong, nonatomic) GameViewController *gameViewController;
#end
GameScene.m
//This line of code will be executed in the "performGameOver" method but it does not work and the banner is still shown?
[self.gameViewController hideBanner];
You should use NSNotification
In viewController.m
- (void)handleNotification:(NSNotification *)notification {
if ([notification.name isEqualToString:#"hideAd"]) {
[self hidesBanner];
}else if ([notification.name isEqualToString:#"showAd"]) {
[self showBanner];
}}
-(void)hidesBanner {
NSLog(#"HIDING BANNER");
[adView setAlpha:0];
self.bannerIsVisible = NO;
}
-(void)showsBanner {
NSLog(#"SHOWING BANNER");
[adView setAlpha:1];
self.bannerIsVisible = YES;
}
In your scene:
Sends message to viewcontroller to show ad.
[[NSNotificationCenter defaultCenter] postNotificationName:#"showAd" object:nil];
Sends message to viewcontroller to hide ad.
[[NSNotificationCenter defaultCenter] postNotificationName:#"hideAd" object:nil];
More info:
https://stackoverflow.com/a/21967530/4078517
I am using sprite-kit and targeted iOS 7. I want to show leaderboard with button in my MenuScene.
my helper method codes.
#import "GameKitHelper.h"
NSString *const PresentAuthenticationViewController =
#"present_authentication_view_controller";
#interface GameKitHelper()<GKGameCenterControllerDelegate>
#end
#implementation GameKitHelper {
BOOL _enableGameCenter;
}
+ (instancetype)sharedGameKitHelper
{
static GameKitHelper *sharedGameKitHelper;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedGameKitHelper = [[GameKitHelper alloc] init];
});
return sharedGameKitHelper;
}
- (id)init
{
self = [super init];
if (self) {
_enableGameCenter = YES;
}
return self;
}
- (void)showGKGameCenterViewController:
(UIViewController *)viewController
{
if (!_enableGameCenter) {
NSLog(#"Local play is not authenticated");
}
GKGameCenterViewController *gameCenterViewController =
[[GKGameCenterViewController alloc] init];
gameCenterViewController.gameCenterDelegate = self;
gameCenterViewController.viewState =
GKGameCenterViewControllerStateAchievements;
[viewController presentViewController:gameCenterViewController
animated:YES
completion:nil];
}
I want to Leaderboard Button in this class.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:#"start"]) {
MyScene *myScene = [MyScene sceneWithSize:self.size];
[self.view presentScene:myScene transition:[SKTransition pushWithDirection:SKTransitionDirectionLeft duration:0.5]];
}
if ([node.name isEqualToString:#"gameCenter"]) {
//HERE MY LEADERBOARD BUTTON ACTION
//I don't know what i write here...
{
}
I tried so much methods but these working in iOS 6, I targeted iOS 7.
I tried this:
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:self]; Xcode says for self
Incompatible pointer types sending 'GameMenuScene *' to parameter of type 'UIViewController *'
Andrey is right. gameKitHelper means [gameKitHelper sharedGameKitHelper]. like this example
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
Keep coding :)
if ([node.name isEqualToString:#"gameCenter"]) {
UIViewController *vc = self.view.window.rootViewController;
[[GameKitHelper sharedGameKitHelper] showGKGameCenterViewController:vc];
}
But actually you should present another ViewController from your ViewController, not from SKScene
Try this, it's easy to implement and works well:
https://github.com/nihalahmed/GameCenterManager
inside viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(openLeaderboard)
name:#"TestNotification"
object:nil];
Inside VC:
- (void) openLeaderboard
{
// Open Leaderboards here
}
In your Scene:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];
I'm trying to change from gamePlayscene to a GameOverScene, but when the simulator tries to changes the scene, the simulator stops but I don't receive any message in the Log.
GameOverScene.h
#interface GameOverScene : CCScene {
GameOverScene *scene;
//screen size
float winWidth;
float winHeight;
//Game vars
int score;
//Facebook vars
FBSession* session;
NSString *messageStr;
NSString *userid;
}
+ (GameOverScene *)scene;
- (id)init;
#end
GameOverScene.m
#implementation GameOverScene {
}
+ (GameOverScene *)scene
{
return [[self alloc] init];
}
// -----------------------------------------------------------------------
- (id)init
{
if( (self=[super init] )) {
NSLog(#"define tamanho da tela");
winWidth = self.contentSize.width;
winHeight = self.contentSize.height;
NSLog(#"define botao");
// Facebook login button
CCButton *fbLoginButton = [CCButton buttonWithTitle:#"Login with FB" fontName:#"Verdana-Bold" fontSize:30.0f];
fbLoginButton.position = ccp(winWidth/2, winHeight/2);
[fbLoginButton setTarget:self selector:#selector(fbLoginClicked:)];
[self addChild:fbLoginButton];
}
}
I'm calling the GameOverScene this way:
[[CCDirector sharedDirector] replaceScene:[GameOverScene scene]
withTransition:[CCTransition transitionFadeWithDuration:1.0f]];
put "return self" in the -(id)init method after the if block.
Note: I am posting this as a reference for other developers that might run into the same issue.
Why do I have a memory leak with this code:
#interface SPWKThing : NSObject
#property (strong, nonatomic) NSArray *things;
#end
#implementation SPWKThing {
BOOL _isKVORegistered;
}
- (id)init
{
self = [super init];
if (self) {
NSLog(#"initing SPWKThing");
[self registerKVO];
}
return self;
}
- (void)didChangeValueForKey:(NSString *)key {
if ([key isEqualToString:#"things"]) {
NSLog(#"didChangeValueForKey: things have changed!");
}
}
#pragma mark - KVO
- (void)registerKVO
{
if (!_isKVORegistered) {
NSLog(#"Registering KVO, and things is %#", _things);
[self addObserver:self forKeyPath:#"things" options:0 context:NULL];
_isKVORegistered = YES;
}
}
- (void)unregisterKVO
{
if (_isKVORegistered) {
NSLog(#"Unregistering KVO");
[self removeObserver:self forKeyPath:#"things"];
_isKVORegistered = NO;
}
}
- (void)dealloc
{
NSLog(#"SPWKThing dealloc");
[self unregisterKVO];
}
#end
#implementation SPWKViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self runDemo];
}
- (void)runDemo
{
SPWKThing *thing = [[SPWKThing alloc] init];
thing.things = #[#"one", #"two", #"three"];
thing = nil;
}
#end
My output is:
initing SPWKThing
Registering KVO, and things is (null)
didChangeValueForKey: things have changed!
dealloc is never called? Why? I am setting thing = nil in the last line of runDemo!
See a demo project here: https://github.com/jfahrenkrug/KVOMemoryLeak
The answer is:
Never override didChangeValueForKey: (at least not without calling super). The documentation does not warn you about this.
Use the correct method observeValueForKeyPath:ofObject:change:context: instead.
This project clearly demonstrates this: https://github.com/jfahrenkrug/KVOMemoryLeak
I can get the HUD layer to appear, but I can't seem to update it. I got it working in Ray's tutorial, but for some reason I can't get it working in my own app. I made a new Cocos2d project just so I can try and isolate the problem and I'm having the same issue... maybe you guys can help. ( I'm getting no errors and tried to fix the indentation as best I could for StackOverflow..)
Problem: I can't update the scoreLabel
Code:
GameHUD.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface GameHUD : CCLayer {
CCLabelTTF *scoreLabel;
}
- (void) updateScore:(int)score;
#end
GameHUD.m
#import "GameHUD.h"
#implementation GameHUD
- (id) init {
if (self = [super init]) {
scoreLabel = [CCLabelTTF labelWithString:#"00000" dimensions:CGSizeMake(240,100) hAlignment:kCCTextAlignmentRight fontName:#"Arial" fontSize:32.0f];
scoreLabel.anchorPoint = ccp(0,0);
scoreLabel.position = ccp(200,0);
scoreLabel.color = ccc3(255, 200, 100);
[self addChild:scoreLabel];
}
return self;
}
- (void)updateScore:(int)score {
scoreLabel.string = [NSString stringWithFormat:#"%i",score];
}
#end
HelloWorldLayer.h
#import "cocos2d.h"
#import "GameHUD.h"
#interface HelloWorldLayer : CCLayer
{
GameHUD *_hud;
}
#property (nonatomic,retain) GameHUD *hud;
+(CCScene *) scene;
#end
HelloWorldLayer.m
#import "HelloWorldLayer.h"
#import "AppDelegate.h"
#pragma mark - HelloWorldLayer
#implementation HelloWorldLayer
#synthesize hud = _hud;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
GameHUD *hud = [GameHUD node];
[scene addChild:hud];
layer.hud = hud;
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
// create and initialize a Label
CCLabelTTF *label = [CCLabelTTF labelWithString:#"Layer A" fontName:#"Marker Felt" fontSize:64];
// ask director for the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label on the center of the screen
label.position = ccp( size.width /2 , size.height/2 );
// add the label as a child to this Layer
[self addChild: label];
// Try to update the scoreLabel in the HUD (NOT WORKING)
[_hud updateScore:74021];
}
return self;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[super dealloc];
}
The init is called when you invoke [HelloWorldLayer node] when the HUD is not created yet, ie, _hud is nil. Sending message to a nil object is a void operation and it doesn't crash as it is if calling functions on 'NULL` objects.