code crashes when sprite go to the position - ios

I use following code to show cloud randomly
- (void) cloudFly
{
int whichcloud = (arc4random() % 2) + 1;
CCSprite *target = [CCSprite spriteWithImageNamed:[NSString stringWithFormat:#"cloud%d.png",whichcloud]];
target.opacity = 0.3;
int minY = target.contentSize.height / 2;
int maxY = winSize.height - target.contentSize.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
target.position = ccp(winSize.width + (target.contentSize.width/2), actualY);
[self addChild:target];
int minDuration = 1.0;
int maxDuration = 3.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
id actionMove = [CCActionMoveTo actionWithDuration:actualDuration position:ccp(-target.contentSize.width / 2, actualY)];
id actionMoveDone = [CCActionCallFunc actionWithTarget:self selector:#selector(cloudFinished:)];
[target runAction:[CCActionSequence actions:actionMove, actionMoveDone, nil]];
[_clouds addObject:target];
}
- (void)cloudFinished:(id)sender
{
CCSprite *sprite = (CCSprite *)sender;
[sprite stopAllActions];
[self removeChild:sprite cleanup:YES];
}
but when the cloud flys to the position, this code will crash at line
- (void)cloudFinished:(id)sender
I use cocos2d-iphone v3.x, I try to comment/remove all codes in
- (void)cloudFinished:(id)sender
but it still crash. BWT, does ccsprite remove tag?

CCActionCallFunc is expecting a selector with no arguments, you should use CCActionCallBlock instead. There is an example in this answer.

try this:
[ _clouds addChild: target ];

Related

Best way to randomly move sprite forever in Sprite Kit

I have a sprite and I want to move it to random points forever. I have written this code, but I don't think it is efficient.
-(void)addBoss {
SKSpriteNode *boss = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
boss.position = CGPointMake(self.size.width + boss.size.width / 2.0, self.size.height / 2.0);
boss.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:boss.size];
boss.physicsBody.dynamic = YES;
boss.physicsBody.categoryBitMask = bossCategory;
boss.physicsBody.contactTestBitMask = bossContact;
boss.physicsBody.collisionBitMask = 0;
boss.zPosition = 1;
self.boss = boss;
self.bossHealth = bossHP;
CGPoint destination = CGPointMake(self.size.width - boss.size.width / 2.0, boss.position.y);
float time = length(boss.position, destination) / bossSpeed;
SKAction *move = [SKAction moveTo:destination duration:time];
[self addChild:boss];
[self.boss runAction:[SKAction sequence:#[move, [SKAction runBlock:^{
[self artificialIntelligence];
}]]]];
}
- (void)moveBoss {
float minimumX = self.size.width / 2.0 + self.boss.size.width / 2.0;
float maximumX = self.size.width - self.boss.size.width / 2.0;
float minimumY = self.boss.size.height / 2.0;
float maximumY = self.size.height - self.boss.size.height / 2.0;
int rangeX = maximumX - minimumX;
int rangeY = maximumY - minimumY;
float x = arc4random() % rangeX + minimumX;
float y = arc4random() % rangeY + minimumY;
CGPoint dest = CGPointMake(x, y);
float duration = length(self.boss.position, dest) / putinSpeed;
[self.boss runAction:[SKAction moveTo:dest duration:duration] completion:^{
[self moveBoss];
}];
}
-(void)artificialIntelligence {
[self moveBoss];
}
This code works fine, but I don't think that calling the move method recursively after movement finished is not the best solution.
What is the best way to solve this kind of problem?
This is a quick and dirty way to do what you asked:
-(void)moveCharacter {
SKNode *playerNode;
// get random position
CGPoint destination = [self randomPosition];
if(!CGPointEqualToPoint(playerNode.position, destination)) {
// check xPos
if(playerNode.position.x > destination.x) {
playerNode.position = CGPointMake(playerNode.position.x-1, playerNode.position.y);
}
if(playerNode.position.x < destination.x) {
playerNode.position = CGPointMake(playerNode.position.x+1, playerNode.position.y);
}
// check yPos
if(playerNode.position.y > destination.y) {
playerNode.position = CGPointMake(playerNode.position.x, playerNode.position.y-1);
}
if(playerNode.position.y < destination.y) {
playerNode.position = CGPointMake(playerNode.position.x, playerNode.position.y+1);
}
} else {
destinationReached = YES;
}
}
-(CGPoint)randomPosition {
CGRect screenRect = [[UIScreen mainScreen] bounds];
int xPos = arc4random() % (int)screenRect.size.width;
int yPos = arc4random() % (int)screenRect.size.height;
return CGPointMake(xPos, yPos);
}
There are many different variations on how to move your character. You could for example divide the difference of x,y into a fixed number of movements as to have the player move in a smooth line from point A to B. If you are physics to move your player, you would have to use CGVector instead of directly changing his x,y position.

how can we set tag for a CCSprite in cocos2D

I am new to cocos2D . I want to set Tag for CCSprite but this show me error in cococs2D version 3 while i have seen Answer on Stackoverflow [set tag] property but it does not work form me in cocos2d Version 3 .
What I requried is I have created two different Monster and I want to find out in Collision delegate which monster has collided .
Let me show you how I am creating Monster.
CCSprite *monster = [CCSprite spriteWithImageNamed:#"xyz.png"];
int minY = monster.contentSize.height / 2;
int maxY = self.contentSize.height - monster.contentSize.height / 2;
int rangeY = maxY - minY;
int randomY = (arc4random() % rangeY) + minY;
// 2
monster.position = CGPointMake(self.contentSize.width + monster.contentSize.width/2, randomY);
monster.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, monster.contentSize} cornerRadius:0];
monster.physicsBody.collisionGroup = #"monsterGroup";
monster.physicsBody.collisionType = #"monsterCollision";
[_physicsWorld addChild:monster z:1];
// 3
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int randomDuration = (arc4random() % rangeDuration) + minDuration;
// 4
CCAction *actionMove = [CCActionMoveTo actionWithDuration:randomDuration position:CGPointMake(-monster.contentSize.width/2, randomY)];
CCAction *actionRemove = [CCActionRemove action];
[monster runAction:[CCActionSequence actionWithArray:#[actionMove,actionRemove]]];
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair monsterCollision:(CCNode *)monster projectileCollision:(CCNode *)projectile
{
[monster removeFromParent];
[projectile removeFromParent];
score=score+1;
return YES;
}
here I want to fetch CCsprite by Tag or by image i am not sure how can i recognize CCsprite in collision delegate.
I'm not sure but I think you can set name property for a sprite when adding it like:
[self addChild:(CCNode *) z:(NSInteger) name:(NSString *)]
and then later get it by
getChildByName

Changing Sprite Spawns

Here is my code that I m using below and i want it to spawn from the bottom of the x-axis in portrait mode right now in spawns from the top in portrait mode how do i edit the code to do this?
- (void)addBalloon {
// Create sprite
SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:#"balloon"];
// Determine where to spawn the monster along the X axis
int minX = monster.size.width / 2;
int maxX = self.frame.size.width - monster.size.width / 2;
int rangeX = maxX - minX;
int actualX = (arc4random_uniform(rangeX)) + minX;
// Create the monster slightly off-screen along the top,
// and along a random position along the X axis as calculated above
monster.position = CGPointMake(actualX, self.frame.size.height +
monster.size.height/2);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, -
monster.size.height/2) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[monster runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
}
I'm not sure what you are asking here. You want to spawn a sprite on the bottom of the X-axis?
In case it is what I think you are asking, you only have to switch:
monster.position = CGPointMake(actualX, self.frame.size.height + monster.size.height/2);
&&
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, - monster.size.height/2) duration:actualDuration];
with:
monster.position = CGPointMake(actualX, - monster.size.height/2);
&&
SKAction * actionMove = [SKAction moveTo:CGPointMake(actualX, self.frame.size.height + monster.size.height/2) duration:actualDuration];

how to remove sprite object when we create touch in cocos2d?

I am new in cocos2d. I have a problem when we create new sprite object. It's not remove onto the display. Sprite object are not delete when we add new lives.(add heart sprite).
//Here I create a live which in heart shape.
-(id) init {
if( (self=[super init]) ) {
hearthArray = [[NSMutableArray alloc] init];
lives = 4;
for(NSInteger ilive = 0; ilive<lives; ilive++){
CCSprite *hearth = [CCSprite spriteWithFile:#"hearth.png"];
hearth.position = ccp( ((ilive+1)*50), winSize.height - 50);
[hearthArray insertObject:hearth atIndex:ilive];
[self addChild:hearth];
}
return self;
}
//Below code into remove the heart.(decrease lives).
- (void) addMonster:(ccTime)dt {
//select a random monster from the _monsters Array
int selectedMonster = arc4random() % [_monsters count];
Monster *monster = [_monsters objectAtIndex:selectedMonster];
int m = [monster movement];
CCSprite *spriteMonster = [[CCSprite alloc] initWithFile:[monster monsterSprite]];
spriteMonster.tag = [monster tag];
CGSize winSize = [CCDirector sharedDirector].winSize;
int minX = spriteMonster.contentSize.width / 2;
int maxX = winSize.width - spriteMonster.contentSize.width/2;
int rangeX = maxX - minX;
int actualY = (arc4random() % rangeX) + minX;
//BLOCK 2 - Determine speed of the monster
int minDuration = [monster minVelocity];
int maxDuration = [monster maxVelocity];
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
if(m == 1){
spriteMonster.position = ccp( actualY,winSize.height + spriteMonster.contentSize.height/2);
[self addChild:spriteMonster];
//BLOCK 4 - Create the actions
CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp( actualY,-spriteMonster.contentSize.height/2)];
CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[_monstersOnScreen removeObject:node];
[node removeFromParentAndCleanup:YES];
// Remove lifes
lives--;
// [[hearthArray lastObject] removeFromParentAndCleanup:YES];
[self removeChild:[hearthArray lastObject] cleanup:YES];
[hearthArray removeLastObject];
NSLog(#"m=1 when array : %#",hearthArray);
if(lives == 0)
[[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
}];
[spriteMonster runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
[_monstersOnScreen addObject:spriteMonster];
}
}
//Below into Add new lives using for loop.when touch particular object.
-(void)increaseLivesWhentouchCoin{
NSLog(#"lives is get when add live : %i",lives);
NSLog(#"hearthArray when toch coin: %#",hearthArray);
lives = lives+1;
NSLog(#"lives+1 : %i",lives);
for(NSInteger i = 0; i<lives; i++){
hearth = [CCSprite spriteWithFile:#"hearth.png"];
CGSize winSize = [CCDirector sharedDirector].winSize;
hearth.position = ccp( ((i+1)*50), winSize.height-50);
[hearthArray insertObject:hearth atIndex:i];
[self addChild:hearth];
}
NSLog(#"hearthArray out for loop: %#",hearthArray);
}
Please help me.Thanks in advance.
Your increaseliveswhentouch coin method should be like this..
-(void)increaseLivesWhentouchCoin{
CCSprite *hearth = [CCSprite spriteWithFile:#"hearth.png"];
CGSize winSize = [CCDirector sharedDirector].winSize;
hearth.position = ccp( ((lives+1)*50), winSize.height-50);
[hearthArray insertObject:hearth atIndex:lives];
[self addChild:hearth];
lives++;
}
You have to add just one heart object .There is no need to create all objects again,if you want to create remove all the objects first..

Sprite wont spawn [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
This code spawns a monster, but no enemy.
I expect an enemy to be spawned, why doesn't it?
#import "MyScene.h"
#import "GameOverScene.h"
static const uint32_t projectileCategory = 0x1 << 0;
static const uint32_t monsterCategory = 0x1 << 1;
static const uint32_t enemyCategory = 0x1 << 1;
// 1
#interface MyScene () <SKPhysicsContactDelegate>
#property (nonatomic) SKSpriteNode * player;
#property (nonatomic) NSTimeInterval lastSpawnTimeInterval;
#property (nonatomic) NSTimeInterval lastUpdateTimeInterval;
#property (nonatomic) int monstersDestroyed;
#property (nonatomic) int enemysDestroyed;
#end
static inline CGPoint rwAdd(CGPoint a, CGPoint b) {
return CGPointMake(a.x + b.x, a.y + b.y);
}
static inline CGPoint rwSub(CGPoint a, CGPoint b) {
return CGPointMake(a.x - b.x, a.y - b.y);
}
static inline CGPoint rwMult(CGPoint a, float b) {
return CGPointMake(a.x * b, a.y * b);
}
static inline float rwLength(CGPoint a) {
return sqrtf(a.x * a.x + a.y * a.y);
}
// Makes a vector have a length of 1
static inline CGPoint rwNormalize(CGPoint a) {
float length = rwLength(a);
return CGPointMake(a.x / length, a.y / length);
}
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
// 2
NSLog(#"Size: %#", NSStringFromCGSize(size));
// 3
self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
// 4
self.player = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
self.player.position = CGPointMake(self.player.size.width/2, self.frame.size.height/2);
[self addChild:self.player];
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
}
return self;
}
-(void)addMonster {
// Create sprite
SKSpriteNode * monster = [SKSpriteNode spriteNodeWithImageNamed:#"monster"];
monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size]; // 1
monster.physicsBody.dynamic = YES; // 2
monster.physicsBody.categoryBitMask = monsterCategory; // 3
monster.physicsBody.contactTestBitMask = projectileCategory; // 4
monster.physicsBody.collisionBitMask = 0; // 5
// Determine where to spawn the monster along the Y axis
int minY = monster.size.height / 2;
int maxY = self.frame.size.height - monster.size.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.position = CGPointMake(self.frame.size.width + monster.size.width/2, actualY);
[self addChild:monster];
// Determine speed of the monster
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(-monster.size.width/2, actualY) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
SKAction * loseAction = [SKAction runBlock:^{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}];
[monster runAction:[SKAction sequence:#[actionMove, loseAction, actionMoveDone]]];
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
self.lastSpawnTimeInterval += timeSinceLast;
if (self.lastSpawnTimeInterval > 1) {
self.lastSpawnTimeInterval = 0;
[self addMonster];
}
}
- (void)update:(NSTimeInterval)currentTime {
// Handle time delta.
// If we drop below 60fps, we still want everything to move the same distance.
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
self.lastUpdateTimeInterval = currentTime;
if (timeSinceLast > 1) { // more than a second since last update
timeSinceLast = 1.0 / 60.0;
self.lastUpdateTimeInterval = currentTime;
}
[self updateWithTimeSinceLastUpdate:timeSinceLast];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self runAction:[SKAction playSoundFileNamed:#"pew-pew-lei.caf" waitForCompletion:NO]];
// 1 - Choose one of the touches to work with
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
// 2 - Set up initial location of projectile
SKSpriteNode * projectile = [SKSpriteNode spriteNodeWithImageNamed:#"projectile"];
projectile.position = self.player.position;
projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2];
projectile.physicsBody.dynamic = YES;
projectile.physicsBody.categoryBitMask = projectileCategory;
projectile.physicsBody.contactTestBitMask = monsterCategory;
projectile.physicsBody.contactTestBitMask = enemyCategory;
projectile.physicsBody.collisionBitMask = 0;
projectile.physicsBody.usesPreciseCollisionDetection = YES;
// 3- Determine offset of location to projectile
CGPoint offset = rwSub(location, projectile.position);
// 4 - Bail out if you are shooting down or backwards
if (offset.x <= 0) return;
// 5 - OK to add now - we've double checked position
[self addChild:projectile];
// 6 - Get the direction of where to shoot
CGPoint direction = rwNormalize(offset);
// 7 - Make it shoot far enough to be guaranteed off screen
CGPoint shootAmount = rwMult(direction, 1000);
// 8 - Add the shoot amount to the current position
CGPoint realDest = rwAdd(shootAmount, projectile.position);
// 9 - Create the actions
float velocity = 480.0/1.0;
float realMoveDuration = self.size.width / velocity;
SKAction * actionMove = [SKAction moveTo:realDest duration:realMoveDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
[projectile runAction:[SKAction sequence:#[actionMove, actionMoveDone]]];
}
- (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster:(SKSpriteNode *)monster {
NSLog(#"Hit");
[projectile removeFromParent];
[monster removeFromParent];
self.monstersDestroyed++;
if (self.monstersDestroyed > 80) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES];
[self.view presentScene:gameOverScene transition: reveal];
}
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
// 1
SKPhysicsBody *firstBody, *secondBody, *thirdBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
thirdBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
thirdBody = contact.bodyA;
}
// 2
if ((firstBody.categoryBitMask & projectileCategory) != 0 &&
(secondBody.categoryBitMask & enemyCategory) != 0 &&
(thirdBody.categoryBitMask & monsterCategory) != 0)
{
[self projectile:(SKSpriteNode *) firstBody.node didCollideWithMonster:(SKSpriteNode *) secondBody.node];
[self projectile:(SKSpriteNode *) firstBody.node didCollideWithEnemy: (SKSpriteNode *) secondBody.node];
}
}
- (void)addEnemy {
// Create sprite
SKSpriteNode * enemy = [SKSpriteNode spriteNodeWithImageNamed:#"enemy"];
enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.size]; // 1
enemy.physicsBody.dynamic = YES; // 2
enemy.physicsBody.categoryBitMask = enemyCategory; // 3
enemy.physicsBody.contactTestBitMask = projectileCategory; // 4
enemy.physicsBody.collisionBitMask = 0; // 5
// Determine where to spawn the monster along the Y axis
int minY = enemy.size.height / 2;
int maxY = self.frame.size.height - enemy.size.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
enemy.position = CGPointMake(self.frame.size.width + enemy.size.width/2, actualY);
[self addChild:enemy];
// Determine speed of the monster
int minDuration = 1.0;
int maxDuration = 6.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction * actionMove = [SKAction moveTo:CGPointMake(-enemy.size.width/2, actualY) duration:actualDuration];
SKAction * actionMoveDone = [SKAction removeFromParent];
SKAction * loseAction = [SKAction runBlock:^{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}];
[enemy runAction:[SKAction sequence:#[actionMove, loseAction, actionMoveDone]]];
}
- (void)projectile:(SKSpriteNode *)projectile didCollideWithEnemy:(SKSpriteNode *)enemy {
NSLog(#"Hit");
[projectile removeFromParent];
[enemy removeFromParent];
self.enemysDestroyed++;
if (self.enemysDestroyed > 80) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES];
[self.view presentScene:gameOverScene transition: reveal];
}
}
#end
I am not sure if you realize this, but you never actually call addEnemy. Look through the code. You will find a call to addMonster but never addEnemy. Implementing the method is one thing- without calling the method, whatever is inside will never run.

Resources