Modular Scripts in Game Design

Clint Wagoner
3 min readMar 13, 2023

--

How to use less and do more in Unity.

Setting up your scripts to work on multiple versions of the same object type is a necessity in game design. Using Object-Oriented-Programming, Let’s look at how we can use one script for multiple objects in our space shooter game.

Object IDs

In my power-up script, I am using IDs to determine which power-up to give the player. Let’s take a quick look at how this works.

Essentially I am creating a number that will tell the script which effect to use on the player. To do this we need to make a variable that holds the ID, let’s make it a [SerializedField] so that we can change it in the editor. Then, in whatever logic we are writing we can separate our powerup effects via a conditional statement. In this example, I am using the ID to determine which effect to give the player.

public class PowerUp : MonoBehaviour
{
//ID variable
[SerializeField] private int _powerUpID;

private Player _player;
private Shooting _shooting;

void Start()
{
_player = FindObjectOfType<Player>();
_shooting = GameObject.Find("Player").GetComponent<Shooting>();
}


private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
//Using the ID '0' to give the speed power-up
if (_powerUpID == 0)
_player.SpeedPowerUp(_playerSpeedMultiplier, _powerUpCoolDown);

//Using the ID '1' to give the triple shot power-up
if (_powerUpID == 1)
_shooting.TripleShotActive(_powerUpCoolDown);

}
}

}

Arrays

You can also use arrays to get different outputs from a single class. With our Spawn Manager class, we can use an array to tell our spawn manager what to spawn. This is a better practice than if we were to write a new spawn manager for all of the objects we want to spawn in. For example, I am using the SpawnManager class on my enemies, asteroids, and even powerups. One script to rule them all and in arrays, bind them (Kind of nerdy and cheese…I know).

Let’s break the script apart and check out what’s going on here.

public class SpawnManager : MonoBehaviour
{
[SerializeField] private float _fastest = 3f;
[SerializeField] private float _longest = 6f;
[SerializeField] private GameObject[] _spawnPrefabs;
[SerializeField] private GameObject _spawnContainer;
private Vector3 _spawnPos;
private bool _stopSpawning;

void Start()
{
StartCoroutine(SpawnRoutine());
}

IEnumerator SpawnRoutine()
{
while (_stopSpawning == false)
{
int spawnIndex = Random.Range(0, _spawnPrefabs.Length);
_spawnPos = new Vector3(Random.Range(-15, 15), 30, 0);
GameObject newSpawn = Instantiate(_spawnPrefabs[spawnIndex], _spawnPos, _spawnPrefabs[spawnIndex].transform.rotation);
newSpawn.transform.parent = _spawnContainer.transform;
Debug.Log("Spawned Prefab number " + spawnIndex);
yield return new WaitForSeconds(Random.Range(_fastest, _longest));
}
}

public void OnGameOver()
{
_stopSpawning= true;
}
}

Notice we have an array called ‘_spawnPrefabs’. This is an array that will let me add whatever objects I want to spawn per different instance of the same class. So I can have an asteroid spawner object, an enemy spawner object, and a power-up spawner object all use the same ‘SpawnManager’ script. All I have to do is drag different corresponding prefabs into these ‘spawnPrefab ’ slots.

And there you go! Two ways to make your scripts more modular!

Thanks for reading!

--

--