Initializing CCSprite with objects in Cocos2d - cocos2d-iphone

I'm trying to pass the score from my main layer to one of my CCSprite's that initialize depending on said score. When I initialize my CCSprite with this:
//Main Layer
Platform *platform = [[Platform alloc] initWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:#"platform.png"] withScore:score];
//CCSprite Layer
-(id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame withScore:(int)initScore {
if( (self=[super init]) ) {
...
}
}
I get a score with no CCSprite Texture;
Subsequently, when I initialize with this:
//Main Layer
Platform *platform = [[Platform alloc]initWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:#"platform.png"]];
[platform setScore:score];
//CCSprite Layer
#property (readwrite) int score;
#synthesize score;
-(id) init {
if( (self=[super init]) ) {
...
}
}
I get a CCSprite Texture with no score(it's 0). What's a guy to do?

You need to pass along the sprite frame to super so in your first code example change it to this.
//CCSprite Layer
-(id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame withScore:(int)initScore {
if( (self=[super initWithSpriteFrame:spriteFrame]) ) {
...
}
return self; //Make sure to return self!
}

Related

COCOS2d CCLabelTTF not updating with player score - using a CCLayer Class

I would be very grateful for any advice you can offer as I am growing increasingly frustrated with an issue I am having - I also appreciate that the issue I am having is due to my lack of knowledge / understanding.
In an attempt to further my knowledge and stretch myself, I have chosen to create a PlayerStats class that handles the players scoring - and in time, health, etc.
I have the GameLevelLayer and PlayerStats classes implemented as follows:
GameLevelLayer.m as follows:
#import "GameLevelLayer.h"
#import "Player.h"
#import "PlayerStats.h"
#interface GameLevelLayer() {
CCTMXTiledMap *map;
Player *player;
PlayerStats *playerStats;
}
#end
#implementation GameLevelLayer
#synthesize grabber = _grabber;
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
GameLevelLayer *layer = [GameLevelLayer node];
PlayerStats *hudLayer = [PlayerStats node];
[scene addChild: layer];
[scene addChild: hudLayer];
return scene;
}
-(id) init {
if( (self=[super init]) ) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
playerStats = [[PlayerStats alloc]init];
...........
}
PlayerStats.m is as follows:
-(id) init
{
if ((self = [super init])) {
CGSize screenSize = [[CCDirector sharedDirector] winSize];
score = [CCLabelTTF labelWithString:#"Score : 0" dimensions:CGSizeMake(100,20) hAlignment:UITextAlignmentRight fontName:#"Marker Felt" fontSize:(18.0)];
int margin = 5;
score.position = ccp(screenSize.width - (score.contentSize.width/2) - margin, score.contentSize.height/2 + margin);
[self addChild:score z:99];
}
return self;
}
-(void)numberOfItemsCollected:(int)collected {
NSString *str = [score string];
CCLOG(#"What does the label say %#", str);
// This is actually displaying the correct string of what the score should be ..
[score setString:[NSString stringWithFormat:#"Score : %d", collected]];
}
When (from the GameLevelLayer.m) I initiate
[playerStats numberOfItemsCollected:5];
the CCLog shows that the label should show Score : 5 but the label itself does not update.
Any advice would be greatly appreciated as I am very aware that I am misunderstanding the issue.
I think the issue is to do with the Layer that I am updating not being the one I believe it is....
Thanks in advance.
I had declared the CCLabelTTF *score as an instance variable in the PlayerStats Class header. What a difference a night away from code makes.
Finally I managed to solve this issue set string to an empty string then reSet it to your string
[label setString:#""];
[label setString:yourString];

box2d collision detection, code

im new to programming, i have tried the ray wenderlich tutorial but im still confused.
i have a sprite called rock, and a sprite called player, im trying to detect collision between them. but im extremely confused. in need of some help.
-(void)addRock {
CCSprite *rock = [CCSprite spriteWithFile:#"rock.png"
rect:CGRectMake(0, 0, 27, 40)];
// Determine where to spawn the target along the X axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minX = rock.contentSize.width/2;
int maxX = winSize.width - rock.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
// Create the target slightly off-screen along the right edge,
// and along a random position along the X axis as calculated above
rock.position = ccp(actualX, 500);
[self addChild:rock];
// Determine speed of the sprite
int actualDuration = 5;//speed of sprite
}
- (id)init {
if ((self=[super init])) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *player = [CCSprite spriteWithFile:#"Player.png"
rect:CGRectMake(0, 0, 27, 40)];
player.position = ccp(winSize.width/2, winSize.height/4+15);
[self addChild:player];
[self schedule:#selector(gameLogicRock:) interval:0.2];
they are the two sprites, they spawn and position correctly, i only need to detect collision
You have to implement a new class for the collision or say contact listener based on some criteria as tag no. i have an example for you.
// ContactListener.h
#import "Box2D.h"
class ContactListener : public b2ContactListener
{
private:
void BeginContact(b2Contact* contact);
void EndContact(b2Contact* contact);
};
// ContactListener.mm
#import "ContactListener.h"
#import "cocos2d.h"
#import "BodyNode.h"
#import "GameScene.h"
void ContactListener::BeginContact(b2Contact* contact)
{
b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
{
BodyNode* bNodeA = (BodyNode*)bodyA->GetUserData();
BodyNode* bNodeB = (BodyNode*)bodyB->GetUserData();
if ((bNodeA.tag == GameSceneNodeTagBall && bNodeB.tag == GameSceneNodeTagHole) ||
(bNodeA.tag == GameSceneNodeTagHole && bNodeB.tag == GameSceneNodeTagBall))
{
switch (bNodeA.tag) {
case GameSceneNodeTagBall:
if ([bNodeA isKindOfClass:[Ball class]]) {
Ball* ball = (Ball*)bNodeA;
ball.sprite.visible = NO;
[[GameScene sharedGameScene] gameOver];
}
break;
case GameSceneNodeTagHole:
if ([bNodeB isKindOfClass:[Ball class]]) {
Ball* ball = (Ball*)bNodeB;
ball.sprite.visible = NO;
[[GameScene sharedGameScene] gameOver];
}
break;
default:
break;
}
}
}
}
This is an example of ball and hole collision. You can use this as per your requirement.
Hope this will help you.
Thanks!

How to popScene with transitions in cocos2d?

When i call relpaceScene or pushScene in cocos2d, I can add some transitions to it like:
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1 scene:scene]];
but when i call popScene, it takes no parameters, and no transition can be added. Is that so?
How can i popScene with desired transitions?
Per Guy in the cocos2d forums this seems to work: Link to Forum
Add this to CCDirector.h, just after the declaration -(void)popScene (line 402):
- (void) popSceneWithTransition: (Class)c duration:(ccTime)t;
Then add this to CCDirector.m, just after the definition of -(void)popScene (line 768):
-(void) popSceneWithTransition: (Class)transitionClass duration:(ccTime)t;
{
NSAssert( runningScene_ != nil, #"A running Scene is needed");
[scenesStack_ removeLastObject];
NSUInteger c = [scenesStack_ count];
if( c == 0 ) {
[self end];
} else {
CCScene* scene = [transitionClass transitionWithDuration:t scene:[scenesStack_ objectAtIndex:c-1]];
[scenesStack_ replaceObjectAtIndex:c-1 withObject:scene];
nextScene_ = scene;
}
}
You can call the method like this:
[[CCDirector sharedDirector] popSceneWithTransition:[CCSlideInRTransition class] durat
You can use Category as follows:
#interface CCDirector (PopTransition)
- (void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t;
#end
#implementation CCDirector (PopTransition)
- (void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t {
[self popScene];
// Make Transition
if (nextScene_) {
CCScene* scene = [transitionClass transitionWithDuration:t scene:nextScene_];
[scenesStack_ replaceObjectAtIndex:([scenesStack_ count] - 1) withObject:scene];
nextScene_ = scene;
}
}
#end
This way you need not to modify CCDirector class.
I modified Kailash's answer to work with cocos2d 2.1.
CCDirector+additions.h
#import "cocos2d.h"
#interface CCDirector (additions)
-(void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t;
#end
CCDirector+additions.m
#import "CCDirector+additions.h"
#implementation CCDirector (additions)
-(void)popSceneWithTransition:(Class)transitionClass duration:(ccTime)t {
[self popScene];
// Make Transition
if (_nextScene) {
CCScene* scene = [transitionClass transitionWithDuration:t scene:_nextScene];
[_scenesStack replaceObjectAtIndex:([_scenesStack count] - 1) withObject:scene];
_nextScene = scene;
}
}
#end
A more concise version of the above that actually releases the scene so it and its textures can be cleaned up as needed.
CCDirector+addition.h
#import "cocos2d.h"
#interface CCDirector (addition)
- (void) popSceneWithTransition:(Class)transitionClass duration:(ccTime)t;
#end
CCDirector+addition.m
#import "CCDirector+addition.h"
#implementation CCDirector (addition)
- (void) popSceneWithTransition:(Class)transitionClass duration:(ccTime)t {
[_scenesStack removeLastObject];
NSUInteger count = [_scenesStack count];
NSAssert(count > 0, #"Don't popScene when there aren't any!");
CCScene* scene = [transitionClass transitionWithDuration:t scene:[_scenesStack lastObject]];
[self replaceScene:scene];
}
#end
Without having to mess with Cocos2d internals you can do it like:
CCDirector *director = [CCDirector sharedDirector];
CCScene *currentScene = [director runningScene];
CGSize contentSize = [currentScene contentSize];
CCLayerColor *black = [[CCLayerColor alloc] initWithColor:ccc4(0, 0, 0, 0) width:contentSize.width height:contentSize.height];
[currentScene addChild:black];
[black runAction:[CCSequence actionOne:[CCFadeTo actionWithDuration:1.0f opacity:255]
two:[CCCallFunc actionWithTarget:director selector:#selector(popScene)]]];

CCMoveTo has no effect on my CCSprites

all. I have some function "tetrisl" in this function I want to move tetris sprites down:
-(void)tetrisL:(ccTime)dt {
Tetris *s = [[Tetris node]initWithArraySize:4];
[s createL];
for (CCSprite *new in s.tetrisArray) {
[self addChild:new];
id actionMove = [CCMoveTo actionWithDuration:3 position:ccp(new.position.x,0)];
[new runAction: actionMove];
}
[s release];
}
But it's don't work. I think because I try to move different sprites in same Action. How can i fix it? Thanks
Here is Tetris class
#interface Tetris : CCNode {
NSMutableArray *tetrisArray;
Blocks *tempBlock;
}
#property (nonatomic, retain) NSMutableArray *tetrisArray;
#property (nonatomic, retain) Blocks *tempBlock;
-(id)initWithArraySize:(int)sz;
-(void)createL;
#implementation Tetris
#synthesize tetrisArray;
#synthesize tempBlock;
-(id)initWithArraySize:(int)sz {
if( (self=[super init] )) {
tetrisArray = [[NSMutableArray alloc]initWithCapacity:sz];
}
return self;
}
-(void)createL {
int xPos = 10;
int yPos = 460;
for (int i = 0; i < 4; i++) {
tempBlock = [[Blocks node]initWithType:1];
tempBlock.blockSprite.position = ccp(xPos,yPos);
[tetrisArray addObject:tempBlock.blockSprite];
xPos = xPos + 26;
[tempBlock release];
}
}
-(void)dealloc {
[tempBlock release];
[tetrisArray release];
[super dealloc];
}
you can't assign one action to different sprites. One action - one sprite. You can use action copy function to dublicate actions.
But in your case action creates in loop, so it must be different actions...
may be problem somewhere else.
Defferent sprites cann't execute the same action at the same time, so you should copy the action, like following code:
sprite->runAction((CCActionInterval*)aciotn->copy->autoRelease());

Moving a background in a timer

How does one move the background image in a timer using cocos2d.
-(void) update:(ccTime)delta
What would be set in this method to move the background only on its y axis? I would like to scroll the map/background downwards as if the player is moving upwards.
I would like to then call this update method somehow every second or so.
-(void)update:(ccTime)delta
{
backgrd.position = ccp(backgrd.position.x,backgrd.position.y-10);
}
In your init:
-(id)init
{
self = [super init];
if(self)
{
//init your backgrd and stuff..
[self schedule:#selector(update:) interval: 1.0];
}
return self;
}