0
votes

I am developing a game for iOS 7, and it uses Spritekit.

The main skspritenode is a helicopter, and when this helicopter makes contact with a shrink bonus pickup, the helicopter shrinks to make navigation easier for the user. Here is the code for shrinking the helicopter that works as expected (self refers to the helicopter skspritenode):

SKAction *scaleHeli = [SKAction scaleBy:.70 duration:1];
SKAction *setPhysicsBody = [SKAction runBlock:^{
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.size.width, self.size.height)];
self.physicsBody.mass = 0.080944441;
self.physicsBody.restitution = 1.0f;
self.physicsBody.allowsRotation = FALSE;
self.physicsBody.categoryBitMask = APAColliderTypeShip;
self.physicsBody.collisionBitMask = APAColliderTypeCavePiece;
self.physicsBody.contactTestBitMask = APAColliderTypeCavePiece | APAColliderTypeBonusPickup;
}];

SKAction *seq = [SKAction sequence:@[scaleHeli, setPhysicsBody]];

[self runAction:seq];
_shrinkEnabled = true;

I have a timer setup for the shrink bonus that lasts for a predetermined amount of time:

-(void)startShrinkTimer
{
    //Creating the timer for the shield
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self    selector:@selector(countDownShrinkDuration) userInfo:Nil repeats:true];
    _timerSeconds = 15;
}

-(void)countDownShrinkDuration
{
    if(_timerSeconds > 0)
    {
        --_timerSeconds;
    }
    else if(_timerSeconds == 0)
    {
        [_sceneRef disableShrinkBonus];
        [_timer invalidate];
    }

    if(_timerSeconds < 5)
    {
        [_sceneRef shrinkWearingOut];
    }
}

If the timer gets to be less than 5 seconds then the shrinkWearingOut function is called, which adds a label to a node that fades in and out (self refers to the helicopter skspritenode):

SKLabelNode *downLbl = [[SKLabelNode alloc] init];
downLbl.text = @"↓";
downLbl.fontColor = [UIColor whiteColor];
downLbl.fontSize = 9.0f;
downLbl.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft;
downLbl.position = CGPointMake(0,-30);
downLbl.zPosition = 5;

SKAction *fadeOut = [SKAction fadeOutWithDuration: .2];
SKAction *fadeIn = [SKAction fadeInWithDuration: .2];
SKAction *pulse = [SKAction sequence:@[fadeOut,fadeIn]];

SKAction *pulseForever = [SKAction repeatActionForever:pulse];

SKSpriteNode *wearingOut = [[SKSpriteNode alloc] init];
wearingOut.name = @"wearingOut";

[wearingOut addChild:downLbl];

[wearingOut runAction:pulseForever];

[self addChild:wearingOut];

Once the timer reaches zero, the disableShrink function is called, which attempts to remove the pulsating node and scale the helicopter to its original size (self refers to the helicopter skspritenode):

[[self childNodeWithName:@"wearingOut"] removeFromParent];

SKAction *scaleHeli = [SKAction scaleBy:1.3 duration:1];
SKAction *setPhysicsBody = [SKAction runBlock:^{
    self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.size.width, self.size.height)];
    self.physicsBody.mass = 0.080944441;
    self.physicsBody.restitution = 0.0f;
    self.physicsBody.allowsRotation = FALSE;
    self.physicsBody.categoryBitMask = APAColliderTypeShip;
    self.physicsBody.collisionBitMask = APAColliderTypeCavePiece;
    self.physicsBody.contactTestBitMask = APAColliderTypeCavePiece | APAColliderTypeBonusPickup;

    _shrinkEnabled = false;
}];

SKAction *seq = [SKAction sequence:@[scaleHeli, setPhysicsBody]];

[self runAction:seq];

Problem # 1: This line of code: [[self childNodeWithName:@"wearingOut"] removeFromParent]; does not actually remove the pulsating node from the helicopter node, I have set a breakpoint here and verified that the node is not nil, yet it still seems to not remove the node. Very frustrating as I have used the exact same line of code with a different bonus pickup with a different name and it works just fine. The only difference is the other bonus pickup is using an skshapenode, either way they both inherit from sknode, so they should both function the same.

Problem # 2:The pulsating node is added successfully, but only pulses a couple of times, which I find strange because I use the exact set of skactions on a different bonus and that bonus pulses until it is removed from the helicopter node.

1

1 Answers

0
votes

Observations:

You should not use NSTimer. Instead use the update: method of SKScene to perform timed actions and if needed forward it to child nodes that need it. Or use SKAction runBlock sequenced with waitForDuration. NSTimer may not run synchronous with Sprite Kit updates / render loop, and they won't stop firing if a node or the scene is paused.

Check that you don't have multiple child nodes with the name "wearingOut". Sounds like you may have added more than one. The use of NSTimer may actually cause strange behavior because Sprite Kit may delay adding/removing nodes from the scene and so timing of add/remove of nodes may be an issue. This is a wild guess though.

The pulsing issue may also indicate multiple sprites, perhaps they pulsate asynchronously so they appear as not pulsating. Alternatively try the fadeAlphaTo: actions.

In general try using the documented initializers. There may be issues if you do just [[SKLabelNode alloc] init]. I ran into some issues with [SKSpriteNode node], not drawing for instance even after setting a texture. Instead do [SKLabelNode labelNodeWithFontNamed:@"Arial"] or any of the other designated initializers. Refer to the Sprite Kit Framework reference.