I am doing a car racing project, a part of said project is a system for returning stuck AI cars into the road.
The script stores the nearest waypoint id(waypoints are in an array on another script) in a variable.
When the car is stuck for x amount of seconds we do the following:
- Place the car at a position relative to the stored waypoint
- Change the layer of the gameobject that contains the rigidbody to another layer called “ReSpawn”. This layer is configured to not collide with the other cars respawning or otherwise.
- When the car has been in its new position for 3 seconds, it returns to the default layer, and is now able to collide with other cars.
I have 2 emerging bugs in this implementation:
- The collision layers just don’t work. The car still collides with incoming cars and with other respawning cars.
- The cars seem to share the currentTrackerWP variable, even though it is not static. Resulting in cars spawning not in their designated waypoints, but in the next waypoint of the car that updated it last(I am not even sure if this is true, just my guess from the debug logs the code has spewed in the past)
This is the script, the layer change happens on line 82, in line 88 there is a method being invoked that restores the layer, that method is in line 57.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AIController : MonoBehaviour
{
public Circuit circuit;
Drive ds;
public float brakingSensitivity = 1.1f;
public float steeringSensitivity = 0.01f;
public float accelSensitivity = 0.3f;
public float distanceToTargetThreshold = 2.0f; //threshold, aumentar si el coche empieza a dar vueltas entorno a un waypoint
Vector3 target;
Vector3 nextTarget;
int currentWP = 0;
float totalDistanceToTarget;
GameObject tracker; //El objeto al que sigue el vehículo
int currentTrackerWP = 0;
public float lookAhead = 12;
float lastTimeMoving = 0;
void Start()
{
ds = this.GetComponent<Drive>();
target = circuit.waypoints[currentWP].transform.position;
nextTarget = circuit.waypoints[currentWP + 1].transform.position;
totalDistanceToTarget = Vector3.Distance(target, ds.rigidbody.gameObject.transform.position);
tracker = GameObject.CreatePrimitive(PrimitiveType.Capsule);
DestroyImmediate(tracker.GetComponent<Collider>());
tracker.GetComponent<MeshRenderer>().enabled = false;
tracker.transform.position = ds.rigidbody.gameObject.transform.position;
tracker.transform.rotation = ds.rigidbody.gameObject.transform.rotation;
//Ghost Shader Effect
this.GetComponent<Ghost>().enabled = false;
}
void ProgressTracker()
{
Debug.DrawLine(ds.rigidbody.gameObject.transform.position, tracker.transform.position);
if(Vector3.Distance(ds.rigidbody.gameObject.transform.position, tracker.transform.position) > lookAhead)
return;
tracker.transform.LookAt(circuit.waypoints[currentTrackerWP].transform.position);
tracker.transform.Translate(0, 0, 1.0f);
if(Vector3.Distance(tracker.transform.position, circuit.waypoints[currentTrackerWP].transform.position) < 1) //Tolerancia
{
currentTrackerWP++;
if(currentTrackerWP >= circuit.waypoints.Length)
currentTrackerWP = 0;
}
}
void ResetLayer()
{
ds.rigidbody.gameObject.layer = 0;
//Debug.Log("rigidbody layer: "+ ds.rigidbody.gameObject.layer + " lastTimeMoving: " + lastTimeMoving);
//Ghost Shader Effect
this.GetComponent<Ghost>().enabled = false;
}
void Update()
{
ProgressTracker();
Vector3 localTarget;
float targetAngle;
//Car Stuck Fix
if(ds.rigidbody.velocity.magnitude > 1)
{
lastTimeMoving = Time.time;
}
if(Time.time > lastTimeMoving + 4)
{
ds.rigidbody.gameObject.transform.position = circuit.waypoints[currentTrackerWP].transform.position + Vector3.up * 2 +
new Vector3(Random.Range(-1,1), 1, Random.Range(-1,1));
tracker.transform.position = ds.rigidbody.gameObject.transform.position;
ds.rigidbody.gameObject.layer = 8;
//Debug.Log("rigidbody layer: "+ ds.rigidbody.gameObject.layer + " lastTimeMoving: " + lastTimeMoving);
//Ghost Shader Effect
this.GetComponent<Ghost>().enabled = false;
Invoke("ResetLayer", 3);
}
//Car Bump Fix
if(Time.time < ds.rigidbody.GetComponent<AvoidDetector>().avoidTime)
{
localTarget = tracker.transform.right * ds.rigidbody.GetComponent<AvoidDetector>().avoidPath;
}
else
{
localTarget = ds.rigidbody.gameObject.transform.InverseTransformPoint(tracker.transform.position);
}
targetAngle = Mathf.Atan2(localTarget.x, localTarget.z) * Mathf.Rad2Deg;
float speedFactor = ds.currentSpeed / ds.maxSpeed;
float corner = Mathf.Clamp(Mathf.Abs(targetAngle), 0, 90);
float cornerFactor = corner/90.0f;
//Steer
float steer = Mathf.Clamp(targetAngle * steeringSensitivity, -1, 1) * Mathf.Sign(ds.currentSpeed);
//Brake
float brake = 0;
if(corner > 10 && speedFactor > 0.1f) //Alterar el valor este si va lento en esquinas
{
brake = Mathf.Lerp(0, 1 + speedFactor * brakingSensitivity, cornerFactor);
}
//Acceleration
float accel = 1f;
if(corner > 20 && speedFactor > 0.2f)
{
accel = Mathf.Lerp(0, 1 * accelSensitivity, 1 - cornerFactor);
}
//Debug.Log("Brake: "+ brake + " Accel: " + accel + " Speed: " + ds.rigidbody.velocity.magnitude);
ds.Go(accel,steer, brake);
ds.CheckForSkid();
ds.CalculateEngineSound();
}
}
This is the layer setup

And this is the layer collision matrix
