Chapter 2. Scripting Strategies

Since scripting will consume a great deal of our development time, it will be enormously beneficial to learn some best practices. Scripting is a very broad term, so we will try to limit our exposure in this chapter to situations that are very Unity specific, focusing on problems arising from within the Unity APIs and engine design. We will discuss the nuances and advanced topics of the C# language, .NET library, and Mono Framework, in Chapter 7, Masterful Memory Management.

Whether you have some specific problems in mind that you wish to solve or you just want to learn some techniques for future reference, this chapter will introduce you to an array of methods that you can use to improve your scripting efforts now and in the future. In each case, we will explore how and why the performance issue arises, an example situation in which the problem is occurring, and one or more solutions to combat the issue.

Cache Component references

A common mistake when scripting in Unity is to overuse the GetComponent() method. For example, the following script code is trying to check a creature's health value, and if its health goes below 0, disable a series of Components to prepare it for a death animation:

void TakeDamage() {
  if (GetComponent<HealthComponent>().health < 0) {
    GetComponent<Rigidbody>().enabled = false;
    GetComponent<Collider>().enabled = false;
    GetComponent<AIControllerComponent>().enabled = false;
    GetComponent<Animator>().SetTrigger("death");
  }
}

Each time this method executes, it will reacquire five different Component references. This is good in terms of heap memory consumption (in that it doesn't cost any), but it is not very friendly on CPU usage. This is particularly problematic if the main method were called during Update(). Even if it is not, it still might coincide with other important events, such as creating particle effects, replacing an object with a ragdoll (thus invoking various activity in the physics engine), and so on. This coding style can seem harmless, but it can cause a lot of long-term problems and runtime work for very little benefit.

It costs us very little memory space (only 32 or 64 bits each time; Unity version, platform, and fragmentation permitting) to cache these references for future use. So, unless you're extremely bottlenecked on memory, a better approach would be to acquire the references during initialization and keep them until they are needed:

private HealthComponent _healthComponent;
private Rigidbody _rigidbody;
private Collider _collider;
private AIControllerComponent _aiController;
private Animator _animator;

void Awake() {
  _healthComponent = GetComponent<HealthComponent>();
  _rigidbody = GetComponent<Rigidbody>();
  _collider = GetComponent<Collider>();
  _aiController = GetComponent<AIControllerComponent>();
  _animator = GetComponent<Animator>();
}

void TakeDamage() {
  if (_healthComponent.health < 0) {
    _rigidbody.detectCollisions = false;
    _collider.enabled = false;
    _aiController.enabled = false;
    _animator.SetTrigger("death");
  }
}

Caching the Component references in this way spares us from reacquiring them each time they're needed, saving us some CPU overhead each time, at the expense of some additional memory consumption.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.199.184