CCSprite not rendering when made in a method from an external class - objective-c

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];

Related

CCLayer is null

I am trying to change the color of a CCLayerColor called bgColorLayer, however when I check to see if it is initialized it returns null. I have a color picker that calls the setBGColor: method. I know the colorpicker is calling the method and it is spitting out the correct colors. I am just at a loss as to why the bgColorLayer is null.
This is Cocos2D for Mac.
Any thoughts on why?
In my AppDelegeate method I have an IBOUTLET that is is tied to the NSColorWell
- (IBAction)colorwellBackground:(id)sender {
NSLog(#"Color Well: %#", [sender color]);
// Yes I know the sender color isn’t passing the correct value
AnimationViewerLayer * bkg = [AnimationViewerLayer alloc];
[bkg setBGColor:[sender color]];
}
AnimationViewerLayer.h
#interface AnimationViewerLayer : CCLayer
{
CCLayerColor * bgColorLayer;
}
+ (CCScene *) scene;
#end
AnimationViewLayer.m
#import "AnimationViewerLayer.h"
#implementation AnimationViewerLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
AnimationViewerLayer *layer = [AnimationViewerLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init])) {
float red = 25.0 * 255;
bgColorLayer = [CCLayerColor layerWithColor:ccc4(57, 109, 58, 255)];
[self addChild:bgColorLayer z:1];
}
return self;
}
- (void) setBGColor: (ccColor3B) color{
NSLog(#"SET BG COLOR");
[bgColorLayer setColor:ccRED];
}
- (void) dealloc {
[super dealloc];
}
#end

How to update gamehud in a CCSprite or CCNode, Cocos2d

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];
}

why is this OCUnit test failing?

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.

Setup and send custom delegate method within init?

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;
}

NSInvocation invocationWithMethodSignature, method signature argument cannot be nil

I followed tutorial from cocos2d official site . I try to create some items for a menu when creating them i pass a selector with one parameter. For each item i pass different selector . I think here is the problem , but i dont see realy why here is the problem. My header file looks :
// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"
#import "CCTouchDispatcher.h"
// HelloWorldLayer
#interface HelloWorldLayer : CCLayer {
CCSprite *first;
CCSprite *second;
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
- (void) setUpMenus;
- (void) doSomethingOne: (CCMenuItem *) menuItem;
- (void) doSomethingTwo: (CCMenuItem *) menuItem;
- (void) doSomethingThree: (CCMenuItem *) menuItem;
#end
Implementation file :
// Import the interfaces
#import "HelloWorldLayer.h"
// HelloWorldLayer implementation
#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;
}
- (void) doSomethingOne: (CCMenuItem *) menuItem
{
NSLog(#"The first menu was called");
}
- (void) doSomethingTwo: (CCMenuItem *) menuItem
{
NSLog(#"The second menu was called");
}
- (void) doSomethingThree: (CCMenuItem *) menuItem
{
NSLog(#"The third menu was called");
}
// 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])) {
first = [CCSprite spriteWithFile:#"seeker.png"];
first.position = ccp(100, 100);
[self addChild:first];
second = [CCSprite spriteWithFile:#"Icon.png"];
second.position = ccp(50, 50);
[self addChild:second];
[self schedule:#selector(nextFrame:)];
[self setUpMenus];
self.isTouchEnabled = YES;
}
return self;
}
- (void) registerWithTouchDispatcher {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
- (BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
- (void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [self convertTouchToNodeSpace: touch];
[second stopAllActions];
[second runAction: [CCMoveTo actionWithDuration:1 position:location]];
}
- (void) nextFrame:(ccTime)dt {
first.position = ccp( first.position.x + 100*dt, first.position.y );
if (first.position.x > 480+32) {
first.position = ccp( -32, first.position.y );
}
}
- (void) setUpMenus {
CCMenuItemImage *menuItem1 = [CCMenuItemImage itemFromNormalImage:#"myfirstbutton.png"
selectedImage:#"myfirstbutton_selected.png"
target:self
selector:#selector(doSomenthingOne:)];
CCMenuItemImage *menuItem2 = [CCMenuItemImage itemFromNormalImage:#"mysecondbutton.png"
selectedImage:#"mysecondbutton_selected.png"
target:self
selector:#selector(doSomenthingTwo:)];
CCMenuItemImage *menuItem3 = [CCMenuItemImage itemFromNormalImage:#"mythirdbutton.png"
selectedImage:#"mythirdbutton_selected.png"
target:self selector:#selector(doSomenthingThree:)];
CCMenu *myMenu = [CCMenu menuWithItems:menuItem1,menuItem2,menuItem3, nil];
[myMenu alignItemsVertically];
[self addChild:myMenu];
}
// 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
You've got the same typo in all three menu item creation calls. You're telling the menu items that the selector they should use is called doSomenthing... (note the spurious n in the middle):
CCMenuItemImage *menuItem1 = [... selector:#selector(doSomenthingOne:)];
CCMenuItemImage *menuItem2 = [... selector:#selector(doSomenthingTwo:)];
CCMenuItemImage *menuItem3 = [... selector:#selector(doSomenthingThree:)];
but the actual names of your methods are doSomethingOne:, doSomethingTwo:, and doSomethingThree:.
The exact cause of the error message is that later, when the menu item needs to perform that selector, it will ask your class to tell it the method signature for the selector you gave it. Since you gave the item an incorrect selector, your class doesn't know the signature, and it returns nil. The menu item tries to construct an NSInvocation object anyways to perform its action, which fails because the invocation can't be created with a nil signature.
Fix the typos and everything should work fine.