- Home /
(Unfixable?) iOS frame drops/stutter issues
I have a REALLY basic game and I have done my best to optimise the hell out of it but I still get an odd pause that lasts around 0.2 of a second every so often. I have noticed that the longer I leave the game running, the less is occurs.
I have cached EVERYTHING in my game, I have tried running without collision, I have turned off all the sound, removed game objects, I have literally tested with and without every single item in the game and I can't get it to go ways.
The other issue is that the collision is very delayed. When my ray cast hits the object, there is a decent pause before it triggers the "game over" function.
This is a basic game with 5 obstacles that I recycle, a player ship that is made out of six separate parts that breaks up on game over, a cylinder, a few 3D text objects and a few quads rotating with stars.
All movement is being handled with transform.Translate (I have also tried every other possible combination of moving everything but nothing helped with the stuttering or the collision issues).
As you can see from the image, the game is VERY simple, but because it's fast paced, the pauses are really noticeable and the game is difficult enough without these hiccups!
It also needs to be noted that these issues ONLY happen on iOS, on all of my devices (iPad4, iPhone 4, iPhone 4S, iPhone 5C). What's even stranger is that I get a perfect 60fps on all devices, even the 4, so I'm certainly not doing anything to test the grunt of these machines!
Here is my collision code and yes, I tried with triggers/colliders too, still have the issues. I've even tried using box colliders instead of mesh colliders... NOTHING works!
function CheckCollision()
{
RayStartPos = _rayEmitterTransform.position;
if (Physics.Raycast (RayStartPos, transform.right, hit, fRayDistance) ||
Physics.Raycast (RayStartPos, transform.forward, hit, fRayDistance * 2) ||
Physics.Raycast (RayStartPos, -transform.right, hit, fRayDistance))
{
bGameIsOver = true;
}
else
{
Debug.DrawRay (RayStartPos, transform.right * fRayDistance, Color.green);
Debug.DrawRay (RayStartPos, -transform.right * fRayDistance, Color.green);
Debug.DrawRay (RayStartPos, transform.forward * (fRayDistance * 2), Color.green);
}
yield;
}
I don't know the answer, but the yield statement at the end of the function is doing nothing and should be removed.
Yeah, I put that in everything I'm accessing from update, was just testing... I was reading about coroutines last night... still don't understand them. lol. Anyway, the yields are gone now and didn't make a difference anyway.
Answer by POLYGAMe · Feb 17, 2014 at 10:34 PM
Well, after a lot of frustration, hair-pulling and kicking the neighbour's cat, I found it!
DYNAMIC FONTS!
I just read that with dynamic fonts, a new texture has to be generated every time a new character is drawn on screen. I had the font size set to a ridiculously high value so they looked ultra smooth... basically, when the ship affected the score, a new texture was being generated, thus causing that spike. This is why it was only happening when the objects were moving on the z axis, as when they get to a certain position, the score is incremented. This was also affecting my collision, as it was drawing that massive game over texture when the ray cast hit.
I'm not sure if what I have said above is 100% correct, but by removing the objects, I eliminated both problems, so I'm guessing it's pretty much spot on!
He deserved it... he kept trying to fix it with Python scripts.
Answer by MakeCodeNow · Feb 17, 2014 at 02:17 AM
If you have access to the Unity Profiler, you should definitely check this out. It's designed to help you drill down and figure out what's causing these kind of hitches. Without that tool, the best anyone can do is guess, so here are some guesses: The 200ms hitch might be garbage collection. It's pretty long for GC, but you never know. I'd scan your code for things that might be generating a lot of grabage, like foreach loops, container modification, and anywhere you call new. Another guess is that the hitch is asset load related. It's unlikely with a game as simple as yours but it could be that an asset somehow becomes unreferenced and unloaded and then needs to be loaded again. * It might be a background process on iOS that you have no control over. Try rebooting the device and testing again. If you can't repro the hitch, then that's a clue.
Lastly, with this kind of stuff you can try shutting down systems in your game one at a time until the hitch goes away. If it does go away, then you can keep doing that until you isolate the problem code.
Good luck!
It's not the GC, everything is being recycled. I only instantiate 4 walls on startup, no other new items are being created.
I doubt it's iOS background related as I have no other apps running, have reset the device and it does it on all of my devices anyway.
And lastly, I have done exactly that... checked with and without just about every possible combination of object activations... really is a head scratcher!!!!
I've tried all available resolutions, all quality settings, v-sync on and off, nothing works!
Oh, something I hadn't checked... I don't know why, is if it happened when I turned the obstacles off... when they are not being moved, the hiccupping stops! So it's in my UpdateObstacles function.
I'm the first to admit, I'm not the greatest technical coder (more the arty type, lol), so is there anything obvious in this code that is awfully done?
function UpdateObstacles()
{
if (_wallTransforms[0].position.z < _playerTransform.position.z - iScoreOffset && !bScoreIsSet)
{
iScore++;
bScoreIsSet = true;
}
if (_wallTransforms[0].position.z < f$$anonymous$$axPosZ)
{
_wallTransforms[0].position.z = _wallTransforms[_wallTransforms.length - 1].position.z + fOffset;
bScoreIsSet = false;
}
_wallTransforms[0].Translate(0,0,fWall$$anonymous$$oveSpeed * Time.deltaTime);
_wallRenderers[0].material.color.r = Random.Range(0.0, 1.0);
_wallRenderers[0].material.color.g = Random.Range(0.0, 1.0);
_wallRenderers[0].material.color.b = Random.Range(0.0, 1.0);
for (var i = 1; i < _wallTransforms.length; ++i)
{
if (_wallTransforms[i].position.z < _playerTransform.position.z - iScoreOffset && !bScoreIsSet)
{
iScore++;
bScoreIsSet = true;
}
if (_wallTransforms[i].position.z < f$$anonymous$$axPosZ)
{
_wallTransforms[i].position.z = _wallTransforms[i - 1].position.z + fOffset;
bScoreIsSet = false;
}
_wallRenderers[i].material.color.r = Random.Range(0.0, 1.0);
_wallRenderers[i].material.color.g = Random.Range(0.0, 1.0);
_wallRenderers[i].material.color.b = Random.Range(0.0, 1.0);
_wallTransforms[i].Translate(0,0,fWall$$anonymous$$oveSpeed * Time.deltaTime);
}
yield;
}
I've streamlined it a bit but would still like to know what I'm doing wrong:
function UpdateObstacles()
{
for (var i = 0; i < _wallTransforms.length; ++i)
{
if (_wallTransforms[i].position.z < _playerTransform.position.z - iScoreOffset && !bScoreIsSet)
{
iScore++;
bScoreIsSet = true;
}
if (_wallTransforms[i].position.z < f$$anonymous$$axPosZ)
{
if (i == 0)
{
_wallTransforms[0].position.z = _wallTransforms[_wallTransforms.length - 1].position.z + fOffset;
}
else
{
_wallTransforms[i].position.z = _wallTransforms[i - 1].position.z + fOffset;
}
bScoreIsSet = false;
}
_wallRenderers[i].material.color.r = Random.Range(0.0, 1.0);
_wallRenderers[i].material.color.g = Random.Range(0.0, 1.0);
_wallRenderers[i].material.color.b = Random.Range(0.0, 1.0);
_wallTransforms[i].Translate(0,0,fWall$$anonymous$$oveSpeed * Time.deltaTime);
}
yield;
}
And here's where I set my obstacles, if this helps...
function SetObstacles()
{
Obstacles = new GameObject[5];
Obstacles[0] = Obstacle;
Obstacles[0].name = "Obstacle_0";
for (var i = 1; i < Obstacles.length; ++i)
{
Obstacles[i] = Instantiate(Obstacle, transform.position, transform.rotation);
Obstacles[i].transform.position.z = Obstacles[i - 1].transform.position.z + fOffset;
Obstacles[i].transform.eulerAngles.z = Random.Range(0, 360);
Obstacles[i].transform.parent = ObstacleParent.transform;
Obstacles[i].name = "Obstacle_" + i;
}
}
Your code and debugging process is pretty solid for an "arty type". You're doing well :)
200ms is a long time. I doubt it's in your code but the code you are calling. $$anonymous$$y guess is that if you comment out the call to Translate() that the hitch goes away. If that's the case, it makes me think that something you're doing is kicking off a lot of internal physics processing. Is your object marked as static? Try disabling components in the Obstacle until you figure out the source.
Your answer
Follow this Question
Related Questions
Stuttering/Jerky at constant movement Unity3D. 1 Answer
Camera doesn't move smoothly at 60fps 1 Answer
Problem with Android Framerate Dropping 2 Answers
Game Freezes upon successive loads 0 Answers
rigidbody addforce jittering 4 Answers