Reputation: 69
I am creating a side scrolling game with a node moving from right to left. The problem is when it goes off the screen it is not removing itself. The only way i can get it to work is by not calling my bat node method multiple times. but i need multiple bats coming onto the screen. The problem seems to be when i call my bat method more than once with either SKAction waitforDuration or performSelector afterDelay.
Bat Method
-(void) addBats
{ int random = arc4random_uniform(self.size.height/2);
bats = [SKSpriteNode spriteNodeWithImageNamed:@"Bat1.png"];
bats.physicsBody = [SKPhysicsBody bodyWithTexture:bats.texture size:bats.frame.size];
bats.position = CGPointMake(self.size.width * 9, random);
bats.zPosition = 4;
[bats setScale:0.3];
bats.physicsBody.categoryBitMask = enemyCategoryL4;
bats.physicsBody.dynamic = NO;
bats.physicsBody.contactTestBitMask = playerCategoryLevel4;
bats.physicsBody.usesPreciseCollisionDetection = YES;
[L4foregroundNode addChild:bats];
SKAction *up = [SKAction moveByX:-1 y: -40 duration:1];
SKAction *down = [SKAction moveByX:-1 y:40 duration:1];
SKAction *action1 = [SKAction repeatActionForever:[SKAction sequence:@[up, down]]];
SKAction *action2 = [SKAction moveByX:-self.size.width * 10 y:0 duration:40.0];
SKAction *group = [SKAction group:@[action1, action2]];
[bats runAction:group];
}
-(void) update:(NSTimeInterval) currentTime {
if(bats.position.x < -50)
{
[bats removeFromParent];
[self addBats];
}
}
The above only works if i call bats once every time. Is there a way i can call more than once and remove the bat each time one goes off screen?
Upvotes: 0
Views: 283
Reputation: 437
For each bat you create in addBats you can use runAction:completion: to run your scrolling action and then in the completion block remove the node from parent. The problem is probably that when you add multiple nodes you are losing reference to the one you want to remove.
This code should do what you want (untested):
SKAction *up = [SKAction moveByX:-1 y:-40 duration:1];
SKAction *down = [SKAction moveByX:-1 y:40 duration:1];
SKAction *action1 = [SKAction repeatActionForever:[SKAction sequence:@[up, down]]];
[bats runAction:action1];
SKAction *scroll = [SKAction moveByX:-self.size.width * 10 y:0 duration:40.0];
[bats runAction:scroll completion:^{
[bats removeFromParent];
}];
Upvotes: 1
Reputation: 13665
Here is an example about how you can create a sprite, move it until it ends up off-screen and remove it right after that:
#import "GameScene.h"
@interface GameScene()
@property (nonatomic, strong)SKSpriteNode *sprite;
@end
@implementation GameScene
-(void)didMoveToView:(SKView *)view{
self.sprite = [SKSpriteNode spriteNodeWithColor:[SKColor purpleColor] size:CGSizeMake(50.0f,50.0f)];
//Place a sprite on right edge of the screen (I assume that your view and a scene have same size)
self.sprite.position = CGPointMake(self.frame.size.width, self.frame.size.height / 2.0f);
SKAction *moveSprite = [SKAction moveTo:CGPointMake(-self.sprite.size.width, self.frame.size.height / 2.0f) duration:5.0f];
SKAction *removeSprite = [SKAction removeFromParent];
SKAction *sequence = [SKAction sequence:@[moveSprite, removeSprite]];
[self addChild:self.sprite];
[self.sprite runAction:sequence withKey:@"moving"];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (self.sprite.parent) {
NSLog(@"Sprite has a parent");
}else{
NSLog(@"Sprite doesn't have a parent");
}
}
@end
Try this code with, and without [SKAction removeFromParent]
(see what is printed after sprite is off screen in both cases).
Upvotes: 1