How to add to ammo if item collected sprite kit - sprite-kit

i have a game where the guy runs around and collects stuff. So I want the score keeper to update and increase if he collects an item and decrease if he uses the item. For example, life item. so here is the code I got so far for labels but that works with text score not integers. any ideas? thanks
- (void)setupUI
{
int barHeight = 45;
CGSize backgroundSize = CGSizeMake(self.size.width, barHeight);
SKColor *backgroundColor = [SKColor colorWithWhite:10 alpha:50];
SKSpriteNode *hudBarBackground = [SKSpriteNode spriteNodeWithColor:backgroundColor size:backgroundSize];
hudBarBackground.position = CGPointMake(0, self.size.height - barHeight);
hudBarBackground.anchorPoint = CGPointZero;
[_hudLayerNode addChild:hudBarBackground];
// 1
SKLabelNode *scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"AvenirNextCondensed-HeavyItalic"];
// 2
scoreLabel.fontSize = 20.0;
scoreLabel.text = #"Score: 0";
scoreLabel.name = #"scoreLabel";
scoreLabel.fontColor = [SKColor orangeColor];
// 3
scoreLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
// 4
scoreLabel.position = CGPointMake(self.size.width - self.size.width / 4, self.size.height - scoreLabel.frame.size.height + 3);
// 5
[_hudLayerNode addChild:scoreLabel];
_scoreFlashAction = [SKAction sequence: #[[SKAction scaleTo:1.5 duration:0.1],
[SKAction scaleTo:1.0 duration:0.1]]];
[scoreLabel runAction: [SKAction repeatAction:_scoreFlashAction count:10]];
}

double score; //property
-(void)setupUI {
//...
SKAction *tempAction = [SKAction runBlock:^{
scoreLabel.text = [NSString stringWithFormat:#"Score: 3.0f", self.score];
}];
SKAction *waitAction = [SKAction waitForDuration:0.2];
[scoreLabel runAction:[SKAction repeatActionForever:[SKAction sequence:#[tempAction,waitAction]]]];
//...
}

Related

Stop node rotation in Sprite Kit

I can't figure out how to stop node from rotating.
Why allowsRotation isn't disabling it?
Here's how I describe my node:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture:[self.spriteAtlas textureNamed:#"test"]];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = NO;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
badguy.physicsBody.velocity = CGVectorMake(0, 0);
badguy.physicsBody.categoryBitMask = CollisionTypeEnemy;
badguy.physicsBody.contactTestBitMask = CollisionTypePlayer | CollisionTypeWall | CollisionTypeEnemy;
badguy.physicsBody.collisionBitMask = CollisionTypeWall | CollisionTypePlayer | CollisionTypeEnemy;
badguy.physicsBody.mass = 10000;
badguy.physicsBody.restitution = 0;
badguy.physicsBody.dynamic = YES;
badguy.zPosition = 10;
On Update I call this method:
-(void)enemiesFollow
{
[self.world enumerateChildNodesWithName:#"badGuy" usingBlock:^(SKNode * _Nonnull badGuyNode, BOOL * _Nonnull stop) {
if((SDistanceBetweenPoints(self.player.position, badGuyNode.position) < 100)&&
(SDistanceBetweenPoints(self.player.position, badGuyNode.position) > 32))
{
SKAction * actionMove = [SKAction moveTo:self.player.position duration:2.0];
[badGuyNode runAction:actionMove];
}else{
[badGuyNode removeAllActions];
}
}];
}
Thanks to Skyler Lauren's suggestion, I am pretty much sure that the problem is in these lines:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture:[self.spriteAtlas textureNamed:#"test"]];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = NO;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
The point is that you can't set properties of a physics body before you create an actual body. So, just move those lines after you create a physics body and you will be good, like this:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(32,32)];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = YES;

Rotate sprite with path

Hi i have a sprite following a path that is a bezier curve and id like the sprite to rotate to the direction it is currently moving, i can tell it to follow the path by setting orientToPath to YES in
SKaction *enemyCurve = [SKAction followpath:cgpath asOffset:NO orientToPath:YES duration:5];
but this just results in the sprite facing the final point of movement. Any suggestions on how i can make it rotate to the current direction its traveling in?
I have included the code i use for the path below. Thank you for any help and suggestions.
-(void)AddEnemy:(MotionType *)motion :(CGPoint*)Start :(CGPoint*)Finish :(EnemyType)enemyType{
double curTime = CACurrentMediaTime();
if (enemyType == One) {
if(curTime > _nextAsteroidspawn)
{
float randSecs = [self randomValueBetween:0.20 andValue:1.0];
_nextAsteroidspawn = randSecs + curTime;
float randY = [self randomValueBetween:0.0 andValue:self.frame.size.height];
float randDuration = [self randomValueBetween:2.0 andValue:10.0];
SKSpriteNode *asteroid = [_Asteroids objectAtIndex:_nextAsteroid];
_nextAsteroid++;
if(_nextAsteroid >= _Asteroids.count){
_nextAsteroid = 0;
}
[asteroid removeAllActions];
asteroid.position = CGPointMake(self.frame.size.width+asteroid.size.width/2, 50);
asteroid.hidden = NO;
CGMutablePathRef cgpath = CGPathCreateMutable();
CGPoint startingPoint = CGPointMake(self.frame.size.width+asteroid.size.width/2 , 50);
CGPoint controlPoint1 = CGPointMake(160, 300);
CGPoint controlPoint2 = CGPointMake(200, 600);
CGPoint endingPoint = CGPointMake(0, self.frame.size.width - self.frame.size.width - asteroid.size.width / 2);
CGPathMoveToPoint(cgpath, NULL, startingPoint.x, startingPoint.y);
CGPathAddCurveToPoint(cgpath, NULL, controlPoint1.x, controlPoint1.y, controlPoint2.x
, controlPoint2.y, endingPoint.x
, endingPoint.y);
SKAction *enemyCurve = [SKAction followPath:cgpath asOffset:NO orientToPath:YES duration:5];
CGPoint location = CGPointMake(-self.frame.size.width-asteroid.size.width, randY);
SKAction *moveAction = [SKAction moveTo:location duration:randDuration];
SKAction *doneAction = [SKAction runBlock:(dispatch_block_t)^(){
asteroid.hidden = YES;
}];
SKAction *moveAsteroidActionWithDone = [SKAction sequence:#[enemyCurve,moveAction, doneAction]];
[asteroid runAction:moveAsteroidActionWithDone withKey:#"asteroidMoving"];
CGPathRelease(cgpath);
//[asteroid runAction: [SKAction repeatActionForever:[SKAction animateWithTextures:_Asteroids timePerFrame:0.1f]]];
}
The code that creates the enemy node can be seen bellow, i do not apply any rotations to the node.
In initWithSize:
_Asteroids = [[NSMutableArray alloc] initWithCapacity:knumAsteroids];
for(int i = 0; i < knumAsteroids; i++)
{
SKSpriteNode *asteroid = [SKSpriteNode spriteNodeWithImageNamed:#"enemyBasic1"];
asteroid.hidden = YES;
[_Asteroids addObject:asteroid];
[self addChild:asteroid];
}
In Update:
[self AddEnemy:BezierCurve :NULL :NULL:One];
The method in update just links to the code posted at the top which determines the path the enemy will take i have also updated it to include the entire method.

Background of 4 images added for each other

Please help.
I have 4 pictures.
I wanna show background with animation.
Each picture should fall over the previous animation alpha. As a result, I got a background of 4 images added for each other.
first show 1.png fade alpha to 1.
until one has not appeared until the end, starts the second image, etc.
var waitTime:NSTimeInterval = 0
var durTime:NSTimeInterval = 4.4
for var i = 0; i < 4; i++ {
let frostImage = SKSpriteNode(imageNamed: "a\(i)")
frostImage.position = CGPointMake(0, 0)
frostImage.zPosition = -1
frostImage.alpha = 0
frostImage.anchorPoint = CGPointZero
frostImage.size = CGSizeMake(256, 384)
self.addChild(frostImage)
self.array.addObject(frostImage)
let w = SKAction.waitForDuration(waitTime)
let s = SKAction.fadeAlphaTo(0.6, duration: durTime)
let a = SKAction.repeatAction(SKAction.sequence([w, s]), count: 1)
durTime -= 0.4
waitTime += 0.2
self.arrayAnim.addObject(a)
}
then
for node in self.array {
node.runAction(self.arrayAnim[ind1] as SKAction, completion: nil)
ind1++
}
I wrote for you but in objective-c, I think you can convert it to swift.
SKSpriteNode *bg1 = [SKSpriteNode spriteNodeWithImageNamed:#"bg1"];
bg1.zPosition = 1;
SKSpriteNode *bg2 = [SKSpriteNode spriteNodeWithImageNamed:#"bg2"];
bg2.zPosition = 2;
SKSpriteNode *bg3 = [SKSpriteNode spriteNodeWithImageNamed:#"bg3"];
bg3.zPosition = 3;
SKSpriteNode *bg4 = [SKSpriteNode spriteNodeWithImageNamed:#"bg4"];
bg4.zPosition = 4;
SKAction *action = [SKAction fadeAlphaTo:1.0 duration:1];
SKAction *wait = [SKAction waitForDuration:1];
SKAction *resetAlpha = [SKAction fadeAlphaBy:0.0 duration:0];
[self runAction:[SKAction repeatActionForever:[SKAction sequence:#[[SKAction runBlock:^{
[bg1 runAction:resetAlpha];
[bg2 runAction:resetAlpha];
[bg3 runAction:resetAlpha];
[bg4 runAction:resetAlpha];
}], [SKAction runBlock:^{
[bg1 runAction:action];
}], wait, [SKAction runBlock:^{
[bg2 runAction:action];
}], wait, [SKAction runBlock:^{
[bg3 runAction:action];
}], wait, [SKAction runBlock:^{
[bg4 runAction:action];
}], wait]]]];

Spritekit - Spawn waves of monsters

I'm making a simple racing game in which the monsters are spawned (randomly) from 3 out of the 5 lanes in the portrait mode.
-(void)addEnemy
{
SKSpriteNode *Enemy;
Enemy = [SKSpriteNode spriteNodeWithImageNamed:#"Enemy1"];
[Enemy setScale:.65];
Enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Enemy.size];
Enemy.physicsBody.categoryBitMask = obstacleCategory;
Enemy.physicsBody.dynamic = YES;
Enemy.zPosition = 2;
Enemy.physicsBody.contactTestBitMask = TurtleCategory;
Enemy.physicsBody.collisionBitMask = 0;
Enemy.physicsBody.usesPreciseCollisionDetection = YES;
Enemy.name = #"Enemy";
//selecting random y position for Enemy
int r = (arc4random() % 5) ;
Enemy.position = CGPointMake(48+r*56,self.frame.size.height);
[self addChild:Enemy];
SKAction *actionMove =
[SKAction moveTo:CGPointMake(Enemy.position.x,-80)
duration:1.43];
[Enemy runAction:actionMove];
SKSpriteNode *Enemy2;
Enemy2 = [SKSpriteNode spriteNodeWithImageNamed:#"Enemy1"];
[Enemy2 setScale:.65];
//Adding SpriteKit physicsBody for collision detection
Enemy2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Enemy.size];
Enemy2.physicsBody.categoryBitMask = obstacleCategory;
Enemy2.physicsBody.dynamic = YES;
Enemy2.zPosition = 2;
Enemy2.physicsBody.contactTestBitMask = TurtleCategory;
Enemy2.physicsBody.collisionBitMask = 0;
Enemy2.physicsBody.usesPreciseCollisionDetection = YES;
Enemy2.name = #"Enemy2";
//selecting random y position for Enemy
int r2 = (arc4random() % 5) ;
Enemy2.position = CGPointMake(48+r2*56,self.frame.size.height);
[self addChild:Enemy2];
SKAction *actionMove2 =
[SKAction moveTo:CGPointMake(Enemy2.position.x,-80)
duration:1.43];
[Enemy2 runAction:actionMove2];
SKSpriteNode *Enemy1;
Enemy1 = [SKSpriteNode spriteNodeWithImageNamed:#"boss1"];
[Enemy1 setScale:.65];
//Adding SpriteKit physicsBody for collision detection
Enemy1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Enemy1.size];
Enemy1.physicsBody.categoryBitMask = obstacleCategory;
Enemy1.physicsBody.dynamic = YES;
Enemy1.zPosition =2;
Enemy1.physicsBody.contactTestBitMask = TurtleCategory;
Enemy1.physicsBody.collisionBitMask = 0;
Enemy1.physicsBody.usesPreciseCollisionDetection = YES;
Enemy1.name = #"Enemy1";
int r1 = (arc4random() % 5) ;
Enemy1.position = CGPointMake(48+r1*56,self.frame.size.height);
[self addChild:Enemy1];
SKAction *actionMove1 =
[SKAction moveTo:CGPointMake(Enemy1.position.x,-80)
duration:1.43];
[Enemy1 runAction:actionMove1];
However, one of problem of this code is that monsters are sometimes spawned on top of each other. Is there a better way to do this?
Thanks
- (CGFloat)randomValueBetween:(CGFloat)low andValue:(CGFloat)high {
return (((CGFloat) arc4random() / 0xFFFFFFFFu) * (high - low)) + low;
}
I found this piece of code from a raywenderlich tutorial I think.
What u can do is call,
CGFloat r1 = [self randomValueBetween:0 andValue:3];
CGFloat r2 = [self randomValueBetween:3 andValue:6]; etc
that might give you different values that u can use as offset.

How can I stop SKAction

_pipeTexture1 = [SKTexture textureWithImageNamed:#"p2"];
_pipeTexture1.filteringMode = SKTextureFilteringNearest;
_pipeTexture2 = [SKTexture textureWithImageNamed:#"p1"];
_pipeTexture2.filteringMode = SKTextureFilteringNearest;
CGFloat distanceToMove = self.frame.size.width + 2 * _pipeTexture1.size.width;
SKAction* movePipes = [SKAction moveByX:-distanceToMove y:0 duration:0.01 * distanceToMove];
SKAction* removePipes = [SKAction removeFromParent];
_movePipesAndRemove = [SKAction sequence:#[movePipes, removePipes]];
SKAction* spawn = [SKAction performSelector:#selector(spawnPipes) onTarget:self];
SKAction* delay = [SKAction waitForDuration:2.0];
SKAction* spawnThenDelay = [SKAction sequence:#[spawn, delay]];
SKAction* spawnThenDelayForever = [SKAction repeatActionForever:spawnThenDelay];
[self runAction:spawnThenDelayForever];
How can i stop the animation action For some certain scenes?
Per the SKNode documentation you can use -(void)runAction:(SKAction *)action withKey:(NSString *)key to assign a name to the action when you first run it. Then you can later remove it with - (void)removeActionForKey:(NSString *)key.