How to get CCScrollLayer to scroll? - objective-c

I am trying to get CCScrollLayer to work in my cocos2d app, but it won't scroll.
Here is what I did:
Using the cocos2d template, created a iOS cocos2d project. Added the CCScrollLayer files, and imported into my HelloWorldLayer class. Added a method "layerWithLevelName" to create the layers.
In init, I created a few layers for testing. Below is the code for my HelloWorldLayer implementation. It is very basic, as I am just trying to get some layers to scroll.
#
// HelloWorldLayer implementation
#import "HelloWorldLayer.h"
#import "CCScrollLayer.h"
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
// return the scene
return scene;
}
-(CCLayer*) layerWithLevelName:(NSString*)name number:(int)number screenSize:(CGSize)screenSize
{
CCLayer *layer = [[[CCLayer alloc] init]autorelease];
int largeFont = [CCDirector sharedDirector].winSize.height / 9;
CCLabelTTF *layerLabel = [CCLabelTTF labelWithString:name fontName:#"Marker Felt" fontSize:largeFont];
layerLabel.position = ccp( screenSize.width / 2 , screenSize.height / 2 + 10 );
layerLabel.rotation = -6.0f;
layerLabel.color = ccc3(95,58,0);
[layer addChild:layerLabel];
return layer;
}
// 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]))
{
// ask director the the window size
NSMutableArray* _layers = [[NSMutableArray alloc]init];
CGSize screenSize = [CCDirector sharedDirector].winSize;
for (int i=0; i<3; i++)
{
int number = i;
NSString* name = [[NSString alloc]initWithFormat:#"level%d",i];
CCLayer* layer = [self layerWithLevelName:name number:number screenSize:screenSize];
[_layers addObject:layer];
[name release];
}
// Set up the swipe-able layers
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:_layers
widthOffset:230];
[self addChild:scroller];
// [scroller selectPage:0];
[scroller release];
[_layers release];
}
return self;
}
- (void) dealloc
{
[super dealloc];
}
#end
If you run the code, you will find that you can see the levels / scroll layer --> It seems to have loaded properly. But you can't scroll. What have I forgotten to do? What am I doing wrong?
EDIT: I am using cocos2d-iphone 1.1beta2

It seems that this is an issue with 1.1beta2.
A temporary workaround is to set scroller.stealTouches = NO;
I don't know what other side effects this has though.
EDIT:
Fix: Use updated CCTouchDispatcher files:
https://github.com/cocos2d/cocos2d-iphone/blob/develop/cocos2d/Platforms/iOS/CCTouchDispatcher.m
and corresponding .h file
https://github.com/cocos2d/cocos2d-iphone/blob/develop/cocos2d/Platforms/iOS/CCTouchDispatcher.h

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

Object Not initializing

So I am trying to make a Circle class in Objective-C. I know Java and OOP, and a little bit of Objective-C, but I cannot figure out why my class will not initialize. Here is the Circle.h:
#import <Foundation/Foundation.h>
#import "Image.h"
#interface Circle : NSObject
{
Image *img;
CGPoint pos;
}
-(id) init;
-(void) draw;
#end
and here is the Circle.m file:
#import "Circle.h"
#implementation Circle
-(id) init{
self = [super init];
if (self != nil) {
img = [[Image alloc] initWithImage:[UIImage imageNamed:#"circle.png"]];
pos = CGPointMake((CGFloat)200, (CGFloat)200);
}
img = [[Image alloc] initWithImage:[UIImage imageNamed:#"circle.png"]];
pos = CGPointMake((CGFloat)200, (CGFloat)200);
return self;
}
-(void) draw{
[img renderAtPoint: pos centerOfImage: YES];
}
#end
Then in my main class I call:
//player is the name of the circle object (Circle *player;)
[player init];
And in my render method I call:
[player draw];
When I run my app, the image will not draw, any help?
You probably want to say:
player = [[Circle alloc] init];
Rather than just [player init], since the latter will do nothing if player is nil (the default value for members).

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.

Cocos2d: CCSprite initWithFile in CCSprite subclass crashes

I have cocos2d project with custom CCSprite subclass:
MyCustomSprite.h:
#import "cocos2d.h"
#interface MyCustomSprite : CCSprite
#end
MyCustomSprite.m:
#import "MyCustomSprite.h"
#implementation MyCustomSprite
- (id)init
{
self = [super initWithFile:#"index.png"];
return self;
}
#end
For some strange reason, this code will crash with "EXC_BAD_ACCESS".
But in spite of this, if i init super as ususal and then write code from CCSprite's initWithFile and initWithTexture, it will work fine:
self = [super init];
if (self) {
// Code from CCSprite.m - initWithFile
CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage: #"index.png"];
CGRect rect = CGRectZero;
rect.size = texture.contentSize;
// Code from CCSprite.m - iniWithTexture
[self setTexture:texture];
[self setTextureRect:rect];
return self;
}
What's the reason that the first example crashes, and second not and what's the difference between them?
Thanks for your answers!
Ok, the reason is bad CCSprite design. If we look to CCSprite.h, we can find:
-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
{
NSAssert(texture!=nil, #"Invalid texture for sprite");
// IMPORTANT: [self init] and not [super init];
if( (self = [self init]) )
}
And thats the reason. Instead of [super init] this method calls [self init], and creates recursion ([self init]-[super InitWithFile:]-[self initWithTexture]-[self init]-...).
.
So, the simplest way to solve this problem - just re-name your init method to something else (for example "initialize") and call it instead of init: [[MyCustomSprite
alloc] initialize].
Another approach that may work is just replace your code by this one:
- (id)init
{
self = [super init];
if (self != nil)
{
CCTexture2D *texture = [[CCTextureCache sharedTextureCache] addImage:#"my_image_name.png"];
CGRect rect = CGRectZero;
if (texture != nil)
{
rect.size = texture.contentSize;
}
[self setDisplayFrame:[CCSpriteFrame frameWithTexture:texture rect:rect]];
}
return self;
}
And a simpler way, if you are using CCSpriteFrameCache, would be just setting the display frame by
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"my_image_name.png"]
Hope to help somebody!

How to unload images in Cocos2d

I am working with cocos2d. At the first Default.png load as first splash, then splash1.png load as second splash. I see in Instruments, that memory don't free when I replace scene. How can I unload images from memory? Thanks!
#import "cocos2d.h"
#import "MainMenu.h"
#interface Splash : CCLayer {
NSMutableArray *m_pSplashes;
int m_nCurrentSplash;
CGSize m_szWinSize;
CCSequence *m_pSequence, *m_pSequenceDefault;
CCCallFunc *m_pCall;
CCSprite *m_pSplashDefault, *splash;
id m_pFadein, m_pDelay, m_pFadeout;
}
#property(nonatomic, retain) CCSequence *m_pSequence;
+(id) scene;
-(void) showNext: (id) sender;
#end
Implementation file
#import "Splash.h"
#implementation Splash
#synthesize m_pSequence;
+(id) scene {
CCScene *scene = [CCScene node];
Splash *layer = [Splash node];
[scene addChild: layer];
return scene;
}
-(id) init {
if( (self=[super init]) ) {
m_szWinSize = [[CCDirector sharedDirector] winSize];
m_pFadein = [CCFadeIn actionWithDuration:2];
m_pDelay = [CCDelayTime actionWithDuration:2];
m_pFadeout = [CCFadeOut actionWithDuration:2];
m_pCall = [CCCallFunc actionWithTarget:self selector:#selector(showNext:)];
m_nCurrentSplash = 0;
m_pSplashes = [[NSMutableArray alloc] init];
m_pSequenceDefault = [CCSequence actions:m_pFadeout, m_pCall, nil];
[m_pSplashes addObject:#"splash1.png"];
m_pSplashDefault = [[[CCSprite alloc] initWithFile:#"Default.png"] autorelease];
[m_pSplashDefault setRotation:-90];
[m_pSplashDefault setPosition:ccp(m_szWinSize.width/2, m_szWinSize.height/2)];
[self addChild:m_pSplashDefault];
[m_pSplashDefault runAction:m_pSequenceDefault];
[m_pFadein retain];
[m_pDelay retain];
[m_pFadeout retain];
[m_pCall retain];
}
return self;
}
-(void) showNext: (id) sender {
if ( m_nCurrentSplash >= [m_pSplashes count] )
{
CCScene *scene = [CCScene node];
id child = [MainMenu node];
[scene addChild:child];
[[CCDirector sharedDirector] replaceScene: [CCFadeTransition transitionWithDuration:1 scene:scene]];
[m_pCall release];
}
else
{
splash = [[[CCSprite alloc] initWithFile:[m_pSplashes objectAtIndex:m_nCurrentSplash]] autorelease];
[splash setPosition:ccp(m_szWinSize.width/2, m_szWinSize.height/2)];
splash.tag = 1;
[self addChild:splash];
m_nCurrentSplash ++;
m_pSequence = [CCSequence actions:m_pFadein, m_pDelay, m_pFadeout, m_pCall, nil];
[splash runAction:m_pSequence];
}
}
-(void) dealloc {
NSLog ( #"dealloc" );
[m_pSplashes release];
[m_pFadein release];
[m_pDelay release];
[m_pFadeout release];
[self removeAllChildrenWithCleanup:YES];
[super dealloc];
}
#end
Either you manually handle by using
[[CCTextureCache sharedTextureCache]removeTexture:(CCTexture2D *)tex]
or:
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
if you are sure the texture is no longer being use.