how to fix occasional stutter in my game? - ios

The context:
In my SKScene I have:
1) a few sprites with no physics controlled by touch using touchesMoved: which instantly changes sprite position property based on touch location,
2) one sprite that while colliding with the others changes its physicsBody.velocity instantly.
That's all - no other fancy processing.
The issue:
I found occasional and random stuttering all of the sprites independently without any FPS dropping.
The questions:
In the context of my performance issue:
1) Is there any reason to update sprite position or velocity in update: method rather than update them instantly?
2) Is there any sense to use SKAction rather than changing directly position or velocity property?
3) If 2 then can make any difference running SKActions instantly or run them in update: method?
Apple says about
update:
method:
This is the primary place to implement your own in-game simulation, including input handling, artificial intelligence, game scripting, and other similar game logic. Often, you use this method to make changes to nodes or to run actions on nodes.
but nothing more like "must,..." or "should, because...".
4) Isn't SpriteKit done like all the changes made to the nodes instantly are processed in respective loop update phase or do I have always go to the appropriate loop method to make/fire changes there to avoid any rendering performance loss or interference?

Related

Removing SKNodes When Not Visible On Screen

In my game, the size of the level can be larger than the screen of the phone and the camera will follow the player around the level, so there can be a decent amount of content(such as SKEmitterNodes) in the scene that is not visible at any given time. I've been reading through some of the SpriteKit documentation and found this quote in the SMEmitterNode section:
"Consider removing a particle emitter from the scene when it is not
visible onscreen. Add it just before it becomes visible."
Is this something that can be done in my type of game design? I don't want the nodes to be completely removed since they will eventually be put on the screen, but is there a good way for me to add/remove the EmitterNodes (or other SpriteNodes) that are a certain distance from the screen/is this a good idea to do? I'm looking to improve my frame-rate and don't want costly nodes like SMEmitterNodes working while they're not even being displayed, but will adding/removing them as the player moves around reduce the performance?
Here is the idea I currently have: create a rectangle that extends a certain distance around the screen and detect when a node comes into that rectangle, and if it's not already added to the scene, go ahead and add it. Thank you for any suggestions.
SKNodes really aren't a problem because when they are off screen they are not being rendered anyway, just evaluated. So the main thing to worry about with SKNodes are any physics bodies attached to them,
SKEmitterNodes however require some processing power, and that is why apple is recommending not having them emit if they are not on screen. I would just subclass my SKScene class, and do a checks only on SKEmitterNodes whether or not they are in frame, and emit based on that.
So, I would throw all your SKEmitterNodes into a container like an array, and have a loop function to have the node do a CGRectIntersectsRect check based on your camera location and viewable screen size. and if they intersect, add it to the scene, if not remove it from the scene. The array will keep a strong reference so you do not have to worry about it deiniting on you

Draw circle and drag touch around SKSpriteNode

I am making a Sprite Kit game where the player (basically a stickman) has a running animation and a parallax scrolling background.
Now I have enemies that come near my player. To destroy these enemies sometimes I have to touch the enemies node to launch a rocket or attack them with an attack button or just jump over them.
Everything is working fine, but I want to add some extra moves to destroy them. I want some enemies that you can just destroy if you have drawn a whole circle around them. So imagine they come and you make a circle and then my player launch a laser or something. The problem is I have no idea where to start.
I haven't found anything on the internet. If it's too complicated or almost impossible how about touching my player node and dragging to the enemy?
EDIT: I think I have to create a custom GestureRecognizer that recognizes if a circle is drawn around a sprite and then runs the code. I don't know how this works ?
Yes, it's too complex. Not just from a coding point of view, but also from that of the player's experience.
Anything that requires complex gestures over a large amount of glass is annoying for the player because they're never going to have the same experience. Their finger's moisture and oil content always changes, as does the ambient temperature and cleanliness of their screen.
So big gestures required to be performed quickly (a gaming input like this) will sometimes be fun and smooth, and other times degrade as an experience based on the nature of the above properties.
Best to avoid them for a game's best possible experience.
If you must do it, there's two ways to research how.
Seek out "custom gesture" creation and utilisation through documentation and google, etc.
Think about using some kind of array to store all the points where the player's finger moves through during that circle gesture and attempt to discern if an enemy is within that space and then act accordingly.
--- probably other ways, too. But these jump to mind.

SceneKit - Adding a new SCNNode to the scene causes severe lag

I found out that adding SCNNodes (with SCNGeometry) to the scene causes a severe lag spike.
According to the Time Profiler it has to generate the geometry (at least the functions/methods are called like that). It does that at the time when the node is added to the scene, not when the node is created. Hence, creating a pool with SCNNodes will not work.
Is there a way to get rid of this lag? I'd like to be able to add nodes to the scene without any FPS drop.
The only idea I have so far is adding everything to the scene already and then hiding / un-hiding it, though this is not really a clean solution.
Here's a shot from Time Profiler:
looks like your are adding a node with an SCNShape or SCNText attached to it and these kinds of geometries are expensive to create (you have to discretize and triangulate the Bézier curve, and eventually have to compute and offset curve for the chamfer).
You can try to preload the following methods from SCNSceneRenderer : -prepareObject:shouldAbortBlock:, -prepareObjects:withCompletionHandler:

How would I build pool-cues / simplified pinball-style plungers with SpriteKit?

I'm working on a game in which the user should be able to trigger 'rods' that come out from the edge of the screen to displace elements on screen (balls). These projectiles roughly resemble pool-cues. Or perhaps pinball plungers, except that they start from the 'loaded' position (mostly offscreen), and when triggered, they eject out, then quickly retreat.
I'm unclear how I should build these with Sprite Kit.
The game uses the PhysicsEngine, and the onscreen balls should be effected both by gravity AND they should be displaced when they collide with the rods. However the rods should neither be effected by gravity, not displaced when they collide with the balls -- they should simply retreat regardless of whether they've made contact with the balls.
I realize I can set the affectedByGravity property for the rods. However because they will still displace slightly when they collide with the balls. How can I 'fix' or 'peg' them in place? Do I need to use an SKPhysicsSlidingJoint? If so, has anyone encountered any examples online? Is there a simpler way to do this?
A related physics engine, Box2D distinguishes static, kinematic, and dynamic bodies.
Kinematic bodies can move and will collide with other objects, but they are themselves not affected by dynamic bodies or forces like gravity. Thus, consider setting rod.dynamic = NO; but animate it with actions. See also here in the reference for SKPhysicsBody.

Box2D / cocos2d animation to a point with rotation

I'm pretty new to Box2D and cocos2d. I'm trying to do something which I thought would be pretty simple, but it is turning out to be more difficult than I had expected and I cannot find a working answer anywhere.
Basically, I want to move a b2body and rotate it to a certain point with animation.
I can get it to the correct position and rotation with:
targetBody->SetTransform(b2Vec2(10.0f,1.0f),10);
But I have no idea how to animate it there over time. I tried using cocos2d animation on the sprite used for the body, but that doesn't do anything. Any ideas?
There are a couple of ways you could do this.
You could use SetTransform every time step to update the position of the body gradually over time, in effect performing the animation yourself. The drawback with this method is that the body is 'teleporting' to the new position rather than moving, so it has no momentum, which means you can get odd results if it hits anything along the way. Still, if you know it will not hit anything or does not need to react to a collision this would be ok.
The other way is to SetLinearVelocity and SetAngularVelocity to give the body proper movement. This will keep the results of a collision realistic, and you don't need to keep updating anything every timestep. On the other hand, you will need to detect when the body has arrived at the desired position and then set the velocities back to zero, otherwise it will just keep moving. For dynamic bodies you will also need to counter gravity somehow, either by setting the gravity scale of the body to zero, or by applying an upwards force to balance gravity, or by changing the body type to kinematic during the move.
In general, you use Box2D to simulate the physical behavior of objects in relation to each other. The rules of mechanics implemented by Box2D dictate how your cocos2d CCSprites move if you continuously update the translation and rotation of your sprites according to their corresponding Box2d b2Body. You will have some kind of repeatedly invoked tick: method in which you step your Box2d world along in time, and in which you update your sprite positions according to simulation results of Box2d.
This pattern corresponds to b2Bodys of type b2_dynamicBody. Physical laws dictate the motion of the body in this case, and your sprites will follow these simulation results. This is why setting a conflicting position of a sprite by means of a CCAction or even directly will be undone almost instantaneously with the next tick:.
Solution 1: kinematic body type
However, there do exist other modes for a b2Body, and one of these is b2_kinematicBody in which the translation is no longer governed by the world but by the velocities or angular speeds you dictate through setters. So it would be one solution to work with body type b2_kinematicBody as in:
b2BodyDef bdef;
bdef.type = b2_kinematicBody;
With this you would manipulate the velocity and angular speed of a b2Body explicitly. In this case, Box2d is still responsible for moving bodies around, but according the velocities you dictate, and without any force effects of collision or gravity applied to this particular body. Also with this strategy, your CCSprites will follow b2Bodys. Setting conflicting positions for your sprites directly or by applying a CCAction would not make sense for the same reason as described above.
Solution 2: decouple sprites from Box2d
An alternative way to animating sprites would be to fully decouple those sprites from Box2d. In this case, you would simply not have any b2Body that governs the position of the sprite you are going to animate. Now, in this case, only you will dictate the position and rotation of your CCSprite, i.e. directly either through its position property or by applying a CCAction.

Resources