I have a Gamehud where I want to display an object's name. There are lots of objects/sprites in main scene what I am trying to do is to display selected(on touch) objects' name on Gamehud.
Problem is if I alloc Gamehud in CCsprite class it creates new instance and does not update current Gamehud. If I use something like GameHUD *gamehud= (GameHUD *)[self.parent getChildByTag:99]; nothing happens I cannot send the object to GameHud class.
So what would be the correct way to update game hud in a ccsprite or ccnodeclass?
Main Scene;
-(id) init
{
if ((self = [super init]))
{
gameHud = [GameHUD gamehud];
[self addChild:gameHud z:2 tag:99];
}
}
My GameHud
+(id) gamehud
{
return [[self alloc] init];
}
-(id) init
{
if ((self = [super init]))
{
//bunch of labels
}
}
-(void)showName: :(Object *)obj
{
NSLog(#"Object name is %#", obj.name);
[_labelSpeed setString:obj.name];
}
In Object Class:CCSprite
-(void) onTouch
{
//obj is the object with name property that I want to use
GameHUD *gamehud= (GameHUD *)[self.parent getChildByTag:99]; // does not send the obj to gamehud and showName is not called
//GameHud *gamehud= [GameHud alloc] init]; // this displays nslog but doesnt update _label
[gamehud showName:obj];
}
First of all use a singlton or you will create a new GameHub everytime you call +(id) gamehud. i think this could be your problem: you add one GameHUD to the scene and call showName: of another object of GameHUD. Another problem is your -(id)init - you dont return self! so you never get your GameHUD
static GameHUD *sharedInstance = nil;
+(id) gamehud {
if( !sharedInstance ) {
sharedInstance = [[GameHUD alloc] init]
}
return sharedInstance;
}
-(id) init {
self = [super init];
if ( self ) {
//bunch of labels
sharedInstance = self;
}
return self; //i dont see this in your code!
}
from now you can access your hud from every point you want and you dont need to handle with tags. Be careful, its not the best way to create a Singleton (ask google). Dont call ..alloc] init] use only [GameHUD gamehud];
-(void) onTouch {
[[GameHUD gamehud] showName:obj];
}
Good Luck!
You may need to create a singleton or something like a semi singleton. Just add new nsobject class name "SingletonGameHud" to your app
SingletonGameHud.h
#import <Foundation/Foundation.h>
#import "GameHUD.h"
//create singleton class to use gamehud in movingobject class
#interface SingletonGameHud : NSObject
{
GameHUD *gamingHud;
}
#property(nonatomic,strong) GameHUD *gamingHud;
+(SingletonGameHud *)sharedInstance;
#end
SingletonGameHud.m
#import "SingletonGameHud.h"
#import "GameHUD.h"
#implementation SingletonGameHud
#synthesize gamingHud=_gamingHud;
+ (SingletonGameHud *)sharedInstance
{
static SingletonGameHud *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SingletonGameHud alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {
_gamingHud = [GameHUD hud];
}
return self;
}
#end
in your game scene call
SingletonGameHud *sharedInstance= [SingletonGameHud sharedInstance];
hud = sharedInstance.gamingHud;
[self addChild:hud z:2 tag:99];
in your on touch method call
-(void) onTouch
{
SingletonGameHud *sharedInstance= [SingletonGameHud sharedInstance];
[sharedInstance.gamingHud showName:obj];
}
Related
It's stepping into the ViewDidLoad of the main view controller, and hitting the line calling get all tweets, but I put a breakpoint in the getAllTweets of both the base and derived to see if it just wasn't hitting the derived like I expected.
#implementation WWMainViewControllerTests {
// system under test
WWMainViewController *viewController;
// dependencies
UITableView *tableViewForTests;
WWTweetServiceMock *tweetServiceMock;
}
- (void)setUp {
tweetServiceMock = [[WWTweetServiceMock alloc] init];
viewController = [[WWMainViewController alloc] init];
viewController.tweetService = tweetServiceMock;
tableViewForTests = [[UITableView alloc] init];
viewController.mainTableView = tableViewForTests;
tableViewForTests.dataSource = viewController;
tableViewForTests.delegate = viewController;
}
- (void)test_ViewLoadedShouldCallServiceLayer_GetAllTweets {
[viewController loadView];
STAssertTrue(tweetServiceMock.getAllTweetsCalled, #"Should call getAllTweets on tweetService dependency");
}
- (void)tearDown {
tableViewForTests = nil;
viewController = nil;
tweetServiceMock = nil;
}
The base tweet service:
#implementation WWTweetService {
NSMutableArray *tweetsToReturn;
}
- (id)init {
if (self = [super init]) {
tweetsToReturn = [[NSMutableArray alloc] init];
}
return self;
}
- (NSArray *)getAllTweets {
NSLog(#"here in the base of get all tweets");
return tweetsToReturn;
}
#end
The Mock tweet service:
#interface WWTweetServiceMock : WWTweetService
#property BOOL getAllTweetsCalled;
#end
#implementation WWTweetServiceMock
#synthesize getAllTweetsCalled;
- (id)init {
if (self = [super init]) {
getAllTweetsCalled = NO;
}
return self;
}
- (NSArray *)getAllTweets {
NSLog(#"here in the mock class.");
getAllTweetsCalled = YES;
return [NSArray array];
}
The main view controller under test:
#implementation WWMainViewController
#synthesize mainTableView = _mainTableView;
#synthesize tweetService;
NSArray *allTweets;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
allTweets = [tweetService getAllTweets];
NSLog(#"was here in view controller");
}
- (void)viewDidUnload
{
[self setMainTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
Since you're able to break in the debugger in viewDidLoad, what's the value of the tweetService ivar? If it's nil, the getAllTweets message will just be a no op. Maybe the ivar isn't being set properly or overridden somewhere else.
You should probably use the property to access the tweetService (call self.tweetService) rather than its underlying ivar. You should only ever access the ivar directly in getters, setters, and init (also dealloc if aren't using ARC for some crazy reason).
You also should not call loadView yourself, rather just access the view property of the view controller. That will kick off the loading process and call viewDidLoad.
Also, if you're doing a lot of mocking, I highly recommend OCMock.
i have a question about initializing a custom delegate.
Within MyScrollView initWithFrame method, there is the first position where i need to send my delegate. But it´s still unknown there, because i set the delegate within MyCustomView after the initializer.
How can i fix that, so the delegate gets called even within init?
Thanks for your help..
MyCustomView.m
self.photoView = [[MyScrollView alloc] initWithFrame:frame withDictionary:mediaContentDict];
self.photoView.delegate = self;
//....
MyScrollView.h
#protocol MyScrollViewDelegate
-(void) methodName:(NSString*)text;
#end
#interface MyScrollView : UIView{
//...
__unsafe_unretained id <MyScrollViewDelegate> delegate;
}
#property(unsafe_unretained) id <MyScrollViewDelegate> delegate;
MyScrollView.m
-(id) initWithFrame:(CGRect)frame withDictionary:(NSDictionary*)dictionary{
self.content = [[Content alloc] initWithDictionary:dictionary];
self = [super initWithFrame:frame];
if (self) {
//.... other stuff
// currently don´t get called
[self.delegate methodName:#"Test delegate"];
}
return self;
}
I am sure you have defined a:
- (id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary *)dictionary;
Then, just pass the delegate, too:
- (id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary *)dictionary withDelegate:(id<MyScrollViewDelegate>)del;
In the Implementation File:
- (id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary *)dictionary withDelegate:(id<MyScrollViewDelegate>)del {
// your stuff...
self.delegate = del;
[self.delegate methodName:#"Test delegate"];
}
Use it:
self.photoView = [[MyScrollView alloc] initWithFrame:frame withDictionary:mediaContentDict withDelegate:self];
One option might be to pass in your delegate in your custom class's initializer:
-(id)initWithFrame:(CGRect)frame withDictionary:(NSDictionary*)dictionary delegate:(id)delegate
{
self = [super initWithFrame:frame];
if (self == nil )
{
return nil;
}
self.content = [[Content alloc] initWithDictionary:dictionary];
self.delegate = delegate;
//.... other stuff
// Delegate would exist now
[self.delegate methodName:#"Test delegate"];
return self;
}
I'm sure this is really obvious to someone, but this simple thing is really frustrating me.
I have a class I made called Class_Sprite, which is a sub-class of CCSprite.
I have a method in this class that is supposed to both create the texture for any given instance of Class_Sprite, and then move it to (200,200).
The program runs in the sim but all I get is a black screen.
I was able to render the sprite directly from the layer class.
Here are the files.
Class_Sprite:
#import "Class_Sprite.h"
#implementation Class_Sprite
-(id)init
{
if ((self = [super init]))
{
}
return self;
}
-(void)make:(id)sender
{
sender = [Class_Sprite spriteWithFile:#"Icon.png"];
[sender setPosition: ccp(200, 200)];
}
#end
Class Sprite header:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Class_Sprite : CCSprite {
}
-(void)make:(id)sender;
#end
HelloWorldLayer.m (where the method is being called)
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self = [super init])) {
Class_Sprite *pc = [[Class_Sprite alloc] init];
[pc make:self]; //here is where I call the "make" method
[self addChild:pc];
[pc release];
}
return self;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#end
And finally the header file for HelloWorldLayer
#import "cocos2d.h"
#import "Class_Sprite.h"
// HelloWorldLayer
#interface HelloWorldLayer : CCLayer
{
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
#end
Thanks for your time
Try changing to this in Class_Sprite.m:
#implementation Class_Sprite
-(id)init
{
if ((self = [super initWithFile:#"Icon.png"]))
{
}
return self;
}
-(void)make:(CCNode *)sender
{
[self setPosition: ccp(200, 200)];
[sender addChild:self];
}
#end
And use it in HelloWorldLayer as follows:
Class_Sprite *pc = [[Class_Sprite alloc] init];
[pc make:self];
[pc release];
I'm new in objective-C and here is my problem:
I want to write a game and i want to use a GameStateManager class to manage the game states. As i've read every class in Objective-C should be inherited from NSObject or it's subclass. So here is the GameStateManager interface:
#interface GameStateManager : NSObject {
int currentState_;
}
+(id) instance;
-(void) setState:(int)state;
#end
And here is the implementation:
#implementation GameStateManager
+(id) instance
{
GameStateManager *manager = [GameStateManager init];
return manager;
}
- (id) init
{
self = [super init];
return self;
}
- (void) setState: (int) state
{
switch (state)
{
case GS_MAIN_MENU_START:
{
// MenuScene *menuScene = [MenuScene node];
// [menuScene build: false];
MenuScene *scene = [scene instance:self :false];
[[CCDirector sharedDirector] runWithScene: scene];
}
break;
case GS_PLAYING:
{
}
break;
}
}
#end
I use this class here:
gameStateManager = [GameStateManager instance];
[gameStateManager setState: GS_MAIN_MENU_START];
The second line generated an SIGABRT signal. What's the problem ?
The problem is here:
+ (id) instance
{
GameStateManager *manager = [GameStateManager init];
return manager;
}
In effect you are calling init without ever calling alloc. I’d recommend that you forget about the instance stuff and use the official init patterns until you are really comfortable with the memory management:
- (id) init
{
self = [super init];
if (self == nil)
return nil;
…
return self;
}
…and then get your instance by calling [[GameStateManager alloc] init].
GameStateManager *manager = [GameStateManager init];
-(id)init is an instance method, not a class method. That line should look like this:
GameStateManager *manager = [[GameStateManager alloc] init];
The issue is that the gameStateManager isn't being created properly. Instead of
[GameStateManager init]
use
[[[GameStateManager alloc] init] autorelease]
The autorelease is for good memory management and doesn't actually affect the initialization.
I have an object which is initiated in my nib file. I want it to be a singleton but also accessible from code through [myClass sharedInstance];. Right now I have this:
static myClass *singleton = nil;
#implementation myClass
+ (myClass *)sharedInstance
{
if (!singleton) singleton = [[self class] new];
return singleton;
}
+ (id)alloc
{
return [self sharedInstance];
}
- (id)init
{
if ([self class] != nil)
self = [super init])
return self;
}
#end
But alloc never gets called.
Solved. See the end of http://www.cocoadev.com/index.pl?SingletonDesignPattern