SKAction scale physicsBody - objective-c

I don't really know where to start. I have an image of a circle stored in an SKSpriteNode and a physicsBody that mirrors the size when it is created.
I am using an SKAction to scale down the size of the image though, and the physicsBody remains the same size. How can I scale down the physicsBody?
My code:
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"whiteball"];
sprite.size = CGSizeMake(20, 20);
sprite.position = CGPointMake(dx, CGRectGetHeight(self.frame)-dy);
sprite.name = #"ball";
sprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:sprite.size.width/2];
[self addChild:sprite];
SKNode *ballNode = [self childNodeWithName:#"ball"];
if (ballNode != Nil){
ballNode.name = nil;
SKAction *delay = [SKAction waitForDuration:3];
SKAction *scale = [SKAction scaleTo:0 duration:1]; // I want this to scale the physicsBody as well as the spriteNode...
SKAction *remove = [SKAction removeFromParent];
//put actions in sequence
SKAction *moveSequence = [SKAction sequence:#[delay, scale, remove]];
//run action from node (child of SKLabelNode)
[ballNode runAction:moveSequence];
}

If you set the size of the physicsbody to the size of the circle, you may achieve what you seek.
_circle = [SKSpriteNode spriteNodeWithImageNamed:#"cirlce"];
_circle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_circle.size.width/2];

Related

SpriteKit SKAction moveTo: distorted when app goes to background

In a SpriteKit game, I am using a forever repeating SKAction moveTo: to display metal shine/shimmer on a sprite. It's basically an SKCropNode mask that moves from one position to another, pauses, moves back to it's starting position, and repeats. The maskNode itself animates in the reverse direction.
This works fine, even with hundreds of them on the screen running for hours.
However, when the app goed to the background and comes back, all the positions of these nodes have changed. The animations still continue, but at the wrong positions. Metal shimmer everywhere on the screen, except where it should be.
I am not changing anything in the UIApplication delegate methods. Even if I pause the SKView while the app is in the background, the exact same thing happens.
// create the shine node
SKSpriteNode *shine = [SKSpriteNode spriteNodeWithTexture:#"metal_shine"];
shine.size = self.size;
// create the mask node
SKSpriteNode *maskNode = [SKSpriteNode spriteNodeWithTexture:#"disk_mask"]];
maskNode.size = self.size;
// create the crop node
SKCropNode *cropNode = [[SKCropNode alloc] init];
[cropNode addChild:shine];
cropNode.maskNode = maskNode;
cropNode.maskNode.position = CGPointMake(self.size.width * 0.5, self.size.height * -0.5);
cropNode.position = CGPointMake(self.size.width * -0.5, self.size.height * 0.5);
[self addChild:cropNode];
// add actions
SKAction *delayAction = [SKAction waitForDuration:1.0];
SKAction *pauseAction = [SKAction waitForDuration:3.0];
SKAction *resetActionMaskNode = [SKAction moveTo:CGPointMake(self.size.width * 0.5, self.size.height * -0.5) duration:0];
SKAction *moveActionMaskNode = [SKAction moveTo:CGPointMake(self.size.width * -0.5, self.size.height * 0.5) duration:0.6];
SKAction *resetActionCropNode = [SKAction moveTo:CGPointMake(self.size.width * -0.5, self.size.height * 0.5) duration:0];
SKAction *moveActionCropNode = [SKAction moveTo:CGPointMake(self.size.width * 0.5, self.size.height * -0.5) duration:0.6];
SKAction *repeatActionMaskNode = [SKAction repeatActionForever:[SKAction sequence:#[resetActionMaskNode, moveActionMaskNode, pauseAction]]];
SKAction *repeatActionCropNode = [SKAction repeatActionForever:[SKAction sequence:#[resetActionCropNode, moveActionCropNode, pauseAction]]];
// go
[cropNode.maskNode runAction:[SKAction sequence:#[delayAction, repeatActionMaskNode]] withKey:#"idleAnimation"];
[cropNode runAction:[SKAction sequence:#[delayAction, repeatActionCropNode]] withKey:#"idleAnimation"];

random x position issue

I have a circle spawning every few seconds and I have five lanes that I want them to spawn into but I want it to go to a different one at random. The code I'm using works properly but it won't let me use my five x positions? I've tried multiple solutions but they won't work. I'm still new to objective c so any help would be appreciated. (Also the code below isn't my whole method obviously but it's the only part I need to show.)
#import "GameScene.h"
int xPos1;
int xPos2;
int xPos3;
int xPos4;
int xPos5;
#implementation GameScene
-(void) addBall:(CGSize) size{
xPos1 = 8.5;
xPos2 = 74;
xPos3 = 138;
xPos4 = 203;
xPos5 = 267.5;
CGRect box = CGRectMake( arc4random() , self.frame.size.height, //pos
45, 45); //size
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:box];
SKShapeNode *circle = [SKShapeNode node];
circle.path = circlePath.CGPath;
circle.fillColor = [SKColor colorWithRed:(243.0f/255) green:(134.0f/255) blue:(48.0f/255) alpha:1.0];
circle.strokeColor = nil;
circle.lineWidth = 3;
//add physics
circle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:circle.frame.size.width/2];
//appy actions to move sprite
SKAction *wait = [SKAction waitForDuration:2];
SKAction *move = [SKAction moveToY:-self.size.height - 50 duration:2];
SKAction *remove = [SKAction removeFromParent];
SKAction *sequence = [SKAction sequence:#[wait, move, remove]];
SKAction *repeat = [SKAction repeatActionForever:sequence];
SKAction *spawn = [SKAction performSelector:#selector(addBall:) onTarget:self];
SKAction *delay = [SKAction waitForDuration:2.5];
SKAction *spawnThenDelay = [SKAction sequence:#[delay, spawn]];
[self runAction:spawnThenDelay];
[circle runAction:repeat];
[self addChild:circle];
}
Here are the different things I've tried using the x positions in arc4random:
CGRect box = CGRectMake( arc4random() %(xPos1, xPos2, xPos3, xPos4, xPos5) , self.frame.size.height, //pos
45, 45);
CGRect box = CGRectMake( arc4random(xPos1, xPos2, xPos3, xPos4, xPos5) , self.frame.size.height, //pos
45, 45);
I've also tried just putting the integers directly in there...
Try by creating an array of X Positions and selecting from that using a random index.
CGFloat xPositions[5] = {8.5,74,138,203,267.5};
int randomIndex = arc4random() % 5;
int randomXPosition = xPositions[randomIndex]
CGRect box = CGRectMake(randomXPosition, self.frame.size.height, 45, 45);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:box];

Gravity not affecting a node when endless background is enabled in sprite kit

When I implement the following code, my main character is not affected by gravity.
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball.png"];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.size.height/2];
ball.physicsBody.dynamic = YES;
ball.physicsBody.linearDamping = NO;
ball.physicsBody.angularDamping = NO;
ball.physicsBody.friction = 0;
ball.physicsBody.usesPreciseCollisionDetection = YES;
ball.position = CGPointZero;
ball.zPosition = 1;
[myWorld addChild:ball];
Here's the background
for (int i = 0; i < 2; i++) {
SKSpriteNode * bg = [SKSpriteNode spriteNodeWithImageNamed:#"background"];
//bg.anchorPoint = CGPointZero;
bg.position = CGPointMake(i * bg.size.width, 0);
bg.name = #"background.png";
//bg.physicsBody = [SKPhysicsBody bodyWithEdgeFromPoint:CGPointMake(-bg.frame.size.width/2, -bg.frame.size.height/2 +20) toPoint:CGPointMake(bg.frame.size.width/2, -bg.frame.size.height/2 + 20)];
bg.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:bg.frame];
[self addChild:bg];
}
I tried the code here Stack discussion here and everything works as expected, except the gravity on the y axis.
Gravity in the scene:
if (self = [super initWithSize:size]) {
self.anchorPoint = CGPointMake(0.5, 0.5);
self.physicsWorld.gravity = CGVectorMake(0, -2);
[self startGravityIncrease];
........
- (void)startGravityIncrease {
SKAction *blockAction = [SKAction runBlock:^{
CGVector gravity = self.physicsWorld.gravity;
gravity.dx += 0.6;
gravity.dy -= 0.3;
self.physicsWorld.gravity = gravity;
}];
SKAction *waitAction = [SKAction waitForDuration:5];
SKAction *sequenceAction = [SKAction sequence:#[waitAction, blockAction]];
SKAction *repeatAction = [SKAction repeatActionForever:sequenceAction];
[self runAction:repeatAction];
}
What am I doing wrong here?

How do I implement enemies that shoot?

I made a game with SpriteKit. I structured my game by coding a GameScene (SKScene) and a separate enemy class.
I want the spawning enemies to shoot a particle e.g. every 2 seconds (just moving an SKEmitterNode by the y axis) I tried to do it with a timer, but it doesn't really work.
I call my Enemy class from the gaming Scene with this code:
GameScene.m
-(void)enemiesLevel1{
EnemyClass* wave1 = [[EnemyClass alloc] init];
[wave1 enemiesLevel1:self];
}
And I am basically calling this method from EnemyClass.m
-(void)enemiesLevel1:(SKScene *)scene
{
enemy = [SKSpriteNode spriteNodeWithImageNamed:Enemy];
//Enemy Path
(...)
SKAction *followPath2 = [SKAction followPath:pathRef2
asOffset:NO
orientToPath:YES
duration: pathSpeed];
SKAction *forever = [SKAction repeatActionForever:followPath2];
//PhysicsBody Eigenshaften
enemy.physicsBody =[SKPhysicsBody bodyWithCircleOfRadius:enemy.size.width];
enemy.physicsBody.dynamic = YES;
enemy.physicsBody.categoryBitMask = enemyCategory;
[enemy runAction:forever];
[scene addChild:enemy];
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(weaponParticle)
userInfo:nil
repeats:YES];
}
-(void)weaponParticle{
screenHeight = self.frame.size.height;
screenWidth = self.frame.size.width;
//Schuss-Particles
enemyParticlePath = [[NSBundle mainBundle] pathForResource:#"ShootFire" ofType:#"sks"];
enemyParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:enemyParticlePath];
enemyParticle.physicsBody =[SKPhysicsBody bodyWithCircleOfRadius:0.2];
enemyParticle.physicsBody.categoryBitMask = shootCategory;
enemyParticle.physicsBody.contactTestBitMask = playerCategory;
//Schuss-Action
moveDown = [SKAction moveByX:0.0 y:-screenHeight duration:1.0];
remove = [SKAction removeFromParent];
weaponShot = [SKAction sequence:#[moveDown, remove]];
enemyParticle.position = CGPointMake(enemy.position.x, enemy.position.y+10);
[self addChild:enemyParticle];
[enemyParticle runAction: weaponShot];
}
The enemies are spawning 1 by 1 just how I wanted, but they can't shoot. Can anyone help me out?
Instead of scheduling NSTimer try something like this:
SKAction *shoot = [SKAction runBlock:^{
// add code that shoots here
}];
SKAction *wait = [SKAction waitForDuration:0.5];
[enemy runAction:[SKAction repeatActionForever:[SKAction sequence:#[shoot, wait]]]];

How to repeat this action 3 times instead of repeating it forever- Sprite Kit

How to repeat this action 3 or 2 times instead of repeating it forever
SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:#"AmericanTypewriter-Bold"];
label.text = #"Boom";
label.fontColor = [SKColor blackColor];
label.fontSize = 90;
label.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame)+25);
SKAction *disappear = [SKAction fadeAlphaTo:0.0 duration:0.2];
SKAction *appear = [SKAction fadeAlphaTo:1.0 duration:0.2];
SKAction *pulse = [SKAction sequence:#[disappear,appear]];
[label runAction:[SKAction repeatActionForever:pulse]];
[self addChild:label];
You need to use SKAction's repeatAction:count: method documented here.
[label runAction:[SKAction repeatAction:pulse count:3]];