Hello guys. I’m currently in the process of debugging my game to make it as polished as possible when I released it. However, I soon find out I’m getting a major drop in frame rate which is quite a big problem for me.
The game works perfectly fine in like the first 30 levels, the frame rate is consistent and playable. In the last several levels of my game, I deemed some of the levels in the game as being unplayable. So out of all the levels available, maybe only 3-5 levels are having major frame rate drops. So I tested a level that I noticed to be lagging the most and here’s the result:
I’m kind of new with using the Profiler but I do know it’s a good tool to optimize my game as much as possible. In the screenshot, you can see that Physics2D.FixedUpdate is getting huge spikes. I’m not sure why that’s the case but my theories are that because it’s a shoot em up game, the cause must be either the bullets instantiated in the game or the enemies active in the scene. I’ve already rewrote my whole game so that it’s using as less Physics as I can but the issue is still happening with no improvement.
All my enemies are pretty much the same when it comes to behaviour. They have a Rigidbody2D (Is Kinematic set to true) and a Polygon Collider2D. The script pretty much looks like this:
using UnityEngine;
public class PursuerController : MonoBehaviour
{
public StatusIndicator status;
public GameObject basicNeon;
public GameObject explosion;
private DataManager data;
private GameManager GM;
private SFXManager SFXManager;
private Rigidbody2D pursuer;
private EnemyStatsController stats;
private ShieldController shieldControl;
private Transform target;
private bool isCollided;
void Start()
{
data = GameObject.FindWithTag("PlayManager").GetComponent<DataManager>();
GM = GameObject.FindWithTag("GameManager").GetComponent<GameManager>();
SFXManager = GameObject.FindWithTag("GameManager").transform.GetChild(1).GetComponent<SFXManager>();
pursuer = GetComponent<Rigidbody2D>();
stats = GetComponent<EnemyStatsController>();
stats.maxHealth = (int)Random.Range(30f, 45f) * data.difficulty;
stats.speed = Random.Range(0.9f, 1.3f) * data.difficulty;
stats.collisionDamage = Random.Range(11f, 17f);
stats.CurHealth = stats.maxHealth;
shieldControl = GameObject.FindWithTag("Shield").GetComponent<ShieldController>();
target = GameObject.FindWithTag("Player").transform;
}
void Update()
{
// Sets health bar
status.SetHealth(stats.CurHealth, stats.maxHealth);
if (stats.CurHealth <= 0f)
{
GM.totalEnemiesDestroyed++;
float killReward = Random.Range(stats.minKillReward, stats.maxKillReward) / data.difficulty;
if (!isCollided)
{
// Instantiate neons
for (int i = 0; i < Random.Range(stats.neonControl.basicMinAmount, stats.neonControl.basicMaxAmount); i++)
Instantiate(basicNeon, transform.position, Quaternion.identity);
}
// Set neon display and rewards
data.lastNeon = data.displayedNeon;
if (!isCollided)
{
GM.totalNeonsCollected += killReward;
data.curNeon += killReward;
}
else
{
GM.totalNeonsCollected += killReward / 2;
data.curNeon += killReward / 2;
}
data.neonTimer = 0f;
// Destroys enemy
Destroy(gameObject);
Destroy(transform.parent.gameObject);
}
}
void FixedUpdate()
{
if (!stats.freeze)
{
// Unfreeze
pursuer.constraints = RigidbodyConstraints2D.None;
if (Vector3.Distance(target.position, transform.position) > 0f)
{
// Direction vector from enemy to target
Vector3 dir = target.position - transform.position;
// Rotation to always face player
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle - 90, Vector3.forward);
// Move the enemy into the direction
transform.position = Vector3.MoveTowards(transform.position, target.position, stats.speed * Time.deltaTime);
}
}
else
// Freeze
pursuer.constraints = RigidbodyConstraints2D.FreezeAll;
}
void OnTriggerEnter2D(Collider2D other)
{
if (!shieldControl.isActivated)
{
// Collide if shield deactivated
if (other.gameObject.tag == "Player")
{
isCollided = true;
// Explosion effect
GameObject explosionInstance = (GameObject)Instantiate(explosion, transform.position, Quaternion.identity);
Destroy(explosionInstance, 0.5f);
SFXManager.PlaySound("Explosion", true);
// Kills off enemy
stats.CurHealth -= stats.maxHealth;
}
}
}
}
If the problem is the bullets, I suspect the OnTriggerEnter2D checks is the reason causing the lag but I may be totally wrong. Script:
using UnityEngine;
public class EnemyBulletController : MonoBehaviour
{
public float speed;
public float damage;
public GameObject playerHitEffect;
public GameObject shieldHitEffect;
public LayerMask playerLayer;
private DataManager data;
void Start()
{
data = GameObject.FindWithTag("PlayManager").GetComponent<DataManager>();
}
void Update()
{
// Automatically destroy bullet when out of bounds
if (transform.position.x > data.xBound || transform.position.x < -data.xBound || transform.position.y > data.yBound || transform.position.y < -data.yBound)
Destroy(gameObject);
}
void FixedUpdate()
{
// Bullet's movement
transform.position += transform.up * (speed * data.difficulty);
}
void OnTriggerEnter2D(Collider2D other)
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, transform.up, 100f, playerLayer);
if (hit.collider != null)
{
if (other.gameObject.tag == "Shield")
{
// Hit effect then destroy it
GameObject hitInstance = (GameObject)Instantiate(shieldHitEffect, hit.point, Quaternion.identity);
hitInstance.transform.up = hit.normal;
Destroy(hitInstance, 0.5f);
// Destroy bullet
Destroy(gameObject);
}
if (other.gameObject.tag == "Player")
{
// Damage the player
other.transform.root.GetComponent<PlayerStatsController>().TakeDamage(damage);
// Hit effect then destroy it
GameObject hitInstance = (GameObject)Instantiate(playerHitEffect, hit.point, Quaternion.identity);
hitInstance.transform.up = hit.normal;
Destroy(hitInstance, 0.5f);
// Destroy bullet
Destroy(gameObject);
}
}
}
}
More info: The level I’m testing on lags when there are more than 20 of these enemies in the scene. This may be more on other people’s computer because my laptop isn’t that powerful.



