feat(traffic): add motorcycles with overtaking behavior

main
uc-hoba 3 weeks ago
parent a81533f4e7
commit 57a2ff0852
  1. 249
      Assets/Main.unity
  2. 245
      Assets/Scripts/Traffic/TrafficLane.cs
  3. 2
      Assets/Settings/PC_RPAsset.asset
  4. 146
      Assets/Temp/Motor.prefab
  5. 7
      Assets/Temp/Motor.prefab.meta

@ -288,6 +288,71 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 139439301}
m_CullTransparentMesh: 1
--- !u!1 &191862871
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 191862873}
- component: {fileID: 191862872}
m_Layer: 0
m_Name: Traffic (1)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &191862872
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 191862871}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b9bb25da9b61d4849b3c17eff30adbf8, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TrafficLane
routeLength: 60
laneCenter: 0
vehiclePrefabs:
- {fileID: 1557020077158108179, guid: 7893264379c7b27449c0d5cd800de112, type: 3}
- {fileID: 6059035821173914762, guid: bf52a0f6f1d4ca94abedb85fa135a7cd, type: 3}
- {fileID: 7937761055385602081, guid: 692d27357d450044883464a7dc84418a, type: 3}
motorcyclePrefabs: []
motorcycleRatio: 0
motorcycleSpeedMultiplier: 1.3
overtakeWidth: 0.5
poolSize: 16
baseSpeed: 6
speedVariance: 0.05
followDistance: 6
safeGap: 2
spawnInterval: 0.5
spawnIntervalVariance: 0.4
minSpawnGap: 4
driftAmplitude: 0.05
driftFrequency: 0.08
lateralSmoothSpeed: 2
--- !u!4 &191862873
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 191862871}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0.24, y: 0, z: -23.145}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1527156285}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &203844586
GameObject:
m_ObjectHideFlags: 0
@ -1836,14 +1901,21 @@ MonoBehaviour:
- {fileID: 1557020077158108179, guid: 7893264379c7b27449c0d5cd800de112, type: 3}
- {fileID: 6059035821173914762, guid: bf52a0f6f1d4ca94abedb85fa135a7cd, type: 3}
- {fileID: 7937761055385602081, guid: 692d27357d450044883464a7dc84418a, type: 3}
poolSize: 12
motorcyclePrefabs: []
motorcycleRatio: 0
motorcycleSpeedMultiplier: 1.3
overtakeWidth: 0.5
poolSize: 16
baseSpeed: 6
speedVariance: 0.05
followDistance: 6
safeGap: 2
spawnInterval: 0.5
spawnIntervalVariance: 0.4
minSpawnGap: 4
driftAmplitude: 0.05
driftFrequency: 0.08
lateralSmoothSpeed: 2
--- !u!4 &980030821
Transform:
m_ObjectHideFlags: 0
@ -1852,13 +1924,79 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 980030819}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
m_LocalPosition: {x: -0.28, y: 0, z: 37.23}
m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
m_LocalPosition: {x: -0.28, y: 0, z: 37.5}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_Father: {fileID: 1527156285}
m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
--- !u!1 &1032635067
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1032635068}
- component: {fileID: 1032635069}
m_Layer: 0
m_Name: Traffic w/ motor (1)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1032635068
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1032635067}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0.71, y: 0, z: -23.03}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1527156285}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1032635069
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1032635067}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b9bb25da9b61d4849b3c17eff30adbf8, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TrafficLane
routeLength: 60
laneCenter: 0
vehiclePrefabs:
- {fileID: 1557020077158108179, guid: 7893264379c7b27449c0d5cd800de112, type: 3}
- {fileID: 6059035821173914762, guid: bf52a0f6f1d4ca94abedb85fa135a7cd, type: 3}
- {fileID: 7937761055385602081, guid: 692d27357d450044883464a7dc84418a, type: 3}
motorcyclePrefabs:
- {fileID: 6625968966535654452, guid: 446dfb1d91ecfcf41a2aaefc67e0a310, type: 3}
motorcycleRatio: 0.9
motorcycleSpeedMultiplier: 1.3
overtakeWidth: 0.2
poolSize: 60
baseSpeed: 4
speedVariance: 0.05
followDistance: 4
safeGap: 2
spawnInterval: 0.1
spawnIntervalVariance: 0.4
minSpawnGap: 1
driftAmplitude: 0.2
driftFrequency: 0.08
lateralSmoothSpeed: 2
--- !u!1 &1142443635
GameObject:
m_ObjectHideFlags: 0
@ -2157,6 +2295,41 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1527156284
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1527156285}
m_Layer: 0
m_Name: Traffics
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1527156285
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1527156284}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 980030821}
- {fileID: 1804377709}
- {fileID: 191862873}
- {fileID: 1032635068}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1553319431
GameObject:
m_ObjectHideFlags: 0
@ -2451,6 +2624,72 @@ Canvas:
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!1 &1804377707
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1804377709}
- component: {fileID: 1804377708}
m_Layer: 0
m_Name: Traffic w/ motor
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1804377708
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1804377707}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b9bb25da9b61d4849b3c17eff30adbf8, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::TrafficLane
routeLength: 60
laneCenter: 0
vehiclePrefabs:
- {fileID: 1557020077158108179, guid: 7893264379c7b27449c0d5cd800de112, type: 3}
- {fileID: 6059035821173914762, guid: bf52a0f6f1d4ca94abedb85fa135a7cd, type: 3}
- {fileID: 7937761055385602081, guid: 692d27357d450044883464a7dc84418a, type: 3}
motorcyclePrefabs:
- {fileID: 6625968966535654452, guid: 446dfb1d91ecfcf41a2aaefc67e0a310, type: 3}
motorcycleRatio: 0.9
motorcycleSpeedMultiplier: 1.3
overtakeWidth: 0.2
poolSize: 60
baseSpeed: 4
speedVariance: 0.05
followDistance: 4
safeGap: 2
spawnInterval: 0.1
spawnIntervalVariance: 0.4
minSpawnGap: 1
driftAmplitude: 0.2
driftFrequency: 0.08
lateralSmoothSpeed: 2
--- !u!4 &1804377709
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1804377707}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 1, z: -0, w: 0}
m_LocalPosition: {x: -0.73, y: 0, z: 37.5}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1527156285}
m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
--- !u!1 &1889754488
GameObject:
m_ObjectHideFlags: 0
@ -3908,6 +4147,6 @@ SceneRoots:
- {fileID: 604712594}
- {fileID: 505702790}
- {fileID: 1142443636}
- {fileID: 980030821}
- {fileID: 1527156285}
- {fileID: 465598214}
- {fileID: 303688530}

@ -4,12 +4,13 @@ using UnityEngine;
/// <summary>
/// Simulates a single lane of traffic by recycling a fixed pool of vehicle GameObjects.
/// Vehicles travel along local +Z, with organic lateral drift driven by Perlin noise.
/// Cars decelerate to maintain a safe following gap; motorcycles overtake by shifting sideways.
/// Vehicles travel along local +Z with organic Perlin-noise lateral drift.
///
/// Usage:
/// 1. Place this component on an empty GameObject aligned with the road lane.
/// 2. Assign vehicle prefabs, tune speed and drift.
/// 3. Duplicate and mirror-X for the opposite lane.
/// 2. Assign car / motorcycle prefabs, tune speed and drift.
/// 3. Duplicate and mirror-X (or rotate 180°) for the opposite lane.
/// </summary>
public class TrafficLane : MonoBehaviour
{
@ -24,11 +25,28 @@ public class TrafficLane : MonoBehaviour
// ── Vehicle Pool ──────────────────────────────────────────────────────────
[Header("Vehicle Pool")]
[Tooltip("Prefabs to randomly draw from when spawning. Can contain different vehicle types.")]
[Header("Cars")]
[Tooltip("Car prefabs — randomly chosen at spawn.")]
[ListDrawerSettings(ShowFoldout = false)]
public GameObject[] vehiclePrefabs;
[Header("Motorcycles")]
[Tooltip("Motorcycle prefabs — randomly chosen at spawn. Leave empty to disable motorcycles.")]
[ListDrawerSettings(ShowFoldout = false)]
public GameObject[] motorcyclePrefabs;
[Tooltip("Fraction of pool slots assigned to motorcycles.")]
[Range(0f, 1f)]
public float motorcycleRatio = 0.2f;
[Tooltip("Motorcycles travel this many times faster than baseSpeed on average.")]
[Range(1f, 2.5f)]
public float motorcycleSpeedMultiplier = 1.3f;
[Tooltip("How far sideways (units) a motorcycle shifts when overtaking.")]
public float overtakeWidth = 0.5f;
[Header("Pool")]
[Tooltip("Total number of vehicle instances kept alive at once.")]
[Range(1, 60)]
public int poolSize = 12;
@ -39,9 +57,18 @@ public class TrafficLane : MonoBehaviour
[Tooltip("Average forward speed in units / second.")]
public float baseSpeed = 6f;
[Tooltip("Per-vehicle speed spread as a fraction of baseSpeed (±).")]
[Tooltip("Per-vehicle speed randomisation as a fraction of baseSpeed (±).")]
[Range(0f, 0.5f)]
public float speedVariance = 0.2f;
public float speedVariance = 0.3f;
// ── Following ─────────────────────────────────────────────────────────────
[Header("Following")]
[Tooltip("Distance at which a vehicle starts reacting to the vehicle ahead.")]
public float followDistance = 8f;
[Tooltip("Minimum comfortable gap. At this distance the follower matches the leader's speed exactly.")]
public float safeGap = 2f;
// ── Spawn ─────────────────────────────────────────────────────────────────
@ -66,14 +93,25 @@ public class TrafficLane : MonoBehaviour
[Range(0.01f, 1f)]
public float driftFrequency = 0.08f;
// ── Private state ─────────────────────────────────────────────────────────
[Tooltip("How quickly vehicles adjust their lateral position (affects drift smoothness and overtake transitions).")]
[Range(0.5f, 10f)]
public float lateralSmoothSpeed = 2f;
// ── Internals ─────────────────────────────────────────────────────────────
private enum VehicleType { Car, Motorcycle }
private class Agent
{
public GameObject go;
public float progress; // distance travelled along Z this trip
public float speed; // units / second for this trip
public float noiseRow; // unique Y coordinate in Perlin space for this trip
public VehicleType type;
public float progress; // distance travelled along Z this trip
public float targetSpeed; // natural cruising speed assigned at spawn
public float currentSpeed; // actual speed this frame (may be reduced by following)
public float noiseRow; // unique Y coordinate in Perlin space
public float currentLateral; // smoothed lateral X position
public bool overtaking; // motorcycle is currently overtaking
public float overtakeLateral; // lateral target while overtaking
public bool active;
}
@ -85,7 +123,7 @@ public class TrafficLane : MonoBehaviour
private void Start()
{
if (vehiclePrefabs == null || vehiclePrefabs.Length == 0)
if (!HasAnyPrefab())
{
Debug.LogWarning("[TrafficLane] No vehicle prefabs assigned.", this);
enabled = false;
@ -94,8 +132,6 @@ public class TrafficLane : MonoBehaviour
BuildPool();
ScheduleNextSpawn();
// Scatter a few vehicles along the lane so it doesn't look empty at start.
PrewarmLane();
}
@ -111,16 +147,28 @@ public class TrafficLane : MonoBehaviour
{
for (var i = 0; i < poolSize; i++)
{
var prefab = vehiclePrefabs[Random.Range(0, vehiclePrefabs.Length)];
var go = Instantiate(prefab, transform);
var isMotorcycle = HasMotorcyclePrefabs() && Random.value < motorcycleRatio;
var prefabs = PickPrefabArray(isMotorcycle);
if (prefabs == null || prefabs.Length == 0)
{
continue;
}
var go = Instantiate(prefabs[Random.Range(0, prefabs.Length)], transform);
go.SetActive(false);
pool.Add(new Agent { go = go, noiseRow = Random.Range(0f, 100f) });
pool.Add(new Agent
{
go = go,
type = isMotorcycle ? VehicleType.Motorcycle : VehicleType.Car,
noiseRow = Random.Range(0f, 100f),
currentLateral = laneCenter
});
}
}
private void PrewarmLane()
{
// Spread inactive vehicles evenly so the lane looks populated from frame 1.
var step = routeLength / Mathf.Max(poolSize * 0.5f, 1f);
var z = Random.Range(0f, step);
foreach (var agent in pool)
@ -145,7 +193,45 @@ public class TrafficLane : MonoBehaviour
continue;
}
agent.progress += agent.speed * Time.deltaTime;
FindLeader(agent, out var leaderGap, out var leaderSpeed, out var leaderLateral);
var hasSlowerLeader = leaderGap < followDistance &&
leaderSpeed < agent.targetSpeed * 0.98f;
// ── Longitudinal speed ────────────────────────────────────────────
float effectiveSpeed;
if (agent.type == VehicleType.Motorcycle && hasSlowerLeader)
{
// Motorcycle keeps speed and moves sideways to overtake.
effectiveSpeed = agent.targetSpeed;
agent.overtaking = true;
var side = leaderLateral >= laneCenter ? -1f : 1f;
agent.overtakeLateral = laneCenter + side * overtakeWidth;
}
else
{
// Car (or motorcycle with no slow leader ahead): follow and decelerate.
if (leaderGap < followDistance)
{
var t = Mathf.Clamp01(
(leaderGap - safeGap) / Mathf.Max(followDistance - safeGap, 0.01f));
effectiveSpeed = Mathf.Lerp(leaderSpeed, agent.targetSpeed, t);
}
else
{
effectiveSpeed = agent.targetSpeed;
}
if (agent.overtaking && leaderGap >= followDistance)
{
agent.overtaking = false;
}
}
agent.currentSpeed = Mathf.Max(effectiveSpeed, 0f);
agent.progress += agent.currentSpeed * Time.deltaTime;
if (agent.progress >= routeLength)
{
@ -153,15 +239,28 @@ public class TrafficLane : MonoBehaviour
continue;
}
// Perlin noise: x-axis = position along route, y-axis = per-agent seed.
var noise = Mathf.PerlinNoise(agent.progress * driftFrequency, agent.noiseRow);
var lateral = laneCenter + (noise * 2f - 1f) * driftAmplitude;
// ── Lateral position ──────────────────────────────────────────────
float targetLateral;
if (agent.overtaking)
{
targetLateral = agent.overtakeLateral;
}
else
{
var noise = Mathf.PerlinNoise(agent.progress * driftFrequency, agent.noiseRow);
targetLateral = laneCenter + (noise * 2f - 1f) * driftAmplitude;
}
agent.currentLateral = Mathf.Lerp(
agent.currentLateral, targetLateral, Time.deltaTime * lateralSmoothSpeed);
// ── Apply transform ───────────────────────────────────────────────
var prev = agent.go.transform.localPosition;
var next = new Vector3(lateral, 0f, agent.progress);
var next = new Vector3(agent.currentLateral, 0f, agent.progress);
agent.go.transform.localPosition = next;
// Face direction of travel, ignoring tiny sub-frame deltas.
var delta = next - prev;
if (delta.sqrMagnitude > 1e-6f)
{
@ -181,7 +280,6 @@ public class TrafficLane : MonoBehaviour
spawnTimer = 0f;
ScheduleNextSpawn();
// Block spawn if another vehicle is still near the entry point.
foreach (var agent in pool)
{
if (agent.active && agent.progress < minSpawnGap)
@ -195,27 +293,51 @@ public class TrafficLane : MonoBehaviour
// ── Helpers ───────────────────────────────────────────────────────────────
private void Activate(Agent agent, float startProgress)
private void FindLeader(Agent self, out float gap, out float speed, out float lateral)
{
gap = float.MaxValue;
speed = baseSpeed;
lateral = laneCenter;
foreach (var other in pool)
{
if (!other.active || other == self)
{
continue;
}
var g = other.progress - self.progress;
if (g > 0f && g < gap)
{
gap = g;
speed = other.currentSpeed;
lateral = other.currentLateral;
}
}
}
private void Activate(Agent agent, float startZ)
{
agent.progress = startProgress;
agent.speed = baseSpeed * (1f + Random.Range(-speedVariance, speedVariance));
var speedMult = agent.type == VehicleType.Motorcycle ? motorcycleSpeedMultiplier : 1f;
agent.progress = startZ;
agent.targetSpeed = baseSpeed * speedMult * (1f + Random.Range(-speedVariance, speedVariance));
agent.currentSpeed = agent.targetSpeed;
agent.noiseRow = Random.Range(0f, 100f);
agent.overtaking = false;
var noise = Mathf.PerlinNoise(startZ * driftFrequency, agent.noiseRow);
agent.currentLateral = laneCenter + (noise * 2f - 1f) * driftAmplitude;
agent.go.transform.localPosition = new Vector3(agent.currentLateral, 0f, startZ);
agent.go.SetActive(true);
agent.active = true;
// Teleport silently to start position before enabling.
var noise = Mathf.PerlinNoise(startProgress * driftFrequency, agent.noiseRow);
var lateral = laneCenter + (noise * 2f - 1f) * driftAmplitude;
agent.go.transform.localPosition = new Vector3(lateral, 0f, startProgress);
}
private void SpawnNext(float startProgress)
private void SpawnNext(float startZ)
{
foreach (var agent in pool)
{
if (!agent.active)
{
Activate(agent, startProgress);
Activate(agent, startZ);
return;
}
}
@ -234,6 +356,26 @@ public class TrafficLane : MonoBehaviour
nextSpawnDelay = Mathf.Max(0.1f, spawnInterval + Random.Range(-variance, variance));
}
private bool HasAnyPrefab() =>
(vehiclePrefabs != null && vehiclePrefabs.Length > 0) ||
(motorcyclePrefabs != null && motorcyclePrefabs.Length > 0);
private bool HasMotorcyclePrefabs() =>
motorcyclePrefabs != null && motorcyclePrefabs.Length > 0;
private GameObject[] PickPrefabArray(bool motorcycle)
{
if (motorcycle && HasMotorcyclePrefabs())
{
return motorcyclePrefabs;
}
if (vehiclePrefabs != null && vehiclePrefabs.Length > 0)
{
return vehiclePrefabs;
}
return motorcyclePrefabs;
}
// ── Editor visualisation ──────────────────────────────────────────────────
#if UNITY_EDITOR
@ -245,18 +387,29 @@ public class TrafficLane : MonoBehaviour
Gizmos.color = Color.yellow;
Gizmos.DrawLine(start, end);
// Drift envelope.
// Drift envelope
Gizmos.color = new Color(1f, 1f, 0f, 0.25f);
var left = transform.TransformPoint(new Vector3(laneCenter - driftAmplitude, 0f, 0f));
var right = transform.TransformPoint(new Vector3(laneCenter + driftAmplitude, 0f, 0f));
var leftEnd = transform.TransformPoint(new Vector3(laneCenter - driftAmplitude, 0f, routeLength));
var rightEnd = transform.TransformPoint(new Vector3(laneCenter + driftAmplitude, 0f, routeLength));
Gizmos.DrawLine(left, leftEnd);
Gizmos.DrawLine(right, rightEnd);
Gizmos.DrawLine(left, right);
Gizmos.DrawLine(leftEnd, rightEnd);
// Entry / exit markers.
var ll = transform.TransformPoint(new Vector3(laneCenter - driftAmplitude, 0f, 0f));
var rl = transform.TransformPoint(new Vector3(laneCenter + driftAmplitude, 0f, 0f));
var lle = transform.TransformPoint(new Vector3(laneCenter - driftAmplitude, 0f, routeLength));
var rle = transform.TransformPoint(new Vector3(laneCenter + driftAmplitude, 0f, routeLength));
Gizmos.DrawLine(ll, lle);
Gizmos.DrawLine(rl, rle);
Gizmos.DrawLine(ll, rl);
Gizmos.DrawLine(lle, rle);
// Overtake envelope (shown only when motorcycles are configured)
if (HasMotorcyclePrefabs() && motorcycleRatio > 0f)
{
Gizmos.color = new Color(0.4f, 0.8f, 1f, 0.15f);
var ml = transform.TransformPoint(new Vector3(laneCenter - overtakeWidth, 0f, 0f));
var mr = transform.TransformPoint(new Vector3(laneCenter + overtakeWidth, 0f, 0f));
var mle = transform.TransformPoint(new Vector3(laneCenter - overtakeWidth, 0f, routeLength));
var mre = transform.TransformPoint(new Vector3(laneCenter + overtakeWidth, 0f, routeLength));
Gizmos.DrawLine(ml, mle);
Gizmos.DrawLine(mr, mre);
}
Gizmos.color = Color.green;
Gizmos.DrawSphere(start, 0.3f);
Gizmos.color = Color.red;

@ -44,7 +44,7 @@ MonoBehaviour:
m_ProbeVolumeSHBands: 1
m_MainLightRenderingMode: 1
m_MainLightShadowsSupported: 1
m_MainLightShadowmapResolution: 2048
m_MainLightShadowmapResolution: 8192
m_AdditionalLightsRenderingMode: 1
m_AdditionalLightsPerObjectLimit: 4
m_AdditionalLightShadowsSupported: 0

@ -0,0 +1,146 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1140205653522362818
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6935756313134080057}
- component: {fileID: 311920771717202595}
- component: {fileID: 7669487799238204824}
- component: {fileID: 8064391062658887605}
m_Layer: 0
m_Name: Dummy
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6935756313134080057
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1140205653522362818}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0.055, z: 0}
m_LocalScale: {x: 0.07, y: 0.11, z: 0.185}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7216495632142374776}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &311920771717202595
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1140205653522362818}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &7669487799238204824
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1140205653522362818}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!65 &8064391062658887605
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1140205653522362818}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!1 &6625968966535654452
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7216495632142374776}
m_Layer: 0
m_Name: Motor
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7216495632142374776
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6625968966535654452}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6935756313134080057}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 446dfb1d91ecfcf41a2aaefc67e0a310
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Loading…
Cancel
Save