Unity — custom class enums for fun and profit

Richard Morgan
4 min readJan 8, 2023

--

Let’s have some fun with enums using a custom class. We’ll make 3 speeds for our ai and cycle through the speeds every time we press the space bar, like this:

First, we create our new custom class, AISpeed:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

[System.Serializable]
public class AISpeed
{
// The name of the AI
public string name;
// The speed of the AI
public float speed;
// The state of the AI's speed
public enum SpeedState
{
Slow,
Medium,
Fast
}
public SpeedState speedState;

// This method logs a message to the console depending on the value of speedState
public void Action()
{
switch (speedState)
{
case SpeedState.Slow:
Debug.Log("Slow");
break;
case SpeedState.Medium:
Debug.Log("Medium");
break;
case SpeedState.Fast:
Debug.Log("Fast");
break;
}
}
}

This code defines a class called AISpeed that represents the speed of an artificial intelligence (AI) in a game. The AISpeed class has several fields:

  • name: a string that represents the name of the AI.
  • speed: a float that represents the speed of the AI.
  • speedState: an enumeration (enum) that represents the state of the AI's speed. The possible values of this enum are Slow, Medium, and Fast.

The AISpeed class also has a method called Action that logs a message to the console depending on the value of speedState. If speedState is Slow, it will log "Slow". If speedState is Medium, it will log "Medium". If speedState is Fast, it will log "Fast".

The [System.Serializable] attribute above the class definition indicates that the class can be serialized, meaning that it can be converted to and from a data format such as JSON. This is useful if you want to save the state of an AISpeed object to a file or transmit it over a network.

The using statements at the top of the code allow you to use types from the specified namespaces in your code without specifying the full namespace every time. For example, you can use Vector3 from the UnityEngine namespace simply by writing Vector3 instead of UnityEngine.Vector3.

Now the Speed script that we’ll add to our ai gameobject:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Speed : MonoBehaviour
{
// A list of AISpeed objects representing the possible speeds of the AI
public List<AISpeed> aiSpeeds = new List<AISpeed>();
// The index of the current speed in the aiSpeeds list
private int currentSpeedState = 0;

void Start()
{
// Initialize the AI's speed to the first element in the aiSpeeds list
aiSpeeds[currentSpeedState].Action();
// Set the speed of the NavMeshAgent component to the current speed
GetComponent<NavMeshAgent>().speed = aiSpeeds[currentSpeedState].speed;
}

private void Update()
{
// When the space bar is pressed, change the speed of the AI
if (Input.GetKeyDown(KeyCode.Space))
{
// Increment currentSpeedState and wrap around to 0 if it goes out of bounds
currentSpeedState = (currentSpeedState + 1) % aiSpeeds.Count;
// Perform the action associated with the current speed
aiSpeeds[currentSpeedState].Action();
// Set the speed of the NavMeshAgent component to the current speed
GetComponent<NavMeshAgent>().speed = aiSpeeds[currentSpeedState].speed;
}
}
}

And now we can name and set the values of our speeds in the inspector:

There are a few ways that we could optimize this code:

  1. Instead of using a List to store the AISpeed objects, you could use an array. This would eliminate the overhead of the List class and allow you to access elements in the array more quickly.
  2. Instead of calling GetComponent<NavMeshAgent>() every time you want to access the NavMeshAgent component, you could store a reference to the component in a field. This would avoid the overhead of calling GetComponent every time.
  3. Instead of using the modulo operator (%) to wrap the currentSpeedState index around to 0 when it goes out of bounds, you could simply use an if statement to check if the index has exceeded the bounds of the array and set it to 0 if necessary. This would eliminate the overhead of the modulo operation.

Here we go:

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.AI;

public class Speed : MonoBehaviour
{
// An array of AISpeed objects representing the possible speeds of the AI
public AISpeed[] aiSpeeds;
// The index of the current speed in the aiSpeeds array
private int currentSpeedState = 0;
// A reference to the NavMeshAgent component
private NavMeshAgent navMeshAgent;

void Start()
{
// Store a reference to the NavMeshAgent component
navMeshAgent = GetComponent<NavMeshAgent>();
// Initialize the AI's speed to the first element in the aiSpeeds array
aiSpeeds[currentSpeedState].Action();
// Set the speed of the NavMeshAgent component to the current speed
navMeshAgent.speed = aiSpeeds[currentSpeedState].speed;
}

private void Update()
{
// When the space bar is pressed, change the speed of the AI
if (Input.GetKeyDown(KeyCode.Space))
{
// Increment currentSpeedState and wrap around to 0 if it goes out of bounds
currentSpeedState++;
if (currentSpeedState >= aiSpeeds.Length)
{
currentSpeedState = 0;
}
// Perform the action associated with the current speed
aiSpeeds[currentSpeedState].Action();
// Set the speed of the NavMeshAgent component to the current speed
navMeshAgent.speed = aiSpeeds[currentSpeedState].speed;
}
}
}

Much better!

--

--