118 lines
4.3 KiB
C#
118 lines
4.3 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Code.Track
|
|
{
|
|
public class TrackBuilder : MonoBehaviour
|
|
{
|
|
[SerializeField] private GameObject roadTilePrefab;
|
|
[SerializeField] private float roadWidth = 8f;
|
|
|
|
[SerializeField] private GameObject leftBarrierPrefab;
|
|
[SerializeField] private GameObject rightBarrierPrefab;
|
|
[SerializeField] private float barrierSpacing = 2f;
|
|
|
|
[SerializeField] private GameObject mountainPrefab;
|
|
|
|
[SerializeField] private float mountainSpacing = 10f;
|
|
[SerializeField] private float mountainOffsetFromRoad = 10f;
|
|
[SerializeField] [Range(1f, 100f)] private float mountainMinDistance = 30f;
|
|
[SerializeField] [Range(1f, 3f)] private float mountainScaleMin = 1f;
|
|
[SerializeField] [Range(1f, 3f)] private float mountainScaleMax = 2f;
|
|
|
|
private readonly List<GameObject> _spawned = new();
|
|
|
|
public void Build(TrackData data)
|
|
{
|
|
Clear();
|
|
if (data?.Waypoints == null || data.Waypoints.Count < 2) return;
|
|
|
|
BuildRoadAndBarriers(data);
|
|
BuildMountains(data);
|
|
}
|
|
|
|
private void BuildRoadAndBarriers(TrackData data)
|
|
{
|
|
var points = data.Waypoints;
|
|
for (var i = 0; i < points.Count - 1; i++)
|
|
{
|
|
var a = points[i];
|
|
var b = points[i + 1];
|
|
var delta = b - a;
|
|
|
|
if (delta.sqrMagnitude < 0.01f) continue;
|
|
|
|
var forward = delta.normalized;
|
|
var right = Vector3.Cross(Vector3.up, forward);
|
|
var length = delta.magnitude;
|
|
|
|
var roadPos = (a + b) / 2f;
|
|
var roadRot = Quaternion.LookRotation(forward, Vector3.up);
|
|
var road = Instantiate(roadTilePrefab, roadPos, roadRot, transform);
|
|
road.transform.localScale = new Vector3(roadWidth, 1f, length);
|
|
_spawned.Add(road);
|
|
|
|
var fenceSegments = Mathf.Max(1, Mathf.CeilToInt(length / barrierSpacing));
|
|
for (var j = 0; j <= fenceSegments; j++)
|
|
{
|
|
var t = j / (float)fenceSegments;
|
|
var pos = Vector3.Lerp(a, b, t);
|
|
var leftPos = pos - right * (roadWidth * 0.5f + 0.5f);
|
|
var rightPos = pos + right * (roadWidth * 0.5f + 0.5f);
|
|
|
|
Instantiate(leftBarrierPrefab, leftPos, roadRot, transform);
|
|
Instantiate(rightBarrierPrefab, rightPos, roadRot, transform);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void BuildMountains(TrackData data)
|
|
{
|
|
if (mountainPrefab == null || data.Waypoints.Count < 2) return;
|
|
|
|
var spacing = Mathf.Max(1f, mountainMinDistance);
|
|
|
|
for (var i = 0; i < data.Waypoints.Count - 1; i++)
|
|
{
|
|
var a = data.Waypoints[i];
|
|
var b = data.Waypoints[i + 1];
|
|
var delta = b - a;
|
|
|
|
if (delta.sqrMagnitude < 0.01f) continue;
|
|
|
|
var forward = delta.normalized;
|
|
var right = Vector3.Cross(Vector3.up, forward);
|
|
var segmentLength = delta.magnitude;
|
|
|
|
var mountainCountOnSegment = Mathf.Max(1, Mathf.RoundToInt(segmentLength / spacing));
|
|
|
|
for (var j = 0; j < mountainCountOnSegment; j++)
|
|
{
|
|
var t = (j + 0.5f) / mountainCountOnSegment;
|
|
if (t > 1f) t = 1f;
|
|
|
|
var posOnSegment = Vector3.Lerp(a, b, t);
|
|
|
|
var useLeft = j % 2 == 0;
|
|
var outwardDir = useLeft ? -right : right;
|
|
|
|
var mountainPos = posOnSegment + outwardDir * (roadWidth * 0.5f + mountainOffsetFromRoad);
|
|
mountainPos.y = 0f;
|
|
|
|
var mountainRot = Quaternion.LookRotation(forward, Vector3.up);
|
|
|
|
var mountain = Instantiate(mountainPrefab, mountainPos, mountainRot, transform);
|
|
var scale = Random.Range(mountainScaleMin, mountainScaleMax);
|
|
mountain.transform.localScale = Vector3.one * scale;
|
|
_spawned.Add(mountain);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Clear()
|
|
{
|
|
foreach (var obj in _spawned) Destroy(obj);
|
|
_spawned.Clear();
|
|
}
|
|
}
|
|
} |