Skip to main content

Random Direction Changer

Written by: Akram Taghavi-Burris | © Copyright 2024
Status

Randomly Change Directions

Our apple tree's movement is looking great! However, we have one final requirement: the ability to randomly change direction. Since this requirement may not be needed for every movable object, we will create a standalone class called RandomDirectionChanger.

The RandomDirectionChanger will randomly reverse a game object's direction based on a specified percentage chance, checked at regular intervals. When the condition is met, it will call the ReverseDirection method that we have already implemented in the MovableObjectBase. To access the ReverseDirection method, our RandomDirectionChanger will need to reference the MovableObjectBase component.

RandomDirectionChanger.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static CSG.Utilities.TimeUtilities;

public class RandomDirectionChanger : MonoBehaviour
{
[SerializeField]
[Tooltip("Percentage chance of changing direction (e.g., 10%)"))]
private float _changeDirectionChance = 10f;

[SerializeField]
[Tooltip("Time interval (in seconds) to check for direction change")]
private float _checkInterval = 2f; // How often to check (in seconds)

// Property to get or set the ChangeDirectionChance of the object
public float ChangeDirectionChance
{
get => _changeDirectionChance;
set => _changeDirectionChance = value;
}

// Property to get or set the CheckItnerval
public float CheckInterval
{
get => _checkInterval;
set => _checkInterval = value;
}


private MovableObjectBase _movableObject; // Reference to the MovableObjectBase

private void Start()
{
// Get the MovableObjectBase component on the same game object
_movableObject = GetComponent<MovableObjectBase>();

// Start the coroutine to check for direction change at regular intervals
StartCoroutine(ChangeDirectionRandomly());
}//end Start()

// Coroutine to check for direction change at specified intervals
private IEnumerator ChangeDirectionRandomly()
{
while (true)
{

yield return new WaitForSecondsGametime(_checkInterval); // Wait for the next interval in game time

// Roll a random number between 0 and 100
float randomRoll = Random.Range(0f, 100f);

// If the roll is less than or equal to the changeDirectionChance, reverse direction
if (randomRoll <= _changeDirectionChance)
{
_movableObject.ReverseDirection();
Debug.Log("Direction Changed!");
}//end if (randomRoll <= _changeDirectionChance)
}//end While
}//end IEnumerator
}

WaitForSeconds

To check for random direction changes, we set up an IEnumerator in our RandomDirectionChanger class that waits based on our specified check interval. Unity provides two built-in wait methods, each with its own drawbacks:

  • WaitForSeconds: This method waits for a specified amount of time but can drift over long durations, particularly if the game is paused or if the frame rate fluctuates significantly.

  • WaitForSecondsRealtime: This method waits based on real-time, continuing even when the game is paused. However, it is not suitable for scenarios where the wait needs to be tied to game activity.

Since there isn't a built-in option that combines accurate game timing with pause-aware functionality, we will implement a custom WaitForSecondsGameTime class. Because this logic could be useful elsewhere, we will organize it within a TimeUtilities class.