Skip to content

Latest commit

 

History

History
116 lines (96 loc) · 3.3 KB

CS_UNITY.md

File metadata and controls

116 lines (96 loc) · 3.3 KB

Related Refactoring Techniques

Universal C#

OOP

  • Use a serialized public property to cut down a serialized private field
// 👎 non-compliant
[SerializeField] private int _level;
public int Level => _level;

// 👍 preference
[field: SerializeField] public int Level {get; private set;}

// 👍 preference: use UsedImplicitly attribute if only assign in Inspector
[field: SerializeField] public int Level {get; [UsedImplicitly] private set;}
[field: SerializeField] [UsedImplicitly] public int Level {get; private set;}

Declaration, Initialization & Assignment

  • Refer directly to specific component when Instantiate new GameObject
// 👎 non-compliant
GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);
bulletBody = bullet.GetComponent<Rigidbody>();
bulletBody.velocity = transform.forward * speed;

// 👍 preference
Rigidbody bulletBody = Instantiate(bulletPrefab, transform.position, transform.rotation);
bulletBody.velocity = transform.forward * speed;
  • Declare public members which don't need to modify in Playmode w/ [HideInInspector] attribute

Reason: clean up Inspector

Function

  • Pass individual vector components without creating new vector (Unity API usually has overloading method for this, otherwise, create extension method)
// 👎 non-compliant
_ballRigidbody.AddForce(shotPoint.transform.TransformDirection(new Vector3(0f, 0f, _powerToRoll)));

// 👍 preference
_ballRigidbody.AddForce(shotPoint.transform.TransformDirection(0f, 0f, _powerToRoll));

Animation

  • Use hash id to change animator state

Reason: do not need to validate string each time -> improve performance

// 👎 non-compliant
void Update(){
  if(attackKey.IsUp()) anim.SetTrigger("Attack");
}

// 👍 performance
private readonly int ATTACK_HASH = Animator.StringToHash("Attack");

void Update(){
  if(attackKey.IsUp()) anim.SetTrigger(ATTACK_HASH);
}

3rd-Party Asset

  • Wrap asset API usage in its conditional compiling symbol (directive) to avoid error on its absence.

Use CCU to automatically detect and add asset symbol.

  • Create a wrapper/adapter for commonly-used class/attribute from 3rd-party asset
// 👎 non-compliant
public class MyClass1 : MonoBehaviour {
#if USING_SERVICE
  [SerializeField] private ServiceClass _service;
#endif
  
  public void DoSomething() {
#if USING_SERVICE
    _service.Execute();
#endif
  }
}
// and many other classes using ServiceClass...

// 👍 preference
[Serializable]
public class ServiceWrapper {
#if USING_SERVICE
  [SerializeField] private ServiceClass _service;
#endif

  public void Execute() {
#if USING_SERVICE
    _service.Execute();
#endif
}

public class MyClass1 {
  [SerializeField] private ServiceWrapper _service;
  
  public void DoSomething() {
    _service.Execute();
  }
}

Others

  • GetComponent => TryGetComponent when need to get and use a component:
// 👎 non-compliant
bulletBody = bullet.GetComponent<Rigidbody>();
if(bulletBody is not null) 
  bulletBody.velocity = transform.forward * speed;

// 👍 preference
if(bullet.TryGetComponent(out Rigidbody bulletBody)
  bulletBody.velocity = transform.forward * speed;