Schedule Sprite at Random Time Cocos2d 3.0 - cocos2d-iphone

I want to schedule these two sprites at random time during game play, then keep changing the time so the sprites appear randomly
I believe that something like this has to be done but it has not worked
int minDuration = 5.0;
int maxDuration = 30.0;
int rangeDuration = maxDuration - minDuration;
int randomDuration = (arc4random() % rangeDuration) + minDuration;
if (randomDuration == randomDuration) {
[self schedule:#selector(addshieldICON:) interval:10];
[self schedule:#selector(addspeedICON:) interval:10];
}
Any help or suggestions? Thank you

I would try something like this to start. It's difficult to tell from your question whether you want these two sprites to show up at the same time or if you want two separate schedules. Either way, you can modify this code to get the job done.
-(void)scheduleWithRandomInterval {
int minDuration = 5.0;
int maxDuration = 30.0;
int rangeDuration = maxDuration - minDuration;
int randomDuration = (arc4random() % rangeDuration) + minDuration;
[self scheduleOnce:#selector(showIcons) delay:randomDuration];
}
-(void)showIcons {
[self addshieldICON];
[self addspeedICON];
[self scheduleWithRandomInterval];
}
A word of caution though: I've had some issues with v2.1 adding a new scheduler from its own selector. If you notice that the scheduleWithRandomInterval is not called more than once, then you may need to do a bit of a hack job to get around it. In the past I've done it like this.
Instead of
[self scheduleWithRandomInterval];
I would use
[self delayedScheduleWithRandomInterval];
with a new function to handle a double delay
-(void)delayedScheduleWithRandomInterval {
[self scheduleOnce:#selector(scheduleWithRandomInterval) 0.01];
}

Related

Sprite not drawing/appearing on screen, Cocos2d

I'v got trouble getting my sprite to appear on screen using my current method. I got multiple sprites on the screen already, but I'v added this new one in a different manner as I'm going to manipulate it later on (handling different interactions and such). But I don't see why it doesn't appear on the screen when I run the program. I'v tried changing the z order without luck, but that might be because the sprite wasn't added in the init method like the others so the z order doesn't affect it in comparison to the background and such created in the init method. Anyways, got any clue for why it won't draw on screen?
- (void) addMonster {
CCSprite * monster = [CCSprite spriteWithImageNamed:#"Ghost.png"];
// Determine where to spawn the monster along the Y axis
CGSize viewSize = [CCDirector sharedDirector].viewSize;
int minY = monster.contentSize.height / 2;
int maxY = viewSize.height - monster.contentSize.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 = ccp(viewSize.width + monster.contentSize.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
CCActionMoveTo * actionMove = [CCActionMoveTo actionWithDuration:actualDuration
position:ccp(-monster.contentSize.width/2, actualY)];
CCActionCallBlock * actionMoveDone = [CCActionCallBlock actionWithBlock:^(CCNode *node) {
[monster removeFromParentAndCleanup:YES];
}];
[monster runAction:[CCActionSequence actions:actionMove, actionMoveDone, nil]];
}
//The call back function
-(void)gameLogic:(CCTime)dt {
[self addMonster];
}
- (id)init{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
if( (self = [super init]) ) {
self.userInteractionEnabled = YES;
//How often a new ghost gets produced
[self schedule:#selector(gameLogic:) interval:1.0];
//And some more code none relevant to this keeps going...
I am having the same problem.
The sprites i add do appear, but when i leave the scene and come back, they won't appear. As far as i know sprites needs to be added in the init method. When you add them at a later stage (in my case) they appear only once.
I am still looking for a solution to add the sprites at a later stage than the init method and appears more than once.
Maybe this answer helps you finding a solution.

cocos2d flappy bird demo

I am working with the flappy bird demo trying different things just to get to "know each other".
Going through the demo, I've managed to change the direction of the game to vertical scroll moving upwards.
Having reversed the CGFloat to negative values makes my obstacles move upward but once they are out of bounds they do not re-spawn.
If I change the values for a downward scroll they re-spawn as per the update method.
Can someone explain to me what I'm doing wrong with the x to y conversion? Why is the bottom recognized and the top of my screen not?
Thanks in advance
#import "MainScene.h"
static const CGFloat scrollSpeed = -280.f; //upwards
static const CGFloat firstObstaclePosition = -568.f;
static const CGFloat distanceBetweenObstacles = 80;
#implementation MainScene {
CCSprite *_hero;
CCPhysicsNode *_physicsNode;
NSMutableArray *_obstacles;
}
- (void)spawnNewObstacle {
CCNode *previousObstacle = [_obstacles lastObject];
CGFloat previousObstacleYPosition = previousObstacle.position.y;
if (!previousObstacle) {
// this is the first obstacle
previousObstacleYPosition = firstObstaclePosition;
}
CCNode *obstacle = [CCBReader load:#"Obstacle"];
obstacle.position = ccp(0, previousObstacleYPosition + distanceBetweenObstacles);
[_physicsNode addChild:obstacle];
[_obstacles addObject:obstacle];
}
- (void)update:(CCTime)delta {
_hero.position = ccp(_hero.position.x, _hero.position.y + delta * scrollSpeed);//move on Y axis
_physicsNode.position = ccp(_physicsNode.position.x, _physicsNode.position.y - (scrollSpeed *delta));//scroll in Y axis
//spawn more
NSMutableArray *offScreenObstacles = nil;
for (CCNode *obstacle in _obstacles) {
CGPoint obstacleWorldPosition = [_physicsNode convertToWorldSpace:obstacle.position];
CGPoint obstacleScreenPosition = [self convertToNodeSpace:obstacleWorldPosition];
if (obstacleScreenPosition.y < -obstacle.contentSize.height) {
if (!offScreenObstacles) {
offScreenObstacles = [NSMutableArray array];
}
[offScreenObstacles addObject:obstacle];
}
}
for (CCNode *obstacleToRemove in offScreenObstacles) {
[obstacleToRemove removeFromParent];
[_obstacles removeObject:obstacleToRemove];
// for each removed obstacle, add a new one
[self spawnNewObstacle];
}
}
- (void)didLoadFromCCB {
self.userInteractionEnabled = TRUE;
_obstacles = [NSMutableArray array];
[self spawnNewObstacle];
[self spawnNewObstacle];
[self spawnNewObstacle];
}
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
}
#end
I've attached the _physicsNode screenshot from SB.
It looks like your obstacles will be spawning fine if they are a short, constant height, and the distance between them value is large enough. It may be better to incorporate the height of the obstacles to get a more meaningful value of the distance variable. Just a thought.
The line -
obstacle.position = ccp(0, previousObstacleYPosition + distanceBetweenObstacles);
Could be -
obstacle.position = ccp(0, previousObstacleYPosition + distanceBetweenObstacles + previousObstacle.contentSize.height);
As for the problem of the vertical scrolling working downwards and not upwards I believe it is due to this line:
if (obstacleScreenPosition.y < -obstacle.contentSize.height) {
Since this line is responsible for determining when an obstacle is off the screen it has an effect on the spawning of the next obstacle. It makes sense why this line works for downwards scrolling but needs to be changed for upwards scrolling.
Try:
if (obstacleScreenPosition.y > (_physicsNode.contentSize.height + obstacle.contentSize.height)) {
You may or may not need the size of the obstacle depending on where it is anchored.
I hope this works, Good luck.

How to change ZOrder in a CCSequence?

I would like to know how to change the ZOrder of a CCSprite in a CCSequence. I have tried using CCCallBlock as suggested in another thread but it has bugged out and stops the other sprites of the same class moving. Is there another method someone can suggest?
crystalEntryPoint = [self position];
float xD = [crystal position].x - crystalEntryPoint.x;
float yD = [crystal position].y - crystalEntryPoint.y;
CGPoint dest = ccp(crystalEntryPoint.x + (xD * 2),crystalEntryPoint.y + (yD * 2));
float easingRate = 2;
CCMoveTo *moveTo = [CCMoveTo actionWithDuration:1 position:dest];
CCMoveTo *moveBack = [CCMoveTo actionWithDuration:1 position:crystalEntryPoint];
CCEaseInOut *easeTo = [CCEaseInOut actionWithAction:moveTo rate:easingRate];
CCEaseInOut *easeBack = [CCEaseInOut actionWithAction:moveBack rate:easingRate];
CCCallBlock *zOrderBehind = [CCCallBlock actionWithBlock:^{ [self setZOrder:kManaSpriteBehindCrystalZValue]; }];
CCCallBlock *zOrderInFront = [CCCallBlock actionWithBlock:^{ [self setZOrder:kManaSpriteZValue]; }];
CCSequence *seq = [CCSequence actions:easeTo,zOrderBehind,easeBack,zOrderInFront,nil]; //,zOrderInfront
CCRepeatForever *rep = [CCRepeatForever actionWithAction:seq];
[self runAction:rep];
Try CCCallBlockN which gives the block the node running the action as parameter. The current setup retains self inside the block which may cause the node not to dealloc later on because the sequence runs forever and thus holds a strong self-reference until the node deallocates - I can't say if cocos2d is able to clean it up properly, it should but it might not.
Not sure if this is related to your issue or not but it seems to me a likely explanation considering everything else in the code snippet looks fine.
CCCallBlockN *zOrderBehind = [CCCallBlockN actionWithBlock:^(CCNode* node){
[node setZOrder:kManaSpriteBehindCrystalZValue];
}];
CCCallBlockN *zOrderInFront = [CCCallBlockN actionWithBlock:^(CCNode* node){
[node setZOrder:kManaSpriteZValue];
}];
If that doesn't work either then try CCActionTween which allows changing any property by name.
id zOrderChange = [CCActionTween actionWithDuration:0.0
key:"zOrder"
from:kManaSpriteZValue
to:kManaSpriteZValue];
I'm not sure if from / to having the same value will work. If it doesn't try using 0 as the from parameter and perhaps even increasing duration to some low value like 0.01.

CCAnimation with low delay doesn't finish

I created a CCAnimation as seen below. I tried lowering the delay to something below .05f and the animation now fails to complete! Its only 8 frames. I don't know if I am doing something wrong. At first I thought it was a memory leak and I was losing the action, so I assigned it to a strong property to test that, and still did it. I'm not sure how the delay could cause my animation to fail to finish. I am running in the simulator at 60 frames per sec.
Using Kobold 2.0.4
Can anyone help?
else if([model currentState] == PROCESSING_FIRST_ACTION)
{
CCDirector* director = [CCDirector sharedDirector]; // process model
//Get the top left corner of the screen
int screen_height = director.screenSizeAsPoint.y;
int screen_width = director.screenSizeAsPoint.x;
id attacker = [model attacker];
id attackChoice = [attacker getRegisteredAttack];
CCAction* attack = [model.resourceManager animation: #"simple-attack-frame"];
CCSprite * attackSprite = [model.resourceManager sprite: #"simple-attack-frame-01"];
attackSprite.position = ccp(screen_width - rxa(80), screen_height - rya(80));
attackSprite.tag = 5;
self.action = attack;
CCNode * check = [self getChildByTag:5];
if(check == nil)
{
[self addChild: attackSprite];
[attackSprite runAction:attack];
}
}
resource manager:
-(id)animation: (NSString*)_resource
{
NSMutableArray *frames = [NSMutableArray array];
for(int i = 1; i <= 8; ++i)
{
[frames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"%#-0%d", _resource, i]]];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames: frames delay:1/60];
CCAction * action = [CCAnimate actionWithAnimation: animation];
return action;
}
In your line
CCAnimation *animation = [CCAnimation animationWithSpriteFrames: frames delay:1/60];
you're setting the delay to 1/60, but as 1 and 60 are both integers, 1/60 is 0. Try using 1.0f/60.0f and you'll get a floating point divide.
After digging around on the web I found a solution. I'm not the one who submitted this solution but I can attest that it fixed my problems:
https://github.com/cocos2d/cocos2d-iphone/commit/60f9cc98783b9a6a5635db4f468f83e0511c74c8

How to animate label's value in cocos2d?

I am making a slot machine game in iphone. I am using cocos2d as its language. I am greatly disturb coding for the method that will animate score in the game. The animation looks like with the fps. Can you help me do it. Animating the score in cocos2d. Can you share sample code that looks like what i need now. Thanks in advance.
Here is how I do my score. it is not really animated, but if you want it to be like fps this will do it. Just call this method when your score changes.
in your init method:
// create and initialize the _scoreLabel
_scoreLabel = [CCLabel labelWithString:#" "
dimensions:CGSizeMake(labelSizes.width,labelSizes.height)
alignment:UITextAlignmentLeft
fontName:#"Helvetica"
fontSize:20.0];
_scoreLabel.color = ccc3(255,255,255);
_scoreLabel.position = ccp((labelSizes.width / 2), (winSize.height - (labelSizes.height / 2)));
[self addChild:_scoreLabel z:1];
This is the score update method:
-(void)updateScore {
[_scoreLabel setString:[NSString stringWithFormat:#"Score: %d / %d", _score, _scoreToWin]];
}
Then to update the score when the score changes call it like this:
// Then later to set the Score
[self updateScore];
I've done it in this way:
_odd = _odd + _stage*value;
[self schedule:#selector(pointAdder) interval:1.0/(3.0*_odd)];
and
- (void)pointAdder {
if (_odd==0) {
[self unschedule:#selector(pointAdder)];
return;
}
else {
int tmp = [_lblScore.string intValue];
[_lblScore setString:[NSString stringWithFormat:#"%i",tmp+1]];
_odd--;
}
}