I am making somewhat of a flappy bird clone (mostly for practice) and everything works fine, but it is just really slow with a low FPS of 13 and a max FPS of 28. Why would this be?
So I ran a check with the unity profiler and it turns out that my MoveLeft script which I am using to reuse my obstacles is taking up 73% of the CPU. I have it attached to each of my 6 prefabs, which include 2 long obstacles and a token (to collect) in middle each. The game works by moving the prefabs along the camera, then moving them back after they pass the camera.
Here is the script:
using UnityEngine;
using System.Collections;
public class MoveLeft : MonoBehaviour
{
[SerializeField]
private float _speed = 5f;
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.left * Time.deltaTime * _speed);
if (transform.position.x < -15)
{
float randomYPosition = UnityEngine.Random.Range(-3, 3);
transform.position = new Vector3(15, randomYPosition, 0);
}
}
}
I really want to fix the lag. What can I do? I am sure this is the script causing it, but without this script my game does not work. Thank you! All help is appreciated!
Hierarchy (objects that I am moving with MoveLeft script. Script only attached to tree parents)
And a scene view that displays colliders found in prefabs
Profiler with information regarding my MoveLeft script
Answer
Performance problems are tricky to diagnose remotely, but the fact that your palm trees turn almost solid green when selected is a probable clue.
If you started with a nice high-resolution image, Unity probably generated PolygonCollider2D data like what you see on the left: trying to capture each frond in exacting detail.
But if you're making a flappy bird clone, that detail is wasted. If a player ever ends up between those fronds or below the crown they're screwed anyway, so you don't need pixel-perfect collisions there. You could manually tweak the points to get something like the one in the middle, or replace the PolygonCollider2D with a simple EdgeCollider2D chain like the example on the right, for virtually identical gameplay.
Why does the polygon count matter so much?
When it comes to physics and collision tests, checking against a mesh of polygons is one of the most expensive things you can do. Circles/spheres and other primitives like boxes are generally a lot faster than similarly-shaped meshes, so you'll want to avoid polygon meshes whenever you don't need vertex-for-vertex fidelity, or at least try to keep the number of polygons/edges as low as possible.
But wait, why is the game even doing detailed collision calculations for these trees when the player is nowhere near them?
Because of this line:
transform.Translate(Vector3.left * Time.deltaTime * _speed);
Physics objects, including colliders, are happiest when they're moving using physics (like Rigidbody2D forces & velocities). That lets the physics engine make good predictions about where they're going and what they might hit along the way, so it only checks for the minimum number of collisions each step.
When you Translate
a physics object like a Collider
, from the perspective of the physics engine it's just teleported, and could potentially be anywhere in the scene, intersecting with any other body. So suddenly its predictions are out the window and it needs to do more exhaustive checks and updates to make sure it safely handles even the worst teleportation cases. Any clever acceleration structures it had for speeding up checks against this object are now invalid too and need to be rebuilt - this is especially expensive for static colliders (ones with no Rigidbody
/Rigidbody2D
) as the physics system assumes these will never move. All that work is what's spiking time in your update function.
This gets compounded if the trees are in a physics layer that's allowed to collide with itself - because now the engine has to check not just each tree against the player, but each tree against every other tree.
So, your best bet fixes, with the biggest performance wins first:
Don't move the trees every frame. Move the camera and the player avatar. Then you only need to reposition a tree when it scrolls off-screen, and then only one tree at a time. Huge win.
Simplify your colliders to the minimum of what you need for your gameplay, using EdgeCollider2D or simpler primitives if possible. If you need to depart from the visible shape, err toward the inside - players feel much better about living when it looked like they were going to die than they do about dying when it looked like they should've lived. ;)
If you need objects to move every frame, do it with a Rigidbody2D and velocity. That way the physics engine keeps control of their locations and has fewer surprises thrown its way, so it can work at peak efficiency. You can also set the body to Kinematic if you need to override the physics without incurring the cost of moving static colliders.
Keep the obstacles in a physics layer that only collides with the player. That lets the physics engine focus only on the collisions that could possibly matter for gameplay.
No comments:
Post a Comment