Rotate nodes in SpriteKit before the scene displays - ios

I'm creating a game where there is a split screen view for 2 players.
The game is for an iPad and the the split screen will work in such way that each player will see the nodes right-side-up.
The way that the app works is that the upper half of the game will have all nodes rotated upside-down.
The problem I have is that when the scene is being loaded, none of the actions are being executed before the scene is fully in view.
For an instance, I'm using the following command to rotate one of the labels:
[self.player1Score runAction:[SKAction rotateByAngle:UP_SIDE_DOWN duration:0]];
The problem is that the rotation won't take place until the scene animation is done - which will make it look very strange as the nodes will rotate immediately once the scene is fully in view (I could animate them, but I prefer they load up already rotated properly).
I tried running this from both initWithSize and didMoveToView but the results were the same.
My only option at the moment is for the Textures to be duplicated and rotated using Photoshop - but I'd rather to have the app "lighter" and not have unnecessary graphics if I can help it.
Any suggestions?
Thanks in advance!

Why don't u set SKNode's zRotation property to set the rotation as a the node is created, instead of rotating them using SKAction.
SKNode *node = [SKNode node];
node.zRotation = -M_PI/2.0;

Related

Revolving animation using cocos2d ios

I need a animation like revolving electrons on three orbiter path i the middle of nucleus. I am currently using cocos2d 3.2V for developing my game. I tried to make revolving animation using bezier path but this work for quadrant of circle not make a complete circle animation. How can i achieve this kind of animation using cocos 2d?
Thanks in advance
The center is your parent node, you add the orbiting nodes to the parent with their position at an offset like 40x0, then rotate the parent and the child will rotate around it.
If you need different rotation speeds simply add multiple parent nodes to the center, one for each "planet".
If you want to make the movement an ellipsis you can cheat to some extent. You can have the parent move slightly up and down (or between any other two opposing points) synchronized with the rotation.

Checking/removing SKScene sprite children easily/efficiently?

Working on an iOS game using SpriteKit. My background is made up of map tiles (essentially an infinite map, procedurally generated).
Our system is designed to manage "chunks" of the map, and we only load chunks near the player. Since SpriteKit requires we add SKSpriteNodes, we no longer have clean control over "unloading" sprites for chunks/tiles that are no longer near the player.
I realize SpriteKit won't actually render things off-screen, but it's going to kill performance if we can't remove sprites no longer needed, or check if a chunk/tile is already added.
Since SKNodes doesn't respond to isEqual:, I only see two ways to do this:
Give each sprite a name with their chunk/tile coordinate, and check this name each update
Maintain a separate array of loaded tiles and check that instead
Is there any easier way of checking/removing if a sprite has been added already? Maybe a partial string match on sprite name?
I'm not sure that using SpriteKit is the best solution (Xcode simulator seems to drag at 30fps, have yet to test on a real device). We originally built this game in Java and we're rendering our own textures - hence only what was loaded and could be fed into opengl manually.
-(void) renderToScene:(SKScene *)scene {
for( Chunk *chunk in loadedChunks ){
for( Tile *tile in [chunk getTiles] ){
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithTexture:tileTexture];
sprite.name = #"Tile";
sprite.position = CGPointMake(realX,realY);
[scene addChild:sprite];
}
}
}
What will in fact kill your framerate is frequently creating and removing nodes - you should have a pool of sprites that you re-use rather than recreate.
Just update the sprite's texture, position and other attributes when reusing one of those you no longer need. A common use case is to have enough tiles to span the entire screen plus one row and one column, so that when an entire row or column has moved outside the screen you can reposition it at the other side with new textures according to the map data.
If i'm understanding what you're asking correctly. You want to properly remove a node/sprite from the scene if its no longer within view.
You should just be able to call the [self removeFromParent] method to remove in whenever its outside the bounds of the screen. Remember you can call this method on any object as long as its a child.
For instance if i had character,
SKSpriteNode *character;
SKSpriteNode *sword;
//all the rest of the properties are up to you.
if my character picked up a sword in the game and after a certain time period the sword is no longer accessible. I would do:
[character addChild:sword];
which would add it to the character.
[sword removeFromParent];
when i no longer need the sword to be apart of its parent.

Emitter not rotating with parent node

Code --> http://pastebin.com/W3DMYjXa
I am tinkering with SpriteKit and I cannot seem to get an emitter node to rotate with my spaceship the way I would like.
I watched the Apple Tech Talks Session where they described making a spaceship and using an emitter for the thrust exhaust, but they lock the ship to only face one direction.
In my experiment I am trying to allow the player sprite (spaceship) to travel in any direction, I have rotation and scrolling working for the player, but the particle emitter doesn't seem to rotate with the player.
my hierarchy looks something like this
Scene
-->World Node
-->Player Node
---->Player Sprite
---->Emitter Node
My theory is that If I rotate (Player Node) it should rotate both of its children, and it does rotate them, but the emitter continues to emit in the same direction.
I can change the emission angle manually, but it seems needlessly complicated.
here is what I am using to rotate
-(void)rotatePlayerToDirection:(TTDirection)direction {
CGFloat radDir;
CGFloat emiDir;
scrollDirection = direction;
switch (direction) {
case TTUp:
radDir = 0;
emiDir = 3.142;
break;
case TTRight:
radDir = 4.712;
emiDir = 1.571;
break;
case TTDown:
radDir = 3.142;
emiDir = 0;
break;
case TTLeft:
radDir = 1.571;
emiDir = 4.712;
break;
default:
break;
}
SKAction *rotatePlayer = [SKAction rotateToAngle:radDir duration:0.1 shortestUnitArc:YES];
[playerNode runAction:rotatePlayer];
}
Am I missing something here?
Here is a video of this in action
http://youtu.be/NGZdlB9-X_o
I'm fairly certain there is a bug in spritekit to do with the targetNode and rotation. The other answer seems to suggest this is expected behavior, but that ignores that the docs explicitly give this situation as a motivation for the existence of targetNode.
Working with Other Node Types
What you really want is for the particles to be spawned, but thereafter be
independent of the emitter node. When the emitter node is
rotated, new particles get the new orientation, and old
particles maintain their old orientation.
It then gives an example using targetEmitter on how to achieve this. However, the example code does not work.
It seems that setting targetNode breaks particle rotation.
UPDATE: I found a workaround.
Spritekit is failing to adjust the SKEmitterNode.emissionAngle property when SKEmitterNode.targetNode is set. You can work around this by setting it manually after actions have been processed.
Assuming that your SKEmitterNode has only one parent, you can do something like this in your scene.
- (void)didEvaluateActions
{
// A spaceship with a thrust emitter as child node.
SKEmitterNode *thrust = (SKEmitterNode *)[self.spaceship childNodeWithName:#"thrust"];
thrust.emissionAngle = self.spaceship.zRotation + STARTING_ANGLE;
}
Note that if there are multiple ancestor nodes which may be rotated, you will need to loop through them and add all of their zRotations together.
I know this is an old question, and the OP has probably found a solution or workaround, but I thought I would add by two pence worth, in case it helps anybody else.
I am just starting out with SpriteKit and Swift, and am developing a game where nodes fly around and collide with each other, changing direction of travel frequently.
I add an emitter to each node, and initially found that as the node rotated and changed direction, the emission 'trail' remained fixed. I then read that the emitter should have its target node set not as the node it is a child of, but the scene they both exist in.
That at least made the particle trail twist and turn realistically rather than just spurt out in one direction.
But the nodes can spin and changes direction, and I wanted the particles to trail away from the node in the opposite direction to its travel - just like a smoke trail from a plane or rocket.
As the node may rotate, setting the emitters angle of emission to the z-rotation of the node does not work. So...
I track all onscreen nodes in a dictionary, removing them from the scene as they travel off the screen.
So in didSimulatePhysics I use the same dictionary to get the node and calculate the angle of travel from the velocity vector, and then set the emitters emission angle accordingly :
import Darwin
// in your scene class...
override func didSimulatePhysics() {
removeOffScreenParticles()
for (key,particle) in particles {
let v = particle.physicsBody!.velocity
particle.trail!.emissionAngle = atan2(v.dy, v.dx) - CGFloat(M_PI)
}
}
I am aware that this calculation and adjustment is being performed for each on screen node, in every frame, so will probably use my frame counter to only do this check every n'th frame if performance becomes an issue.
I hope this helps someone!
You are setting the emitter's targetNode property to the background. Note that this forces the emitter's particles to be rendered by the background node, and they will be treated as if the background was their parent. So, the particles aren't changing the angle, because the rotation of the background does not change.
Remove [emitter setTargetNode:backgroundNode] and the emitter's emission angle should be rotating correctly along with the player.
If you're looking for a 'middle ground', where the angle rotates along with the player, while the already-rendered particles aren't 'stuck' to the emitter, try this:
First, do not set the targetNode on the emitter (it defaults to nil).
Second, just as you are about to run the rotation action, temporarily set the targetNode to another node, and reset it back to nil when it completes (so that the particles can rotate along):
emitter.targetNode = backgroundNode;
[playerNode runAction:rotatePlayer completion:^{
emitter.targetNode = nil;
}];
Note that the results are also 'middle ground' - the emitter 'puffs' as the target node changes (the previous particles are removed, and new ones are rendered by the new target node). Hope that helps.
Other than that, there's no really straightforward way of achieving this - setting the emission angle manually might be the simplest way, after all. Here's one way to do it, right before running the rotation (the emitter target node is still nil, also, there's no need to hardcode emission angles):
float originalAngle = emitter.emissionAngle;
emitter.emissionAngle = emitter.emissionAngle - radDir;
[playerNode runAction:rotatePlayer completion:^{
emitter.emissionAngle = originalAngle;
}];

scale around certain point over time SpriteKit

I have a SpriteKit Scene in which I want to have the effect as if a camera zoom and scale. Does anyone know of any libraries or some easy methods of doing this?
It was very easy to do in other 2D engines but does not seem simple.
I was thinking of doing it from the app delegate, and using the window to zoom since my character does stay around the same position.
The desired effect I would like to accomplish is like that of the start of an Angry Bird level when the camera pans into the level and then the launch doc.
http://www.youtube.com/watch?v=_iQbZ3KNGWQ This is an example of the camera zoom and pans I am talking about.
Thanks for the help.
If you add an SKNode to the SKScene, and make your scene content children of that node instead of direct children of the scene, then you can zoom and pan all of the contained content just by adjusting the xScale, yScale and position properties of the added node. (Any content you did not want scrolled e.g. scores or whatever could then be added to a different SKNode or added directly to the scene).
The adjustment could be done by overriding one of update:, didEvaluateActions, or didSimulatePhysics in your SKScene subclass. The choice would depend on if you are just moving your character around by yourself in update:, or if it also gets moved around by running SKActions or by simulated physics.

How to apply full-screen SKEffectNode for post-processing in SpriteKit

I'm trying out SpriteKit with the following setup:
An SKScene with two child nodes used merely for grouping other
nodes: foreground and background.
background is really empty as of now, but would eventually hold some
type of background sprite / layers.
foreground is a SKEffectNode and whenever the user taps on the
screen, a new intance of a SKnode subclass which represents a game
element is added as child to it.
This SKNode subclass basically creates 3 SKShapeNodes and two labels: an outter
circumference, an inner circumference, 2 labels and an inner quarter circumference. The inner quarter circumference has an SKAction that
makes it rotate forever about its origin / center.
Now here's the issue, as long as foreground doesn't have any CIFilter or has shouldEnableEffects = NO, everything is fine. That is, I can tap on the screen and my game elements are instantiated and added to the main scene. But the minute I try adding a CIGaussianBlur or CIBloom to the foreground, I notice two things:
The framerate drops to about 2fps. Mind you, this happens even with
as little as 6 nodes alive in the scene.
The effect seems to be constantly cropping its contents or adjusting
it's frame. That is, if I have one node, the "full screen" effect
seems to try and constantly crop or adjust its bounds to the minimum
area required to hold all nodes. This is for one node:
And this is for 2 nodes:
In OpenGL ES 2, one would do a post blur / bloom by basically rendering the whole framebuffer (all objects) to texture, then doing at least one more pass to blur,etc on that texture and then either present that in the framebuffer attached to the display or compose that with the original render back to the framebuffer. I'd expect SKEffectNode to work in a similar way. However the cropping and the poor performance makes me think I might be using the effect node the wrong way. Any thoughts?
It seems to be a bug with the SKEffectNode trying to apply a filter on children SKShapeNodes as far as I can tell. I played around with this and achieved your results, but when I switched out the SKShapeNodes for SKSpriteNodes (using a simple png of a circle) the cropping no longer appears. It's a bug in that SKEffectNode doesn't handle the stroke of the SKShapeNode very well. If you take off the stroke (lineWidth = 0) and give it a fill color, you'll see that there is no cropping.
As for the frame rate, SKShapeNodes perform poorly. Doing the switch to SKSpriteNodes I mentioned earlier boosted my fps from 40 to 50 when I had 35 nodes on the screen (iPhone 5) with the filter applied.

Resources