Duplicating a particle emitter effect in Sprite Kit - swift

I need to have a particle emitters effects to appear duplicated in 2 spots (For split screen purposes), I am wondering if anybody has come across a way of doing this. My goal is to have this running on iOS 10. Here is what I have tried so far.
Assigning targetNode to an SKNode and then copying SKNode every frame: targetNode does not work in iOS 10 for me.
Assigning the particle emitter to an SKNode, and using view.textureFromNode to make a texture to copy every frame : takes 1/120th of a frame, too slow for me.
Assigning a custom action to a particle node that duplicates the node into another SKNode : Actions will not run on iOS 10
Copying the existing particle node in hopes that the seed is not random : The seed is random
Tried copying the particle emitter on update : Particle just spawns at origin
Tried SKReferenceNode : Just a copy of the emitter, runs on its own
The only option I am left for true emitting is writing my own particle emitter, which I am trying to avoid, so I am wondering if anybody else had this problem and knew of a solution to achieve desired effect.
The other thing I could do is prerendering the emitters, but this will take up a lot of texture memory if I go this route.
Edit: To help visualize, I drew a picture, The white border shows where the Split Screen happens. The black border shows where the scene wrapping happens.
As of right now, both Player 1 and Player 2 are on the original scene.
Player 2 is walking right and is about to hit a world wrap to move him to the left hand side of the world, but he has not hit it yet. So I need to have a copy of the scene happening so that it visually looks like one scene. Since player 1 is still on the original scene, the original emitter needs to stay in place. Player 2 is going to have to see the same image happening in the copy, otherwise once he passes that border, a "glitchy" effect will happen, and the illusion of wrapping is now gone.
Final Result:
We just said F%%% it, Player 1 and Player 2 will be looking at different emitter nodes, we will just attach the emitters to each players camera when needed.

This just works (I guess as intended), but I have no idea how much is performant or how it fits your needs and your current game. Anyways, maybe it can help you in some way. First, in your GameViewController...Split screen :)
#import "GameViewController.h"
#import "GameScene.h"
#implementation GameViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * leftSKView = (SKView *)self.leftScene;
leftSKView.ignoresSiblingOrder = YES;
leftSKView.showsFPS = YES;
leftSKView.showsNodeCount = YES;
SKView * rightSKView = (SKView *)self.rightScene;
rightSKView.ignoresSiblingOrder = YES;
rightSKView.showsFPS = YES;
rightSKView.showsNodeCount = YES;
// Create and configure the scene.
GameScene *scene = [GameScene nodeWithFileNamed:#"GameScene"];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[leftSKView presentScene:scene];
[rightSKView presentScene:scene];
}
leftScene and rightScene are UIViews defined in a storyboard using autolayout to take half of a screen each. Also a class is changed to SKView (it was UIView). Pretty trivial...
Then in your game scene just add an emitter which will be shared between these two views. Because only one emitter is used, particles emitting (how they move) will be mirrored. So in game scene, just add a particle:
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"MyParticle" ofType:#"sks"]];
emitter.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidX(self.frame));
emitter.name = #"explosion";
emitter.targetNode = self;
[self addChild:emitter];
}
I know that you don't need all this code, but if this is what you want in some way, I will post it for completeness. And here is the result:

Related

How to add a view to SceneKit?

I am very new to Swift and currently coding a minigolf game.
However, the player can hit the ball n times.
How do I make a simple view which should show how many hits the player has left?
I think that you want something like this:
First of all, i recommend you to create a function to call when the game is restarted, there you can reset the scene, reset the player moves, etc...
You may do this like:
func restart(){
//Everything you need to restart the game
}
To call it later you just have to:
restart()
Ok, let's go to what you asked now:
declare a Int variable that contains the number of moves that the player has:
var playerMoves = 10 //Whatever number you want
Ok, you have a variable that contains the number of moves, now you have to show this on your scene, to do this, create an SKLabelNode:
let moveLabel = SKLabelNode()
Now, set the label text to be equal your playerMoves, set the position, the zPosition, the font, whatever you want:
moveLabel.text = "\(playerMoves)" //add this line to restart function that i mentioned and also set the variable playerMoves to "n" again.
moveLabel.position = ....
moveLabel.fontSize = ....
moveLabel.zPosition = ... //A number higher than any other zPosition
addChild(moveLabel) //Don't forget to add the label to scene!
Thats it! And now you have to update the playerMoves every time the player moves, to do this i'm assuming you are controlling somehow when the player moves (using update function, touches began, created a function, etc....)
so...when the player take one move:
playerMoves -= 1
moveLabel.text = "\(playerMoves)"
THATS IT!!! :) HOPE IT HELPS!
there are several ways to go about it. the most common way would be to overlay a spritekit scene over the scenekit scene. in the spritekit scene you can have a label element that you update
the code might look something like
let overlay = SKScene(fileNamed: "yourspritekitscene.sks")
yourScnView.overlaySKScene = menuOverlay
you can also assign a spritekit scene as a texture on a 3D object in your scene. or you can can make the numbers a texture you swap as you count down.

Q: How do I move objects down the y axis as my player moves up?

Creating a game like Doodle Jump where my player is constantly being moved up by bouncing off of obstacles. Ive tried every trick in the book but nothing seems to be working/doing exactly what I want. Can anyone give me some tips?
iOS 9 introduced the Camera Node. Use SKCameraNode, which is a subclass of SKNode, and can be translated and rotated in same way.
So, instead of moving all of your background elements in the opposite direction of your hero/player, you can simply attach your scene's camera node to your hero/player and the rest is taken care of.
PS. You can also do cool stuff like scaling the camera size.
EDIT.
Happy to include an example.
First, make a camera constant in your scene.
import SpriteKit
class myFirstScene: SKScene {
let myCamera: SKCameraNode = SKCameraNode()
...
}
Then in your didMoveToView() function, assign the scene's built-in camera variable to the camera constant we made earlier.
override func didMoveToView( view: SKView ) {
camera = myCamera
...
}
Now, there are a few different ways to "attach" your camera to your hero/player. The first is to attach your camera node to your hero.
hero.addChild( myCamera )
I don't even know if it works that easily because my game uses something different, a simpler version is below.
update(){
camera!.zRotation = hero.zRotation
camera!.position = hero.position
}

SKScene scale + anchorPoint = strange behavior

I have an empty SKScene which needs to be horizontally centered, so I set it's anchorPoint:
self.anchorPoint = CGPoint(0.5f, 0);
I also need to scale it, per SpriteKit - Set Scale and Physics, so I run an action on it like this:
[self runAction:[SKAction scaleTo:0.5f duration:0.0f]];
My problem is that when I detect touches, I get locations that seem strangely off.
I detect touches using the usual (locationInNode:self) method, and I'm currently adding a little blue square where the touches are, but when I touch the 4 corners of my device, I see a frame that is a quarter of my screen (correctly) but is moved to the left by a seemingly arbitrary amount
Here are some things I've already checked:
scene is initialized in viewWillLayoutSubviews, I know it has the correct initial dimensions
scene's scaleMode is set to SKSceneScaleModeAspectFill, but I've tried all of them to no avail
I was struggling with the same issue for awhile, but I think I finally got it figured out. You're not supposed to scale the scene (like it hints if you try setScale). You're supposed to resize it.
Try this:
myScene.scaleMode = SKSceneScaleModeAspectFill;
And then while zooming:
myScene.size = CGSizeMake(newX, newY);
Set Anchor Point as
self.anchorPoint = CGPoint(0.5f, 0);
And set Scene Scale Mode as ASPECT FIT, not aspect fill.
SKSceneScaleModeAspectFit

iPhone game development with Cocos2d: how to generate a cool light effect when an entity gets hit?

Abused topic considering the posts (e.g this or this) but I still don't quiet manage to get what I want.
I am working on a shooter game and I would like to light up my enemies when they get hit (as well as the player).
If I run the following my sprite doesn't get white. Is this the right direction?
-(void) gothitAnimation
{
ccColor3B originalColor = self.color;
id delay = [CCDelayTime actionWithDuration:0.4f];
[self runAction:[CCSequence actions: [CCTintTo actionWithDuration:0.01f red:255 green:240 blue:240], delay, [CCTintTo actionWithDuration:0.01f red:originalColor.r green:originalColor.g blue:originalColor.b] , nil]];
}
I have tried running only the CCTintTo action and it does work only with colours different than white.
I have found Arodius's game demo and it seem to me that there the player ship gets set multiple times to invisible and visible in a short sequence of actions when hit or in lower energy levels (see this demo). Also the enemy get a light effect when hit.
Any idea on how this has been achieved? Did the developer use the CCTintTo action or something else? I know that for the explosion he used ParticleEffects.
The default tint color for sprites is white. So you can't tint to white or make the sprite appear brighter with tinting.
Blinking can be achieved by setting the visible property on and off at an interval. One way to do that is to use the CCBlink action.
Your best bet is to use a particle effect. You can only achieve a true lighting effect if you're using cocos2d 2.0 and write a fragment shader for this particular effect.
I recently needed to do the same, and didn't want to deal with pixel shaders. I figured I could mess with how the texture is blended into the scene to get some sort of white flash out of it.
So, I figured out a reasonable light-flash effect by repeatedly changing the sprite's Destination glBlend function from GL_ONE_MINUS_SRC_ALPHA to GL_ONE, and then back.
Here's my toggle method:
-(void)toggleBlendFlash {
if (sprite_) {
ccBlendFunc blendFunc = sprite_.blendFunc;
if (blendFunc.dst == GL_ONE_MINUS_SRC_ALPHA) {
blendFunc.dst = GL_ONE; //flash white
} else {
blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; //default
}
sprite_.blendFunc = blendFunc;
}
}
Here's my flashing sequence:
CCSequence *sequence =
[CCSequence actions:
[CCCallFunc actionWithTarget:targetEnemy selector:#selector(toggleBlendFlash)],
[CCDelayTime actionWithDuration:0.3],
[CCCallFunc actionWithTarget:targetEnemy selector:#selector(toggleBlendFlash)],
[CCDelayTime actionWithDuration:0.2], nil ];
It may not look perfect for your situation, but give it a try!
EDIT 1: Also, check these links out for more info/resources:
http://digitallybold.com/314/cocos2d-additive-sprite-color-tinting
http://www.andersriggelsen.dk/glblendfunc.php
EDIT 2:
Of course, I just realized that if your sprite is animating between different CCTexture2D objects (e.g. you have 1 file per frame), then it resets your blendFunc for every frame, which means you have to either create a category or a subclass for CCSprite or CCAnimate to re-apply your custom blendFunc... so I guess its not as quick of a solution as I had originally thought.

Most efficient way to create CCSprites and particles in Cocos2D

Right now, in my game, I am spawning a sprite every second or so at the top of the screen (using a sceduler) using this code:
The init method:
[self schedule:#selector(addMeteor:) interval:1];
The scheduler method:
- (void)addMeteor:(ccTime)dt
{
CCTexture2D *meteor = [[CCTextureCache sharedTextureCache] addImage:#"Frame3.png"];
target = [CCSprite spriteWithTexture:meteor rect:CGRectMake(0, 0, 53, 56)];
//Rest of positioning code was here
}
Doing it this way causes a stutter in the frame rate every second or so (Whenever another sprite is spawned). Is there a way to eliminate that?
Thanks in advance!
Tate
I'm guessing the stutter is more likely coming from other parts of the code. Do you explicitly call removeChild on meteors? That might cause a hiccup, especially with many meteors.
My advice: create N meteor sprites up front. When you need one, make it visible and change its position. When you're done with it, set it to visible = NO to make it disappear.