I'm trying to build something similar to Canabalt, adding holes and different heights between buildings (modules). You can see a screenshot of how the game is looking right now at: http://twitpic.com/4kb5jd
Here is the code I'm currently using:
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] )) {
moduleSize = 160;
screenSize = [[CCDirector sharedDirector] winSize];
CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"ModulesScene1.plist"];
CCTexture2D* gameArtTexture = [[CCTextureCache sharedTextureCache] addImage:#"ModulesScene1.png"];
// Create the background spritebatch
spriteBatch = [CCSpriteBatchNode batchNodeWithTexture:gameArtTexture];
[self addChild:spriteBatch];
numStripes = 1;
/* BEGIN MODULES */
NSString* frameName = [NSString stringWithFormat:#"Module0-hd.png"];
CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(0, screenSize.height / 2);
[spriteBatch addChild:sprite z:0 tag:0];
frameName = [NSString stringWithFormat:#"Module0-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake((moduleSize - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:1 tag:1];
frameName = [NSString stringWithFormat:#"Module1-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake((moduleSize * 2) - 1.1f, screenSize.height / 2);
[spriteBatch addChild:sprite z:2 tag:2];
frameName = [NSString stringWithFormat:#"Module2-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 3) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:3 tag:3];
frameName = [NSString stringWithFormat:#"Module0-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 4) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:4 tag:4];
frameName = [NSString stringWithFormat:#"Module1-hd.png"];
sprite = [CCSprite spriteWithSpriteFrameName:frameName];
sprite.anchorPoint = CGPointMake(0, 0.5f);
sprite.position = CGPointMake(((moduleSize * 5) - 1.1f), screenSize.height / 2);
[spriteBatch addChild:sprite z:5 tag:5];
/* END MODULES */
// Get current scrollSpped
scrollSpeed = [[GameManager sharedGameManager] scrollSpeed];
speedFactors = [[CCArray alloc] initWithCapacity:numStripes];
[speedFactors addObject:[NSNumber numberWithFloat:2.5f]];
NSAssert([speedFactors count] == numStripes, #"speedFactors count does not match numStripes!");
[self scheduleUpdate];
}
return self;
}
-(void) update:(ccTime)delta
{
CCSprite* sprite;
scrollSpeed = [[GameManager sharedGameManager] scrollSpeed];
CCARRAY_FOREACH([spriteBatch children], sprite)
{
NSNumber* factor = [speedFactors objectAtIndex:0];
CGPoint pos = sprite.position;
pos.x -= scrollSpeed * [factor floatValue];
if (pos.x < -screenSize.width)
{
pos.x += ((screenSize.width * 2) - 2);
int x = (arc4random() % 3);
int xHole = (arc4random() % 10);
NSString *randomName = nil;
CCSpriteFrame *randomFrame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:randomName];
[sprite setDisplayFrame:randomFrame];
}
sprite.position = pos;
}
}
to add holes between the buildings you could add a simple rand() function like that in the init method:
...
sprite.position = CGPointMake(((moduleSize * 3) - 1.1f + (rand()%40)), screenSize.height / 2);
...
this will add a random gap (max 40 points)
Related
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.
In my app, I have an image that acts as the ground, and scrolls along the bottom. I initialize and scroll it with:
-(void)initalizingScrollingBackground
{
for (int i = 0; i < 2; i++)
{
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:#"Bottom_Scroller"];
bg.zPosition = BOTTOM_BACKGROUND_Z_POSITION;
bottomScrollerHeight = bg.size.height;
bg.position = CGPointMake((i * bg.size.width) + (bg.size.width * 0.5f) - 1, bg.size.height * 0.5f);
bg.name = #"bg";
bg.physicsBody = [SKPhysicsBody bodyWithTexture:bg.texture size:bg.texture.size];
bg.physicsBody.categoryBitMask = bottomBackgroundCategory;
bg.physicsBody.contactTestBitMask = flappyBirdCategory;
bg.physicsBody.collisionBitMask = 0;
bg.physicsBody.affectedByGravity = NO;
[self addChild:bg];
}
}
- (void)moveBottomScroller
{
[self enumerateChildNodesWithName:#"bg" usingBlock: ^(SKNode *node, BOOL *stop)
{
SKSpriteNode * bg = (SKSpriteNode *) node;
CGPoint bgVelocity = CGPointMake(-BG_VELOCITY, 0);
CGPoint amtToMove = CGPointMultiplyScalar(bgVelocity,_dt);
bg.position = CGPointAdd(bg.position, amtToMove);
//Checks if bg node is completely scrolled of the screen, if yes then put it at the end of the other node
if (bg.position.x + bg.size.width * 0.5f <= 0)
{
bg.position = CGPointMake(bg.size.width*2 - (bg.size.width * 0.5f) - 2,
bg.position.y);
}
}];
}
However, after it scrolls for so long, it shows a gap in it, as shown below. How can I fix this?
What I'd do is:
// This would go in the init or didMoveToView method of your scene
const NSUInteger numBgs = 3;
for (NSUInteger i = 0; i < numBgs; i++) {
CGFloat color = 0.2f * i;
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithColor:[UIColor colorWithRed:color green:color blue:color alpha:1.0] size:CGSizeMake(512, 300)];
bg.anchorPoint = CGPointMake(0.5, 0);
bg.position = CGPointMake((i * bg.size.width) + (bg.size.width * 0.5f), CGRectGetMinY(self.frame));
bg.name = #"bg";
[self addChild:bg];
if (i == numBgs-1) { // Means it's last bg on the right
lastBg = bg;
}
}
[self enumerateChildNodesWithName:#"bg" usingBlock:^(SKNode *node, BOOL *stop) {
SKSpriteNode * bg = (SKSpriteNode *) node;
//Checks if bg node is completely scrolled of the screen, if yes then put it at the end of the other node
if (bg.position.x + bg.size.width * 0.5f <= 0)
{
bg.position = CGPointMake(lastBg.position.x + bg.frame.size.width,
bg.position.y);
lastBg = bg;
}
CGPoint bgVelocity = CGPointMake(-BG_VELOCITY, 0);
CGPoint amtToMove = CGPointMultiplyScalar(bgVelocity,_dt);
bg.position = CGPointAdd(bg.position, amtToMove);
}];
Where lastBg is an instance variable that points to the bg located at the top most right so that re-positioning is always going to be relative to this sprite.
Other things you can try are switching the check of the position before the re-positioning (as I did in the example) and also remove the check out of the enumerate block and do it independently of the re-positioning.
I used to do like in the example and it worked fine. Let me know how it does.
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..
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.
I have to move background images in iOS Coco2d but I am having a few difficulties. I have tried some solutions provided on some websites but have not been successful in getting them to work properly. Below is the code I am currently working on:-
The background moves smoothly the first time but it is not working properly after that:-
Code in init function :-
bg1 = [CCSprite spriteWithFile: #"bg1.png"];
bg1.anchorPoint = CGPointZero;
[self addChild:bg1 z:-2];
bg2 = [CCSprite spriteWithFile: #"bg1.png"];
[self addChild:bg2 z:-3];
bg2.anchorPoint = CGPointMake(480, 0);
// schedule a repeating callback on every frame
[self schedule:#selector(nextFrame:) interval:.4f];
- (void) nextFrame:(ccTime)dt {
id actionMove = [CCMoveTo actionWithDuration:.4 position:ccp(bg1.position.x - 100 * dt, bg1.position.y)]; //winSize.height/2)];
id actionMove1 = [CCMoveTo actionWithDuration:.4 position:ccp(bg2.position.x - 100 * dt, bg2.position.y)]; //winSize.height/2)];
id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[bg1 runAction:[CCSequence actions:actionMove,actionMoveDone, nil]];
[bg2 runAction:[CCSequence actions:actionMove1,actionMoveDone, nil]];
}
-(void)spriteMoveFinished:(id)sender {
CCSprite *sprite = (CCSprite *)sender;
if(sprite == bg1) {
if (bg1.position.x < -480) {
[self removeChild:bg1 cleanup:NO];
bg1.position = ccp( 480 , bg1.position.y );
[self addChild:bg1 z:-2];
}
}
else if(sprite == bg2)
if (bg2.position.x < -480) {
[self removeChild:bg2 cleanup:NO];
bg2.position = ccp( bg1.position.x+ 480 , bg1.position.y );
[self addChild:bg2 z:-3];
}
}
}
Try this, make sure you flip background 2.
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define MM_BG_SPEED_DUR ( IS_IPAD ? (6.0f) : (2.0f) )
-(void)onEnter
{
[super onEnter];
[self initBackground];
[self schedule: #selector(tick:)];
}
-(void)initBackground
{
NSString *tex = #"BG/Background.png";//[self getThemeBG];
mBG1 = [CCSprite spriteWithFile:tex];
mBG1.position = ccp(s.width*0.5f,s.height*0.5f);
[self addChild:mBG1 z:LAYER_BACKGROUND];
mBG2 = [CCSprite spriteWithFile:tex];
mBG2.position = ccp(s.width+s.width*0.5f,s.height*0.5f);
mBG2.flipX = true;
[self addChild:mBG2 z:LAYER_BACKGROUND];
}
-(void)scrollBackground:(ccTime)dt
{
CGSize s = [[CCDirector sharedDirector] winSize];
CGPoint pos1 = mBG1.position;
CGPoint pos2 = mBG2.position;
pos1.x -= MM_BG_SPEED_DUR;
pos2.x -= MM_BG_SPEED_DUR;
if(pos1.x <=-(s.width*0.5f) )
{
pos1.x = pos2.x + s.width;
}
if(pos2.x <=-(s.width*0.5f) )
{
pos2.x = pos1.x + s.width;
}
mBG1.position = pos1;
mBG2.position = pos2;
}
-(void)tick:(ccTime)dt
{
[self scrollBackground:dt];
}
I think this way is a little simpler. You initialize the backgrounds in initand move them in update.
In the init method:
// position backgrounds
CCSprite *bg1 = [CCSprite spriteWithSpriteFrame:spriteFrame];
CCSprite *bg2 = [CCSprite spriteWithSpriteFrame:spriteFrame];
CCSprite *bg3 = [CCSprite spriteWithSpriteFrame:spriteFrame];
bg1.anchorPoint = ccp(0, 0);
bg1.position = ccp(0, 0);
bg2.anchorPoint = ccp(0, 0);
bg2.position = ccp(bg1.contentSize.width-1, 0);
bg3.anchorPoint = ccp(0, 0);
bg3.position = ccp(2*bg1.contentSize.width-1, 0);
_backgrounds = #[bg1, bg2, bg3];
[self addChild:bg1 z:INT_MIN];
[self addChild:bg2 z:INT_MIN];
[self addChild:bg3 z:INT_MIN];
In the update method:
// endless scrolling for backgrounds
for (CCSprite *bg in _backgrounds) {
bg.position = ccp(bg.position.x - 50 * delta, bg.position.y);
if (bg.position.x < -1 * (bg.contentSize.width)) {
bg.position = ccp(bg.position.x + (bg.contentSize.width*2)-2, 0);
}
}
Note: the code is for Cocos2d 3.0