Scaling (zooming) CameraNode lags overtime - ios

Im using Swift 3.0 and I'm attempting to use the SKCameraNode class as a camera for my game.
I move it around, rotate, and zoom in and out a lot. For some reason, it goes in and out of having these rough patches (about 30 seconds) where it's super etchy, as if it were only being updated a tenth of the usual time. Note that NOTHING else in the game is lagging except camera movement.
However this is only extremely noticeable when I'm trying to zoom in and out.
The occurrence usually happens after a burst of moving it around a lot, but not always. Sometimes it happens the second the app is started, and other times never.
Here is my code, which is running in didFinishUpdate:
camera.run(SkAction.scale(to: size, duration time))
time is usually 0.0, but sometimes not, so I would like to try to keep this as an SKAction if possible. However, I assume the problem resides in using this SKAction. (I'm like 99% sure the problem isn't that I'm accidentally not passing 0.0 for time)
So what should I do to either fix or work my way around this problem? Is this just a limitation of a Swift?
EDIT: I have now also tried using it in other update functions. I also tested to see the run time of didFinishUpdate (To see if it was lag), but it remained consistent. Also, this happens when i try to rotate the camera as well.
ANOTHER EDIT: I've also tried setting gamePhysics speed to 0.9999 which was suggested in another post with a lag problem
Thanks!

Related

SceneKit scenes lag when resuming app

In my app, I have several simple scenes (a single 80 segment sphere with a 500px by 1000px texture, rotating once a minute) displaying at once. When I open the app, everything goes smoothly. I get constant 120fps with less than 50mb of memory usage and around 30% cpu usage.
However, if I minimize the app and come back to it a minute later, or just stop interacting with the app for a while, the scenes all lag terribly and get around 4 fps, despite Xcode reporting 30fps, normal memory usage, and super low (~3%) cpu usage.
I get this behavior when testing on a real iPhone 7 iOS 10.3.1, and I'm not sure if this behavior exists on other devices or the emulator.
Here is a sample project I pulled together to demonstrate this issue. (link here) Am I doing something wrong here? How can I make the scenes wake up and resume using as much cpu as they need to maintain good fps?
I won't probably answer the question you've asked directly, but can give you some points to think about.
I launched you demo app on my iPod 6-th gen (64-bit), iOS 10.3.1 and it lags from the very beginning up to about a minute with FPS 2-3. Then after some time it starts to spin smoothly. The same after going background-foreground. It can be explained with some caching of textures.
I resized one of the SCNView's so that it fits the screen, other views stayed behind. Set v4.showsStatistics = true
And here what I got
as you can see Metal flush takes about 18.3 ms for one frame and its only for one SCNView.
According to this answer on Stackoverflow
So, if my interpretation is correct, that would mean that "Metal
flush" measures the time the CPU spends waiting on video memory to
free up so it can push more data and request operations to the GPU.
So we might suspect that problem is in 4 different SCNViews working with GPU simultaneously.
Let's check it. Comparing to the 2-nd point, I've deleted 3 SCNViews behind and put 3 planets from those views to the front one. So that one SCNView has 4 planets at once. And here is the screenshot
and as you can see Metal flush takes up to 5 ms and its from the beginning and everything goes smoothly. Also you may notice that amount of triangles (top right icon) is four times as many as what we can see on the first screenshot.
To sum up, just try to combine all SCNNodes on one SCNView and possibly you'll get a speed up.
So, I finally figured out a partially functional solution, even though its not what I thought it would be.
The first thing I tried was to keep all the nodes in a single global scene as suggested by Sander's answer and set the delegate on one of the SCNViews as suggested in the second answer to this question. Maybe this used to work or it worked in a different context, but it didn't work for me.
How Sander ended up helping me was the use of the performance statistics, which I didn't know existed. I enabled them for one of my scenes, and something stood out to me about performance:
In the first few seconds of running, before the app gets dramatic frame drops, the performance display read 240fps. "Why was this?", I thought. Who would need 240 fps on a mobile phone with a 60hz display, especially when the SceneKit default is 60. Then it hit me: 60 * 4 = 240.
What I guess was happening is that each update in a single scene triggered a "metal flush", meaning that each scene was being flushed 240 times per second. I would guess that this fills the gpu buffer (or memory? I have no idea) slowly, and eventually SceneKit needs to start clearing it out, and 240 fps across 4 views is simply too much for it to keep up with. (which explains why it initially gets good performance before dropping completely.).
My solution (and this is why I said "partial solution"), was to set the preferedFramesPerSecond for each SceneView to 15, for a total of 60 (I can also get away with 30 on my phone, but I'm not sure if this holds up on weaker devices). Unfortunately 15fps is noticeably choppy, but way better than the terrible performance I was getting originally.
Maybe in the future Apple will enable unique refreshes per SceneView.
TL;DR: set preferredFramesPerSecond to sum to 60 over all of your SceneViews.

Cocos2dx 2.1.4 Game, Continuos FPS drop and never recovers

I am creating a game using cocos2dx 2.1.4. Its FPS drops continuously , and never recover.
Please find the details as follows
Background about the way I am doing things:-
Its game about scrolling down some shapes, each shape is made up of some square blocks.I have 7 kind of blocks. All loaded in a Sprite Sheet and using these blocks from this sprite sheet I create a shape.
A level file is consist of these shapes. I load two levels at the same time one onscreen and another off screen to make it seamless scrolling. For loading two levels at the same time I used two different CCSprite game batch nodes as :-
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("56blackglow.plist");
_gameBatchNode1 = CCSpriteBatchNode::create("56blackglow.png", 200);
_gameBatchNode1->retain();
this->addChild(_gameBatchNode1,kForeground);
_gameBatchNode2= CCSpriteBatchNode::create("56blackglow.png", 200);
_gameBatchNode2->retain();
this->addChild(_gameBatchNode2,kForeground);
The problem I am facing is that as I keep on playing the game frame rate drops continuously , from 60 fps till 10 fps and never recovers or might recover in near future , as I observed for 20 minutes but its too much time to wait.
My observations:-
1> I used Time profiler it shows maximum time is in draw() calls. Also if I play game very fast the peak of time increases in track, that should be fine as I am giving more work to do, but once a peak is attained it remains approximately at that height only, even if I leave the game Idle. Is it normal ? According to me it should have returned to its normal peak once the current work is done.
2> Some where I thought its happening because I used two batch nodes and removing its children on a user touch immediately might causing it slow but then after removing the children it should run normal. to give an idea is it ok to remove 10 children from batch node immediately ? some guys say its very slow process. Just to check if this causing problem , I did :-
Instead of removing them I just set visibility of the children to false.But still FPS drops and never recovers.
Please share your thoughts on this.
Though SpriteBatchNodes are generally quite good for drawing a lot of elements efficiently, I think there are best used for static/not-so-dynamic elements. In your case, if you have a lot of elements which go out of the screen but are still alive the draw() function will have to make some checks, thus hogging your performance (even if you set isVisible(false); explicitly, it still nedds to be checked).
In your case I think it would be better if you simply added new shapes outside of screen via some time-based function, and if they scroll outside of view simply remove them from scene, without using batchNodes.
Just found that with every touch, I am adding 8 new sprites to the layer, and its adding every time I touch . So with time I am giving more and more work to do. This is the problem
Actually I wanted to replace the sprite at 8 places with a touch, the way I was doing every time :-
_colorBottom1=CCSprite::createWithSpriteFrameName(png[0]);
this->addChild(_colorBottom1,kForeground);
_colorBottom1->setPosition(ccp((_colorPanelLeftPad)*_blockWidth,_blockWidth));
It was causing this sprite to be added with every touch.
but it should have been (Replace the texture instead of creating the Sprite again):-
CCSpriteFrame *frame1=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(png0);
_colorBottom1->setDisplayFrame(frame1);

How to remove stutter in a cocos2d running game?

I am building a cocos2d continuous running ios game, where a character is animated to run through a scene. The background, the grounds under the character's feet and a fence behind the running character move in the opposite direction to simulate forward motion. The character itself is animated to run in place. Occasionally additional sprites move by in the scene.
All my movement (except the in place animation of the character) happens in the update method.
I notice that all the moving parts stutter when additional sprites are moving past the scene. When there are no additional sprites, the stutter goes away.
I also notice that the stutter is almost imperceptible in the ipad 3 (ios 6.0.1), whereas it is most noticeable in the iphone 3gs (ios 6.0.1) and ipad 1 (ios 5.1.1), and moderately noticeable on the iphone 4 (ios 6.0.1).
I have no idea where to begin to address this - I tried removing the actual rendering of the additional sprites, and I also tried removing the fence behind the character - but neither change had any impact on the stutter.
Any suggestions?
Update: fixed it by running time profiler as #Fogmeister suggested below. Turns out I was doing disk i/o on every update to look up some state variables. I optimized that away and the stutter is gone on all devices. Thanks!
You need to identify what is taking up the time in the code and causing the stutter.
It seems like it is just an optimisation issue as you can see more stutter on older, slower devices and less on new more powerful devices.
Analyse the app using the Time Profiler instrument. This will tell you where the time is being spent and point you almost instantly to the function (if not the line) that is taking the time.
Once you've found that you can start optimising.
What is your code for the movement of the sprites? If you are updating the positions manually in the -(void) update:(ccTime) delta {} method make sure you are multiplying each movement by delta to account for any minute framerate fluctuations.

Touch responsiveness on iPod

I wrote a simple code that makes an object follow moursor or touch input and works so fast and responsive on editor but when I deploy it on my iPod, it has a slight delay. If you move your finger fast enough, you can see that the object takes time to reach to your finger, it's slight but noticable.
There is no problem in the path that object has to follow in order to get dragged around the scene, problem is it's always like 10 pixels late to the finger's current position. It's like input is checked on less intervals than update.
So is there anyway to make it more responsive? Like with what we can do with physic that we can force it to call more Fixed Update or anything similar.
I want it to follow my finger on the screen fast, without any delay.
I tried these so far with no fruit:
1) Changing FPS ro 60.
2) Changing various settings in AppController.mm
Thanks.

windows phone 7, xna, how do I sample the touch screen more regularly

ok, so apparently xna games can only run at 30fps, which is a shame, because our game on iphone looked alot better at 60...
at any rate, because the only way you can get information about the touch screen state is to get its current state, effectively this means you can only sample the touch screen at 30 fps.
even if our game has to run at 30fps, is there any way to get higher resolution sampling from the touch screen? maybe through callbacks? or by accessing a list of touch events with time stamps?
The function you are looking for is TouchPanel.GetState. It is a simple matter of calling this function at 60Hz.
To get 60Hz you could set Game.TargetElapsedTime to 1/60th of a second. This will give you two updates to every one draw (according to Shawn Hargreaves' post here) assuming you are VSyncing at 30FPS.
If you still want your game state updates to run at 30FPS (just doing touch input at 60FPS), then you could put those updates on a different thread. Start an update going on that thread on the first call to Game.Update, and wait for it to finish on the second one, and so on.
(You should note that normally XNA input must be done on the main thread (source). I assume this applies to Phone and to touch input.)
Alternately you could replace the Game class's timing yourself entirely (calling GraphicsDevice.Present yourself). It's not easy to do, but it's possible. A good place to start is to look at the Game class in Reflector.
(Disclaimer: I haven't tried any actual Phone-based development yet, so there may be some Phone-related gotchas I am unaware of.)
The sampling rate of 30fps is set for performance reasons.
Even if you could find a way to query for touches more frequently you still couldn't update the UI at a faster rate so I'm not sure what benefit you'd get.
Before spending too much time on trying to find a solution I'd test on an actual device to see how acceptable 30fps really is.

Resources