Managing race difficulty using a rubber-banding system

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.

Getting ready

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.

How to do it...

We will implement three different classes for handling low-level and high-level AIs as follows:

  1. Create the class for the basic rival agent:
    using UnityEngine;
    
    public class RacingRival : MonoBehaviour
    {
        public float distanceThreshold;
        public float maxSpeed;
        public Vector3 randomPos;
        protected Vector3 targetPosition;
        protected float currentSpeed;
        protected RacingCenter ghost;
    }
  2. Implement the Start function:
    void Start()
    {
        ghost = FindObjectOfType<RacingCenter>();
    }
  3. Define the Update function for handling the target position to follow:
    public virtual void Update()
    {
        targetPosition = transform.position + randomPos;
        AdjustSpeed(targetPosition);
    }
  4. Define your function for adjusting the speed accordingly:
    public virtual void AdjustSpeed(Vector3 targetPosition)
    {
        // TODO
        // your own behaviour here
    }
  5. Create the class for handling the ghost rider or an invincible racer:
    using UnityEngine;
    
    public class RacingCenter : RacingRival
    {
        public GameObject player;
    }
  6. Implement the initial function for finding its target:
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");
    }
  7. Override the 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();
        }
    }
  8. Implement its special behavior:
    public override void AdjustSpeed(Vector3 targetPosition)
    {
    
        // TODO
        // Use in case the base behaviour also applies
        base.AdjustSpeed(targetPosition);
    }
  9. Create the class for handling the high-level AI:
    using UnityEngine;
    
    public class Rubberband : MonoBehaviour
    {
        RacingCenter ghost;
        RacingRival[] rivals;
    }
  10. Assign each racer its random position in the rubber system. We are using a circular rubber band in this case:
    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;
        }
    }

How it works…

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.75.217