random road generation
This commit is contained in:
1 parent
b974bbd843
commit
ee223cabfd
56 files changed
+2952
-169
No files matched your search
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c32358014964dd3ab6783e71e070ff1
|
||||
timeCreated: 1769501961
|
||||
@@ -0,0 +1,118 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ac421d3ef9c48cdbe79b83b0557568a
|
||||
timeCreated: 1769502030
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Track
|
||||
{
|
||||
public class TrackData
|
||||
{
|
||||
public List<Vector3> Waypoints { get; }
|
||||
public Vector3 StartPosition { get; }
|
||||
public Quaternion StartRotation { get; }
|
||||
public Vector3 FinishPosition { get; }
|
||||
|
||||
public TrackData(List<Vector3> waypoints)
|
||||
{
|
||||
Waypoints = new List<Vector3>(waypoints);
|
||||
StartPosition = waypoints[0];
|
||||
StartRotation = Quaternion.LookRotation(waypoints[1] - waypoints[0]);
|
||||
FinishPosition = waypoints[^1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f38e4bf429a54e4395e1f51c56047bd7
|
||||
timeCreated: 1769501974
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Track
|
||||
{
|
||||
public static class TrackGenerator
|
||||
{
|
||||
public static TrackData Generate(int seed, float targetLength = 200f, int segmentCount = 15)
|
||||
{
|
||||
Random.InitState(seed);
|
||||
|
||||
var points = new List<Vector3> { Vector3.zero };
|
||||
var currentPos = Vector3.zero;
|
||||
var direction = Vector3.forward;
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
{
|
||||
var turn = Random.Range(-25f, 25f);
|
||||
direction = Quaternion.Euler(0, turn, 0) * direction;
|
||||
direction.y = 0;
|
||||
direction.Normalize();
|
||||
|
||||
var segLen = targetLength / segmentCount;
|
||||
currentPos += direction * segLen;
|
||||
points.Add(currentPos);
|
||||
}
|
||||
|
||||
var actualLength = 0f;
|
||||
for (var i = 1; i < points.Count; i++)
|
||||
actualLength += Vector3.Distance(points[i - 1], points[i]);
|
||||
|
||||
if (actualLength > 0.1f)
|
||||
{
|
||||
var scale = targetLength / actualLength;
|
||||
for (var i = 1; i < points.Count; i++)
|
||||
points[i] *= scale;
|
||||
}
|
||||
|
||||
return new TrackData(points);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92c8821d77f0436089f488c3ae723f1f
|
||||
timeCreated: 1769502005
|
||||
@@ -0,0 +1,27 @@
|
||||
using Code.Track;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.UI
|
||||
{
|
||||
public class GameplayController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TrackBuilder trackBuilder;
|
||||
[SerializeField] private Transform playerSpawn;
|
||||
[SerializeField] private Transform finishTrigger;
|
||||
|
||||
private TrackData _currentTrack;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
var seed = Random.Range(0, 10000);
|
||||
_currentTrack = TrackGenerator.Generate(seed, 1000, segmentCount: 30);
|
||||
|
||||
trackBuilder.Build(_currentTrack);
|
||||
|
||||
playerSpawn.position = _currentTrack.StartPosition;
|
||||
playerSpawn.rotation = _currentTrack.StartRotation;
|
||||
|
||||
finishTrigger.position = _currentTrack.FinishPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 881e19e06bba4abaa5010c71ab21de1a
|
||||
timeCreated: 1769502053
|
||||
Reference in new issue
Block a user