- Home /
How can I optimize this code?
Here is my Fixed Update code... It has very poor performance on mobile devices. There is anywhere from 100-500 objects in the scene running this code at any given time. I was hoping maybing someone could give me some insight on how this code could potentionally be optimized. Once the game reaches about 300+ of these objects on a high end mobile device frame rate drops to around 15 fps.
void FixedUpdate()
{
if (GetComponent<Chicken>().isFollowing)
{
transform.LookAt(GetComponent<Chicken>().GetFollowingPlayer());
GetComponent<Rigidbody>().velocity = Vector3.Slerp(GetComponent<Rigidbody>().velocity, transform.forward * GetComponent<Chicken>().followSpeed, Time.deltaTime * turnSpeed);
}
else
{
Wander();
}
}
public void Wander()
{
transform.LookAt(wanderDestination);
GetComponent<Rigidbody>().velocity = Vector3.Slerp(GetComponent<Rigidbody>().velocity, transform.forward * speed, Time.deltaTime * turnSpeed);
distanceToDestination = wanderDestination - GetComponent<Rigidbody>().position;
if (distanceToDestination.magnitude < 1)
{
SetRandomDestination();
}
}
public void SetRandomDestination()
{
wanderDestination = RandomNavSphere(transform.position, wanderRadius, -1);
}
public static Vector3 RandomNavSphere(Vector3 origin, float dist, int layermask)
{
NavMesh.SamplePosition((Random.insideUnitSphere * dist) + origin, out navHit, dist, layermask);
return navHit.position;
}
You can start by not using .GetComponent
so casually. It's expensive and you're better off saving that reference the first time you encounter it.
Answer by andrew-lukasik · Sep 18, 2018 at 10:11 PM
Separate Physics updates from your ai/decision making code and run these in batches:
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class Mob : MonoBehaviour
{
static List<Mob> _instances = new List<Mob>(100);
[SerializeField] [HideInInspector] Rigidbody _rigidbody;
Vector3 _targetVelocity;
#if UNITY_EDITOR
void OnValidate ()
{
if( _rigidbody==null ) { _rigidbody = GetComponent<Rigidbody>(); }
}
void OnDrawGizmos ()
{
Vector3 position = transform.position;
Gizmos.color = Color.blue;
Gizmos.DrawLine( position , position + _targetVelocity );
Gizmos.color = Color.cyan;
Gizmos.DrawLine( position , position + _rigidbody.velocity );
}
#endif
void OnEnable ()
{
//register instance:
if( _instances.Count==_instances.Capacity )
{
_instances.Capacity *= 2;
}
_instances.Add( this );
}
void OnDisable ()
{
//unregister instance:
_instances.Remove( this );
}
void FixedUpdate ()
{
//NO AI CODE, simple operations only
_rigidbody.velocity = Vector3.Lerp( _rigidbody.velocity , _targetVelocity , Time.fixedDeltaTime );
}
async Task AiTick ()
{
//AI CODE GOES HERE
if( Random.value>0.5f )
{
Vector2 vec = Random.insideUnitCircle;
_targetVelocity = new Vector3( vec.x , 0f , vec.y );
}
else
{
_targetVelocity = Vector3.zero;
}
await Task.CompletedTask;
}
[RuntimeInitializeOnLoadMethod]
static async void MobAi ()
{
List<Mob> batch = new List<Mob>();
while( Application.isPlaying )
{
//grab new batch:
batch.Clear();
batch.AddRange( _instances );
//process batch:
foreach( Mob mob in batch )
{
//execute ai code:
await mob.AiTick();
}
//await:
await Task.Delay( 1000/4 );
}
}
}
This has made the performance impeccable! BUT I am struggling to get this to run smoothly. It creates a very choppy movement.
This batching is very interesting! Also, a bit beyond my current skill set but has really opened my eyes to taking my program$$anonymous$$g to the next level. Thank you for this.
$$anonymous$$y fixed Timestep is .05. It seems interpolation no longer works?. Only if lower the fixed timestep will it run smooth. But increasing the timestep will bring me back to low performance. Some insight on how I might address the choppy movement of the game objects would be much appreciated! Thanks!
Answer by Eno-Khaon · Sep 18, 2018 at 08:54 PM
The biggest piece of advice here:
CACHE YOUR COMPONENT CALLS!
Every time you call GetComponent(), you're making a very complex check for a component on your GameObject. If you cache the results of those into each object, that alone will save a ton of unnecessary calculation work.
As an example of how to approach this:
Rigidbody rb;
Chicken ckn;
void Start()
{
rb = GetComponent<Rigidbody>();
ckn = GetComponent<Chicken>();
}
void FixedUpdate()
{
if (ckn.isFollowing)
// etc.
}
Yes, that's the 99.9% of the problem. The other operations you do are O$$anonymous$$ including the random functions.
While I agree with the caching, I don't agree with the variable na$$anonymous$$g :P
This did improve performance. It's Certainly not 99% of the problem as @Baalhug suggested. It is a step in the right direction for sure. I still get a low FPS on mobile though. @andrew-lukasik suggestion has dramatically increased performance.
Your answer
Follow this Question
Related Questions
Performance of 2D Apps on mobile: Optimizations? 0 Answers
SketchUp Sandbox vs. Unity Terrain 2 Answers
How performant is performant? 0 Answers
Improving code performance 1 Answer