SKEmitterNode settings not appearing - ios

I created an sks file with the settings I want it to have, and when I call the method of adding the node onto the scene, the emitter particles don't look anything similar to what I set up. Any reason why?
-(SKEmitterNode *)emitParticles
{
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"explosionParticles" ofType:#"sks"]];
emitter.position = CGPointMake(self.size.width/2, self.size.height/2);
emitter.targetNode = self.scene;
[self addChild:emitter];
return emitter;
}
What I want.
What I get.

Related

specific positioning of SKEmitterNode from a class to main scene

Im creating an spark affect for a bomb that rotates and scrolls across the screen using SKEmitterNode. I've come to a sticking point as i can't correctly position the spark effect. I can get the SKEmitterNode and spriteNode to move across the screen together with the spark affect positioned in the centre of the bomb while the bomb rotates. The effect i wish to achieve is the spark positioned correctly at the end of the wick on the bomb while the bomb rotates.
The first piece of code is from myScene:
MCBomb *_multiUp = [MCBomb spriteNodeWithImageNamed:#"MultiShotPowerUp"];
[_mainLayer addChild:_multiUp];
// Create spark.
NSString *bombSparkPath = [[NSBundle mainBundle] pathForResource:#"BombSpark" ofType:#"sks"];
SKEmitterNode *_bombSpark = [NSKeyedUnarchiver unarchiveObjectWithFile:bombSparkPath];
_bombSpark.targetNode = _mainLayer;
[_mainLayer addChild:_bombSpark];
_multiUp.spark = _bombSpark;
The next two pieces of code are from the class .m
-(void)updateSpark {
if (self.spark) {
self.spark.position = self.position;
}
and .h
#interface MCBomb : SKSpriteNode
#property (nonatomic) SKEmitterNode *spark;
-(void)updateSpark;
As soon as i add CGPointMake into the mix e.g.
self.spark.position = CGPointMake(0.9, 0.9);
when called the spriteNode floats across the screen and the SKEmitterNode appear bottom left corner static.
Or if i do something like:
self.spark.position = CGPointMake (self.size.width +50 , self.size.height + 400);
The SKEmitterNode is static in its new position and the spriteNode floats across the screen.
Or if i do this:
self.spark.position = CGPointMake (self.size.width +50 , self.size.height + 400);
self.position = self.spark.position;
I get both spriteNode and EmitterNode static in there new position.
As you can see, In my frustration i'm clutching at straws! The positioning is extreme just for affect, I'm still learning and could do with some advice on how to get the correct affect.
Below is the complete class, please see new comment:
-(void)spawnMultiShotPowerUp {
// Setting up Texture Atlas.
SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:#"Parts"];
MCBomb *_multiUp = [MCBomb spriteNodeWithImageNamed:#"MultiShotPowerUp"];
_multiUp.name = #"multiUp";
_multiUp.position = CGPointMake(-_multiUp.size.width, randomInRange(150, self.size.height -100));
_multiUp.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16.0];
_multiUp.physicsBody.categoryBitMask = mCMultiUpCategory;
_multiUp.physicsBody.collisionBitMask = 0;
_multiUp.physicsBody.velocity = CGVectorMake(10, randomInRange(-40, 40));
_multiUp.physicsBody.angularVelocity = M_PI;
_multiUp.physicsBody.linearDamping = 0.0;
_multiUp.physicsBody.angularDamping = 0.0;
[_mainLayer addChild:_multiUp];
// Create spark.
NSString *bombSparkPath = [[NSBundle mainBundle] pathForResource:#"BombSpark" ofType:#"sks"];
SKEmitterNode *_bombSpark = [NSKeyedUnarchiver unarchiveObjectWithFile:bombSparkPath];
_bombSpark.targetNode = _mainLayer;
_bombSpark.position = CGPointMake(20, 0);
_multiUp.spark = _bombSpark;
[_multiUp addChild:_bombSpark];
}
You have these two nodes you are creating:
MCBomb *_multiUp = [MCBomb spriteNodeWithImageNamed:#"MultiShotPowerUp"];
[_mainLayer addChild:_multiUp];
// Create spark.
NSString *bombSparkPath = [[NSBundle mainBundle] pathForResource:#"BombSpark" ofType:#"sks"];
SKEmitterNode *_bombSpark = [NSKeyedUnarchiver unarchiveObjectWithFile:bombSparkPath];
_bombSpark.targetNode = _mainLayer;
[_mainLayer addChild:_bombSpark];
but you are adding your spark to the mainLayer which is not correct for what you are trying to do. You need to add the spark as a child to your bomb instead of the mainLayer.
[_multiUp addChild:_bombSpark];
Keep in mind that the _bombSpark positioning has now changed because it is a child of _multiUp. That means _bombSpark's position 0,0 equals the center position of the _multiUp node.
Add a position to _bombSpark like this:
_bombSpark.position = CGPointMake(20,0);
That puts the spark 20 points up from the center of _multiUp. Play around with the exact x,y coordinate values until you get it to where it has to be.

Particle Effects Disappear When Transitioning to a New SKScene

I'm working on a game using Sprite Kit. I have a particle effect that runs when an object collides with another object; however, this particle effect seems to disappear when I add a transition to another SKScene. What's causing this disappearance, and how do I solve this issue?
Edit: By disappear I mean that it does not appear in the current scene when the scene is still transitioning with all the sprites still showing. It has a 2 second time interval, so shouldn't I be able to see it?
Here's the code for the particle effect and scene transition:
- (void)player:(SKSpriteNode *)player didCollideWithEnemy:(SKSpriteNode *)enemy {
Enemy *monster = (Enemy *)enemy;
if(!monster.isMoving){
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"MyParticle" ofType:#"sks"]];
emitter.position = player.position;
[self addChild: emitter];
isAlive = FALSE;
NSLog(#"Hit");
CrowdedData *crowdedData = [CrowdedData sharedManager];
crowdedData.score = score;
[player removeFromParent];
SKTransition *reveal = [SKTransition fadeWithDuration:2];
GameOver *scene = [GameOver sceneWithSize:self.view.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:scene transition:reveal];
}
}
SKTransition has two properties that are relevant to this:
[transition setPausesOutgoingScene:NO];
[transition setPausesIncomingScene:NO];
Both default to YES, causing either the outgoing in incoming scenes to be paused, which in turn pauses your emitter. For your purposes, setting the pausesOutgoingScene property to NO should be enough to fix this. More info in the docs:
https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKView/Reference/Reference.html

Changing SpriteKit Game Background At A Certain Score

I'm having a little trouble implementing a background change when the player hits a certain score.
I'm using the if(self.score>=10) line to tell my game to change the background but it doesn't seem to be working. I have no errors with this line but no results either.
What I have:
#implementation Scene{
SKScrollingNode * floor;
SKScrollingNode * back;
SKLabelNode * scoreLabel;
}
- (void) createBackground
{
back = [SKScrollingNode scrollingNodeWithImageNamed:#"back" inContainerWidth:WIDTH(self)];
if(self.score>=10){
back = [SKScrollingNode scrollingNodeWithImageNamed:#"image2" inContainerWidth:WIDTH(self)];
[back setAnchorPoint:CGPointZero];
[back setPhysicsBody:[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]];
back.physicsBody.categoryBitMask = backBitMask;
back.physicsBody.contactTestBitMask = birdBitMask;
[self addChild:back];
}
there are certain points you have to keep in your mind i think your both background contains physics body
1)may be and the time of transition they first background colliding with second background and they preventing each other to swap
change your collisionBitMask for both background ->prevent them for colliding
for eg
bg.physicsBody.categoryBitMask=bg1;
bg.physicsBody.collisionBitMask=0;
bg.physicsBody.contactTestBitMask=bg2;
bg.physicsBody.categoryBitMask=bg2;
bg.physicsBody.collisionBitMask=0;
bg.physicsBody.contactTestBitMask=bg1;
or use skaction to swap backgrounds
The way i would do this would be to create a brand new SKScene entirely with a new background.
Or if you want them to scroll to the next background. I would create two backgrounds.
Ex.
//this syntax is wrong (dont remember)
//initializing
SKSpriteNode *bg1 = [SKSpritenode spritenodefromImage:#"bg1"];
SKSpriteNode *bg1 = [SKSpritenode spritenodefromImage:#"bg1"];
bg1.position = CGPointMake(self.size.width/2, self.size.height/2);
bg2.position = CGPointMake(self.size.width/2 + bg1.size.width, self.size.height/2);
//////////////////////////////
//then when you want to scroll them
-(void)scrollBackgrounds
{
bg1.position = CGPointMake(bg1.position.x - 5, self.size.height/2);
bg2.position = CGPointMake(bg2.position.x -5 , self.size.height/2);
}

How to generate SKTexture from a modified SKSpriteNode?

So I have an SKSpriteNode which has undergone two SKActions which modify it's shape and coloring however I want to return the modified SKSpriteNode as an SKTexture which I can apply to another SKSpriteNode. This is what I'm currently using.
1) Generate the "modified" laserNode and store it as a property
-(void)generateLaserSprite
{
SKSpriteNode *laserNode = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:#"Laser.png"]];
[laserNode runAction:[SKAction group:#[[SKAction colorizeWithColor:[SKColor redColor] colorBlendFactor:100 duration:0.0],
[SKAction scaleXBy:0.4 y:0.7 duration:0.0],
]]];
_laserSprite = laserNode
}
2) Then a method from the SKScene calls this method to retrieve a copy of the property
-(SKSpriteNode*)retrieveLaserSprite
{
SKSpriteNode *laserNode = [_laserSprite copy];
laserNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(laserNode.size.width*0.8, laserNode.size.height*0.8)];
//other laserNode.physicsBody modifications
return laserNode;
The problem with this currently is that when I call the second method (retrieveLaserSprite), the returned LaserNode then shows up on screen as the original image (pre-SKAction), and then you can visibly see the SKActions take place on-screen.
It should actually be possible to create a texture from a sprite whose rendering properties have been modified using the -(SKTexture *)textureFromNode: method of the SKView class.
Your code would go like this:
-(SKSpriteNode*)retrieveLaserSprite {
SKTexture *tempTexture = [self.view textureFromNode:_laserSprite];
SKSpriteNode *laserNode = [SKSpriteNode spriteNodeWithTexture:tempTexture];
laserNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(laserNode.size.width*0.8, laserNode.size.height*0.8)];
//other laserNode.physicsBody modifications
return laserNode;
}
You should be able to accomplish this task using something like:
-(SKSpriteNode*)retrieveLaserSprite
{
SKTexture *texture = [self.view textureFromNode:[_laserSprite copy]];
SKSpriteNode *laserNode = [SKSpriteNode spriteNodeWithTexture:texture];
laserNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(laserNode.size.width*0.8, laserNode.size.height*0.8)];
//other laserNode.physicsBody modifications
return laserNode;
}

Access property of current SKScene?

I'm testing out a few different technologies to integrate into my Sprite Kit-powered game, and I'm stumbling on what I'm sure is a simple task.
The test project I'm using came as part of a framework that integrates Spine with Sprite Kit. Everything is contained (and defined) in a single ViewController (which creates one of four views depending on which option of a UISegmentedControl is currently selected). At the bottom of the screen I have a UISwitch which is hooked up to an action:
-(IBAction)changeCostume:(UISwitch *)sender {
if(sender.on) {
NSLog(#"New costume");
} else {
NSLog(#"Old costume");
}
}
The scene I'm working on is defined like this:
+ (SKScene *) buildAvatarWithSize:(CGSize) size
{
SpineSkeleton *avatar = [DZSpineSceneBuilder loadSkeletonName:#"test-avatar" scale:1]; //json
spSkeleton_setSkinByName(avatar.spineContext->skeleton, "test-avatar");
spSkeleton_setSlotsToSetupPose(avatar.spineContext->skeleton);
DZSpineSceneDescription *sceneDesc = [DZSpineSceneDescription description];
... define animations etc. here...
NSArray *nodes = [sceneDesc buildScene];
SKNode *placeHolder = [SKNode node];
placeHolder.position = CGPointMake(100, size.height);
placeHolder.name = #"root";
... more setup code...
SKScene *scene = [[SKScene alloc] initWithSize:size];
scene.scaleMode = SKSceneScaleModeAspectFill;
scene.backgroundColor = [UIColor whiteColor];
[scene addChild:placeHolder];
return scene;
}
The property I want to access is sceneDesc - I need to modify its contents on the fly, when the UISwitch is pressed. I know that it's possible from within the scene setup code, but I'm having trouble figuring out how to do so once the scene's on screen.
Changing values of this property will alter the SKTexture used in various nodes.
It probably doesn't help that I'm still new to Objective-C, and the setup of the project is rather different to how I've been working so far (splitting up scenes into their own classes, with properties that can be easily accessed programatically).
You can use NSNotificationCenter to send a message to the scene when the switch is pressed.
I actually gave up on trying to access sceneDesc programatically, and just changed the textures of the relevant SKSpriteNodes:
SKSpriteNode *root = (SKSpriteNode *)[placeHolder.children[0] childNodeWithName:#"root"];
SKSpriteNode *arm = (SKSpriteNode *)[root childNodeWithName:#"upper arm"];
SKSpriteNode *upperArm = (SKSpriteNode *)[arm childNodeWithName:#"upper arm"];
SKSpriteNode *lowerArm = (SKSpriteNode *)[[arm childNodeWithName:#"bone3"] childNodeWithName:#"lower arm"];
upperArm.texture = [SKTexture textureWithImageNamed:#"blue_sleeve_upper"];
lowerArm.texture = [SKTexture textureWithImageNamed:#"blue_sleeve_lower"];

Resources