We usually want to create experiences that adapt to the player, and racing games are a good field for this, given that there is this gap of the cheater agent.
In this case, we will explore a middle ground for this using a framework that allows you to come up with your own heuristic for managing the speed of the vehicle given its status. It doesn't matter if it is an arcade racing game or simulation; the framework aims to work in a similar fashion for both the cases.
It is important to have grasped the basic skills in Chapter 1, Movement, in order to be able to develop a strategy to extend the framework for your own needs—that is, understanding the principles of how the agent class works and how the behaviors help the player move toward an object. In a nutshell, we are talking about vector operations.
We will implement three different classes for handling low-level and high-level AIs as follows:
using UnityEngine; public class RacingRival : MonoBehaviour { public float distanceThreshold; public float maxSpeed; public Vector3 randomPos; protected Vector3 targetPosition; protected float currentSpeed; protected RacingCenter ghost; }
Start
function:void Start() { ghost = FindObjectOfType<RacingCenter>(); }
Update
function for handling the target position to follow:public virtual void Update() { targetPosition = transform.position + randomPos; AdjustSpeed(targetPosition); }
public virtual void AdjustSpeed(Vector3 targetPosition) { // TODO // your own behaviour here }
using UnityEngine; public class RacingCenter : RacingRival { public GameObject player; }
void Start() { player = GameObject.FindGameObjectWithTag("Player"); }
Update
function, so the invincible car can adapt to the player's behavior:public override void Update() { Vector3 playerPos = player.transform.position; float dist = Vector3.Distance(transform.position, playerPos); if (dist > distanceThreshold) { targetPosition = player.transform.position; base.Update(); } }
public override void AdjustSpeed(Vector3 targetPosition) { // TODO // Use in case the base behaviour also applies base.AdjustSpeed(targetPosition); }
using UnityEngine; public class Rubberband : MonoBehaviour { RacingCenter ghost; RacingRival[] rivals; }
void Start() { ghost = FindObjectOfType<RacingCenter>(); rivals = FindObjectsOfType<RacingRival>(); foreach (RacingRival r in rivals) { if (ReferenceEquals(r, ghost)) continue; r.randomPos = Random.insideUnitSphere; r.randomPos.y = ghost.transform.position.y; } }
The high-level AI rubber system assigns the positions to be held by the racers. Each racer has its own behavior for adjusting speed, especially the invincible racer. This agent works as the center of the mass of the rubber band. If its dance from the player exceeds the threshold, it will adapt. Otherwise, it'll stay just the same, wobbling.