using System.Collections.Generic;
using UnityEngine;
using Random = System.Random;
using System;
using System.Numerics;
using UnityEngine.AI;
using UnityEngine.Experimental.AI;
using Quaternion = UnityEngine.Quaternion;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
public class RoadGenerator : MonoBehaviour
{
[SerializeField]
private Terrain _terrain;
[SerializeField]
private GameObject _spawnarea;
private double _iswidth;
private Vector3 _startPointBezier;
private Vector3 _endPointBezier;
private Random _rnd = new Random();
private Vector3[] _points = new Vector3[11];
private Vector3[] _tangents = new Vector3[20];
private List<Vector3[]> _bp = new List<Vector3[]>();
public void Start()
{
_iswidth = _rnd.NextDouble();
if (_iswidth >= 0.5)
{
_startPointBezier = new Vector3(0, 0, _rnd.Next(_terrain.terrainData.detailHeight * 2));
_endPointBezier = new Vector3(_terrain.terrainData.detailWidth * 2, 0, _rnd.Next((int)_startPointBezier.z, _terrain.terrainData.detailHeight * 2));
for (int i = 1; i < _points.Length - 1; i++)
{
_points[i] = new Vector3((float)(_terrain.terrainData.detailWidth * 2) / 10 * i, 0, _rnd.Next((int)_startPointBezier.z, (int)_endPointBezier.z));
}
_points[0] = _startPointBezier;
_points[_points.Length - 1] = _endPointBezier;
for (int i = 1; i < _tangents.Length - 1; i = i + 2)
{
if (_points[(i - 1) / 2].z < _points[(i + 1) / 2].z)
_tangents[i] =
new Vector3(
_rnd.Next((int)_points[(i - 1) / 2].x,
(int) (_points[(i - 1) / 2].x + (_points[(i + 1) / 2].x - _points[(i - 1) / 2].x) / 2)), 0,
_rnd.Next((int)_points[(i - 1) / 2].z, (int)_points[(i + 1) / 2].z));
else
_tangents[i] =
new Vector3(
_rnd.Next((int)_points[(i - 1) / 2].x,
(int)(_points[(i - 1) / 2].x + (_points[(i + 1) / 2].x - _points[(i - 1) / 2].x) / 2)), 0,
_rnd.Next((int)_points[(i + 1) / 2].z, (int)_points[(i - 1) / 2].z));
_tangents[i + 1] = new Vector3(
_points[(i + 1) / 2].x + (_points[(i + 1) / 2].x - _tangents[i].x), 0,
_points[(i + 1) / 2].z + (_points[(i + 1) / 2].z - _tangents[i].z));
}
_tangents[0] = new Vector3(
_rnd.Next((int)_points[0].x, (int)_points[1].x), 0,
_rnd.Next((int)_startPointBezier.z, (int)_endPointBezier.z));
_tangents[_tangents.Length - 1] = new Vector3(
_rnd.Next((int)_points[_points.Length - 2].x, (int)_endPointBezier.x), 0,
_rnd.Next((int)_startPointBezier.z, (int)_endPointBezier.z));
}
else
{
_startPointBezier = new Vector3(_rnd.Next(_terrain.terrainData.detailWidth * 2), 0, 0);
_endPointBezier = new Vector3(_rnd.Next((int)_startPointBezier.x, _terrain.terrainData.detailWidth * 2), 0, _terrain.terrainData.detailHeight * 2);
for (int i = 1; i < _points.Length - 1; i++)
{
_points[i] = new Vector3(_rnd.Next((int)_startPointBezier.x, (int)_endPointBezier.x), 0, (float)(_terrain.terrainData.detailHeight * 2) / 10 * i);
}
_points[0] = _startPointBezier;
_points[_points.Length - 1] = _endPointBezier;
for (int i = 1; i < _tangents.Length - 1; i = i + 2)
{
if (_points[(i - 1) / 2].x < _points[(i + 1) / 2].x)
_tangents[i] = new Vector3(_rnd.Next((int)_points[(i - 1) / 2].x, (int)_points[(i + 1) / 2].x), 0,
_rnd.Next((int)_points[(i - 1) / 2].z,
(int) (_points[(i - 1) / 2].z + (_points[(i + 1) / 2].z - _points[(i - 1) / 2].z) / 2)));
else
_tangents[i] =
new Vector3(
_rnd.Next((int)_points[(i + 1) / 2].x, (int)_points[(i - 1) / 2].x), 0,
_rnd.Next((int)_points[(i - 1) / 2].z,
(int) (_points[(i - 1) / 2].z + (_points[(i + 1) / 2].z - _points[(i - 1) / 2].z) / 2)));
_tangents[i + 1] = new Vector3(
_points[(i + 1) / 2].x + (_points[(i + 1) / 2].x - _tangents[i].x), 0,
_points[(i + 1) / 2].z + (_points[(i + 1) / 2].z - _tangents[i].z));
}
_tangents[0] = new Vector3(
_rnd.Next((int)_startPointBezier.x, (int)_endPointBezier.x), 0,
_rnd.Next((int)_points[0].z, (int)_points[1].z));
_tangents[_tangents.Length - 1] = new Vector3(
_rnd.Next((int)_startPointBezier.x, (int)_endPointBezier.x), 0,
_rnd.Next((int)_points[_points.Length - 2].z, (int)_endPointBezier.z));
}
Instantiate(_spawnarea, _endPointBezier, Quaternion.identity);
Instantiate(_spawnarea, _startPointBezier, Quaternion.identity);
_bp.Add(new Vector3[] {});
for (int i = 0; i < _points.Length - 1; i++)
{
_bp.Add(MakeBezierPoints(_points[i], _points[i + 1], _tangents[(i * 2)], _tangents[(i * 2) + 1]));
}
_bp[0] = new Vector3[] { (_bp[1][0] + (_bp[1][0] - _bp[1][1]) * 300), _startPointBezier};
_bp.Add(new Vector3[] { _endPointBezier,
(_bp[_points.Length - 1][_bp[_points.Length - 1].Length - 1] +
_bp[_points.Length - 1][_bp[_points.Length - 1].Length - 1] -
_bp[_points.Length - 1][_bp[_points.Length - 1].Length - 2]) * 300 });
CombineInstance[] comb = new CombineInstance[_bp.Count];
GetComponent<MeshFilter>().mesh = new Mesh();
for (int i = 0; i < _bp.Count - 1; i++)
{
comb[i].mesh = GenerateMesh(_bp[i], i + 1);
comb[i].transform = GetComponent<MeshFilter>().transform.localToWorldMatrix;
}
GetComponent<MeshFilter>().mesh.CombineMeshes(comb);
GetComponent<MeshFilter>().mesh.RecalculateNormals();
GetComponent<MeshFilter>().mesh.RecalculateBounds();
}
private Vector3[] MakeBezierPoints(Vector3 p1, Vector3 p2, Vector3 t1, Vector3 t2)
{
Vector3[] vec = new Vector3[_terrain.terrainData.detailWidth * 2 / (_points.Length - 1) + 1];
for (int i = 0; i <= _terrain.terrainData.detailWidth * 2 / (_points.Length - 1); i++)
{
float t = (float)i / (_terrain.terrainData.detailWidth * 2 / (_points.Length - 1));
vec[i] = (float)Math.Pow((1 - t), 3) * p1 + 3 * t * (float)Math.Pow((1 - t), 2) * t1 + 3 * (float)Math.Pow(t, 2) * (1 - t) * t2 + (float)Math.Pow(t, 3) * p2;
}
return vec;
}
private Mesh GenerateMesh(Vector3[] bp, int k)
{
Mesh mesh = new Mesh();
Vector3[] newbp = new Vector3[bp.Length * 4];
int <img src="./images/smilies/unmarked.gif" alt="[]" title="Запланировано" /> triangles = new int[bp.Length * 24];
Vector2[] uv = new Vector2[newbp.Length];
for (int i = 0; i < bp.Length; i++)
{
Vector3 vector;
if (i == bp.Length - 1)
vector = new Vector3(-(_bp[k][1].z - bp[i].z), _bp[k][1].y - bp[i].y, _bp[k][1].x - bp[i].x).normalized;
else
vector = new Vector3(-(bp[i + 1].z - bp[i].z), bp[i + 1].y - bp[i].y, bp[i + 1].x - bp[i].x).normalized;
newbp[i * 4] = new Vector3(vector.x * -6f, vector.y + 0.2f, vector.z * -6f) + bp[i];
newbp[i * 4 + 1] = new Vector3(vector.x * -6f, vector.y - 0.2f, vector.z * -6f) + bp[i];
newbp[i * 4 + 2] = new Vector3(vector.x * 6f, vector.y - 0.2f, vector.z * 6f) + bp[i];
newbp[i * 4 + 3] = new Vector3(vector.x * 6f, vector.y + 0.2f, vector.z * 6f) + bp[i];
if (i < bp.Length - 1)
for (int j = 0; j < 4; j++)
{
triangles[i * 24 + j * 6] = i * 4 + j;
triangles[i * 24 + j * 6 + 1] = (i + 1) * 4 + j;
if (j == 3)
{
triangles[i * 24 + j * 6 + 2] = (i + 1) * 4 + 1 + j - 4;
triangles[i * 24 + j * 6 + 3] = (i + 1) * 4 + 1 + j - 4;
triangles[i * 24 + j * 6 + 4] = i * 4 + 1 + j - 4;
}
else
{
triangles[i * 24 + j * 6 + 2] = (i + 1) * 4 + 1 + j;
triangles[i * 24 + j * 6 + 3] = (i + 1) * 4 + 1 + j;
triangles[i * 24 + j * 6 + 4] = i * 4 + 1 + j;
}
triangles[i * 24 + j * 6 + 5] = i * 4 + j;
}
}
for (int i = 0; i < uv.Length; i++)
{
uv[i] = new Vector2(newbp[i].x, newbp[i].z);
}
Vector3[] normals = new Vector3[newbp.Length];
for (int i = 0; i < bp.Length - 1; i++)
{
normals[i * 4] = Vector3.Cross((newbp[i * 4 + 1] - newbp[i * 4]), (newbp[i * 4 + 3] - newbp[i * 4])).normalized;
normals[i * 4 + 1] = Vector3.Cross((newbp[i * 4] - newbp[i * 4 + 1]), (newbp[i * 4 + 2] - newbp[i * 4 + 1])).normalized;
normals[i * 4 + 2] = Vector3.Cross((newbp[i * 4 + 1] - newbp[i * 4 + 2]), (newbp[i * 4 + 3] - newbp[i * 4 + 2])).normalized;
normals[i * 4 + 3] = Vector3.Cross((newbp[i * 4] - newbp[i * 4 + 3]), (newbp[i * 4 + 2] - newbp[i * 4 + 3])).normalized;
}
mesh.vertices = newbp;
mesh.uv = uv;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
}