23

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.

  1. Assigning targetNode to an SKNode and then copying SKNode every frame: targetNode does not work in iOS 10 for me.
  2. 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.
  3. Assigning a custom action to a particle node that duplicates the node into another SKNode : Actions will not run on iOS 10
  4. Copying the existing particle node in hopes that the seed is not random : The seed is random
  5. Tried copying the particle emitter on update : Particle just spawns at origin
  6. 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. enter image description here

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.

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Two days until the bounty ends and still no new answers. That is unexpected I must say. Anyway if I win half of a bounty due to automatic awarding rule, I will raise another bounty (of 250 points, because that is what I could get theoretically). Still it would be nice that some people (which I respect a lot and have many times learnt from them) like @EpicByte or 0x141e comment on this a bit. – Whirlwind Nov 10 '16 at 17:21
  • @Whirlwind, I know, I would put more than 500 bounty if I could. Right now I am looking into using `SKVideoNode`. I am testing the performance of using this vs keeping all of the particle node frames in memory. – Knight0fDragon Nov 10 '16 at 17:24
  • I have also submitted a request to seed the random, Why CAEmitterLayer allows for seeding but not SKEmitterNode is beyond me lol – Knight0fDragon Nov 10 '16 at 17:25
  • Video node is a clever idea. It is meant actually to be used when animation is expensive. But dont know if just works or it is buggy. I've seen few questions where people complaing about some issues with SKVideoNode. But if it works , then why not. – Whirlwind Nov 10 '16 at 17:28
  • Well the why not is because I do not want the same looking effect over and over lol, so I need to write a mechanism to cache and rebuild this video whenever there is background time available, to give the illusion of new emitters. I will let you know how well it performs – Knight0fDragon Nov 10 '16 at 17:31
  • @Knight0fDragon I don't mean to highjack your question, but I am also developing a 2 player game and didn't consider the 2 SKViews option...Brilliant. As far as the limiting the Update call to once, how did you do that? Just set a variable on one of the scenes and check that in the update? Or is there something more elegant? Any other pitfalls or "gotchas" you can share regarding this method? Regards – Ron Myschuk Nov 14 '16 at 16:32
  • 1
    @RonMyschuk the "current time" that gets passed in is consistent among the update between the different views. You need to capture this value and store it in a variable. Next call to update check this value, if stored current time = update current time, mark it false and return. Do this for all of the update calls. Do note, this will mess with SKPhysics in a lot of ways due it being called twice, I have not found an elegant way of getting around this – Knight0fDragon Nov 14 '16 at 16:46
  • @Knight0fDragon Ah, I just read that automatic bounty award works in that way, that answer must be added after the bounty has started (also it has to have a score of at least 2 ). My answer is given before the bounty has started. Sadly, I doubt another bounty would make a difference... Whats happening with a video node thingy ? – Whirlwind Nov 14 '16 at 22:14
  • @Whirlwind Still working on it, finally got the particle emitter to record, now i need to align the textures, resize, and make sure transparency works – Knight0fDragon Nov 14 '16 at 22:18
  • @Knight0fDragon Sounds like a lot of work to do :( – Whirlwind Nov 14 '16 at 22:20
  • @Whirlwind, if this doesn't work, I am just going to create the emitters on a per camera basis, and just not care if player 1 and player 2 see a different effect, so long as there is no glitchy effect – Knight0fDragon Nov 14 '16 at 22:22
  • @Whirlwind, SKVideoNode is a no go, Does not support transparency – Knight0fDragon Nov 17 '16 at 00:56

1 Answers1

7

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: enter image description here

Whirlwind
  • 14,286
  • 11
  • 68
  • 157
  • @Knight0fDragon Hope you don't mind Obj-C answer, I accidentally have chosen Obj-C for a language, so I was lazy to make a Swift based project lol. Also if this is not what you wanted, let me know and I will delete it. But, when I run this on a device, the emitters looks mirrored, cloned...(whatever the right term is :) ) and everything runs in 60fps. – Whirlwind Nov 04 '16 at 16:10
  • Thanks @Whirlwind, I am already using 2 views to create the split screen effect (it gets even crazier with cameras), The problem is there is no scene wrap ability, so you need to duplicate nodes to scene wrap. This issue comes down to when player 1 goes left, and player 2 goes right. Both hit the edge of the world, so the original world is on one side, and the copy world is on another side. (On opposite sides per view) I will need the 2 emitters for this circumstance – Knight0fDragon Nov 04 '16 at 16:14
  • I understand both obj c and swift, so we are good in that regard lol – Knight0fDragon Nov 04 '16 at 16:15
  • If this was single player, I would just swap the SKEmitterNode to keep the primary emitter on scene, but in a split screen world, I no longer have this luxury – Knight0fDragon Nov 04 '16 at 16:18
  • @Knight0fDragon Okay, I (think) I get it. I am on my way home right now, so can't really test anything, but if I come up with something later, will let you know. Anyways, interesting problem to solve. It would be nice if there was some built-in functionality for this ( personally I haven't heard about something like that so far). – Whirlwind Nov 04 '16 at 16:20
  • indeed it is. Thank you for the help. I am updating an app of mine for tvOS, and thanks to the wide screen, split screen effects works perfectly – Knight0fDragon Nov 04 '16 at 16:22
  • btw, for anyone who wants to do it this way, you need to write methods to guarantee update only gets fired once – Knight0fDragon Nov 04 '16 at 18:01
  • is building your own particle system an option? That way you don't have the problem of true random samples, and can absolutely recreate it with certainty they'll be the same. – Confused Nov 04 '16 at 22:26
  • @Confused of course it is an option, but why should I reinvent the wheel? `CAEmitterLayer` actually lets you pick your random seed, no idea why they left this out of `SKEmitterNode` (If there was an efficient way to use CAEmitterLayer in SpriteKit I would use it). – Knight0fDragon Nov 05 '16 at 12:26
  • Another idea... if you think in terms of textures (animated ones) on 3D surfaces (think about a plane in this example, since you're in a 2D space) would it be possible to make two instances of the same plane that point to the one particle system as the thing that's generating their animated texture? – Confused Nov 05 '16 at 15:20
  • This "rendering to a texture" is obviously going to need some kind of rendering, which means a camera or some other form of transfer of the particles. I'm spitballing. And coming up covered in flem. – Confused Nov 05 '16 at 15:22
  • But, consider this, it's possible to render a SceneKit scene into a view in SpriteKit, I think. Could this be a way to do it? My experiences with SceneKit's particle system have been mostly positive. It's no Unreal particles, but it's reasonably performant on even old hardware. – Confused Nov 05 '16 at 15:24
  • @Confused, I am not following you, but it doesn't matter, SceneKit would require a complete rewrite – Knight0fDragon Nov 06 '16 at 18:15