2021-01-05 13:10:20 +01:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using NUnit.Framework.Constraints;
|
|
|
|
using UnityEditor.UIElements;
|
|
|
|
using UnityEngine;
|
|
|
|
using UnityEngine.Assertions;
|
2021-01-11 12:46:46 +01:00
|
|
|
using Utils;
|
2021-01-05 13:10:20 +01:00
|
|
|
using Random = UnityEngine.Random;
|
|
|
|
|
|
|
|
namespace Weapons.Spawning
|
|
|
|
{
|
|
|
|
public enum SpawnType { Circle, Square, Polygon, Composite }
|
2021-01-09 17:18:29 +01:00
|
|
|
public enum SpawnPlane { XY, XZ }
|
2021-01-05 13:10:20 +01:00
|
|
|
public enum SpawnDir { None, Randomised, Spherised, Directional}
|
2021-01-09 17:18:29 +01:00
|
|
|
|
2021-01-05 13:10:20 +01:00
|
|
|
[Serializable]
|
|
|
|
public struct SpawnZone
|
|
|
|
{
|
|
|
|
[SerializeField] private int numToSpawn;
|
2021-01-09 17:18:29 +01:00
|
|
|
[SerializeField] private Vector3 offset;
|
2021-01-05 13:10:20 +01:00
|
|
|
|
|
|
|
[SerializeField] private SpawnType spawnType;
|
|
|
|
[SerializeField] private SpawnDir spawnDir;
|
2021-01-09 17:18:29 +01:00
|
|
|
[SerializeField] private SpawnPlane spawnPlane;
|
2021-01-05 13:10:20 +01:00
|
|
|
|
|
|
|
[SerializeField] private float width;
|
|
|
|
[SerializeField] private float height;
|
|
|
|
[SerializeField] private bool surfaceOnly;
|
|
|
|
|
|
|
|
[SerializeField] private bool evenDistribution;
|
|
|
|
|
|
|
|
[SerializeField] private int numSides;
|
|
|
|
[SerializeField] private int numPerSide;
|
2021-01-09 17:18:29 +01:00
|
|
|
[SerializeField] private bool flipVertical;
|
2021-01-05 13:10:20 +01:00
|
|
|
|
2021-01-11 12:46:46 +01:00
|
|
|
[SerializeField] private ParticleSystem.MinMaxCurve radius;
|
2021-01-05 13:10:20 +01:00
|
|
|
[SerializeField, Range(0, 360)] private float arc;
|
|
|
|
|
|
|
|
[SerializeField] private SpawnZone[] composite;
|
|
|
|
|
|
|
|
public SpawnDir SpawnDir => spawnDir;
|
|
|
|
|
|
|
|
public int NumToSpawn => numToSpawn;
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
public void GetPoint(Transform transform, Action<Vector3, Vector3> onGetPoint)
|
2021-01-05 13:10:20 +01:00
|
|
|
{
|
|
|
|
switch (spawnType)
|
|
|
|
{
|
|
|
|
case SpawnType.Circle:
|
|
|
|
SpawnCircle(transform, onGetPoint);
|
|
|
|
break;
|
|
|
|
case SpawnType.Square:
|
|
|
|
SpawnSquare(transform, onGetPoint);
|
|
|
|
break;
|
|
|
|
case SpawnType.Composite:
|
|
|
|
SpawnComposite(transform, onGetPoint);
|
|
|
|
break;
|
|
|
|
case SpawnType.Polygon:
|
|
|
|
SpawnPoly(transform, onGetPoint);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
private void SpawnPoly(Transform transform, Action<Vector3, Vector3> onGetPoint)
|
2021-01-05 13:10:20 +01:00
|
|
|
{
|
|
|
|
var points = new Vector2[numSides];
|
|
|
|
for (int i = 0; i < numSides; i++)
|
|
|
|
{
|
|
|
|
var angle = (i * (arc * Mathf.Deg2Rad) / numSides) +
|
|
|
|
(90 - transform.eulerAngles.y - arc/2) * Mathf.Deg2Rad;
|
|
|
|
|
|
|
|
points[i] = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < numSides; i++)
|
|
|
|
{
|
|
|
|
var next = i + 1;
|
|
|
|
if (next == numSides)
|
|
|
|
next = 0;
|
|
|
|
|
|
|
|
var direction = Vector2.Lerp(points[i], points[next], 0.5f).normalized;
|
|
|
|
|
|
|
|
for (int j = 0; j < numPerSide; j++)
|
|
|
|
{
|
|
|
|
var t = j / (float) numPerSide;
|
|
|
|
t += (1f / numPerSide)/2f;
|
2021-01-09 17:18:29 +01:00
|
|
|
var point = Vector3.Lerp(points[i], points[next], t);
|
|
|
|
if (flipVertical)
|
|
|
|
point.y = 1 - point.y;
|
|
|
|
|
2021-01-11 12:46:46 +01:00
|
|
|
point *= radius.EvaluateMinMaxCurve();
|
2021-01-05 13:10:20 +01:00
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
if (spawnPlane == SpawnPlane.XZ)
|
|
|
|
{
|
|
|
|
point.z = point.y;
|
|
|
|
point.y = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
var dir = Vector3.up;
|
|
|
|
|
2021-01-05 13:10:20 +01:00
|
|
|
if (spawnDir == SpawnDir.Directional)
|
|
|
|
dir = direction;
|
|
|
|
else if (spawnDir == SpawnDir.Spherised)
|
|
|
|
dir = point.normalized;
|
|
|
|
else if (spawnDir == SpawnDir.Randomised)
|
|
|
|
dir = Random.insideUnitCircle.normalized;
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
if (!surfaceOnly)
|
|
|
|
point = Vector2.Lerp(point, Vector3.zero, Random.Range(0, 1f));
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-01-05 13:10:20 +01:00
|
|
|
onGetPoint?.Invoke(point, dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
private void SpawnComposite(Transform transform, Action<Vector3, Vector3> onGetPoint)
|
2021-01-05 13:10:20 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < numToSpawn; i++)
|
|
|
|
{
|
|
|
|
composite[Random.Range(0, composite.Length)].GetPoint(transform, onGetPoint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
private void SpawnCircle(Transform transform, Action<Vector3, Vector3> onGetPoint)
|
2021-01-05 13:10:20 +01:00
|
|
|
{
|
|
|
|
Assert.IsNotNull(onGetPoint);
|
|
|
|
|
|
|
|
for (int i = 0; i < numToSpawn; i++)
|
|
|
|
{
|
2021-01-09 17:18:29 +01:00
|
|
|
var point = Vector3.zero;
|
|
|
|
|
2021-01-05 13:10:20 +01:00
|
|
|
if (!evenDistribution)
|
|
|
|
{
|
|
|
|
var angle = (Random.Range(-arc / 2f, arc / 2f) + 90 - transform.eulerAngles.y) * Mathf.Deg2Rad;
|
|
|
|
|
|
|
|
point.x = Mathf.Cos(angle);
|
|
|
|
point.y = Mathf.Sin(angle);
|
|
|
|
|
|
|
|
if (!surfaceOnly)
|
|
|
|
point *= Random.Range(0, 1f);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var angle = (i * (arc * Mathf.Deg2Rad) / numToSpawn) +
|
|
|
|
(90 - transform.eulerAngles.y - arc/2) * Mathf.Deg2Rad;
|
|
|
|
|
|
|
|
point = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
|
|
|
|
|
|
|
|
if (!surfaceOnly)
|
|
|
|
point *= Random.Range(0, 1f);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
if (spawnPlane == SpawnPlane.XZ)
|
|
|
|
{
|
|
|
|
point.z = point.y;
|
|
|
|
point.y = 0;
|
|
|
|
}
|
2021-01-05 13:10:20 +01:00
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
var dir = Vector3.up;
|
2021-01-05 13:10:20 +01:00
|
|
|
if (spawnDir == SpawnDir.Spherised || spawnDir == SpawnDir.Directional)
|
|
|
|
dir = point.normalized;
|
|
|
|
else if (spawnDir == SpawnDir.Randomised)
|
|
|
|
dir = Random.insideUnitCircle.normalized;
|
|
|
|
|
|
|
|
|
2021-01-11 12:46:46 +01:00
|
|
|
onGetPoint((point * radius.EvaluateMinMaxCurve()) + offset, dir);
|
2021-01-05 13:10:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
private void SpawnSquare(Transform transform, Action<Vector3, Vector3> onGetPoint)
|
2021-01-05 13:10:20 +01:00
|
|
|
{
|
|
|
|
Assert.IsNotNull(onGetPoint);
|
|
|
|
|
|
|
|
for (int i = 0; i < numToSpawn; i++)
|
|
|
|
{
|
2021-01-09 17:18:29 +01:00
|
|
|
var point = new Vector3
|
2021-01-05 13:10:20 +01:00
|
|
|
{
|
|
|
|
x = Random.Range(-.5f, .5f),
|
|
|
|
y = Random.Range(-.5f, .5f)
|
|
|
|
};
|
|
|
|
|
|
|
|
if (surfaceOnly)
|
|
|
|
{
|
|
|
|
int axis = Random.Range(0, 2);
|
|
|
|
point[axis] = point[axis] < 0f ? -0.5f : 0.5f;
|
|
|
|
}
|
|
|
|
|
|
|
|
point.x *= width;
|
|
|
|
point.y *= height;
|
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
if (spawnPlane == SpawnPlane.XZ)
|
|
|
|
{
|
|
|
|
point.z = point.y;
|
|
|
|
point.y = 0;
|
|
|
|
}
|
2021-01-05 13:10:20 +01:00
|
|
|
|
2021-01-09 17:18:29 +01:00
|
|
|
var dir = Vector3.up;
|
2021-01-05 13:10:20 +01:00
|
|
|
if (spawnDir == SpawnDir.Spherised || spawnDir == SpawnDir.Directional)
|
|
|
|
dir = point.normalized;
|
|
|
|
else if (spawnDir == SpawnDir.Randomised)
|
|
|
|
dir = Random.insideUnitCircle.normalized;
|
|
|
|
|
|
|
|
onGetPoint(point + offset, dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void DrawGizmos(Color color, Transform transform)
|
|
|
|
{
|
|
|
|
switch (spawnType)
|
|
|
|
{
|
|
|
|
case SpawnType.Circle:
|
|
|
|
DrawGizmosCircle(color, transform);
|
|
|
|
break;
|
|
|
|
case SpawnType.Square:
|
|
|
|
DrawGizmosSquare(color, transform);
|
|
|
|
break;
|
|
|
|
case SpawnType.Composite:
|
|
|
|
DrawComposite(color, transform);
|
|
|
|
break;
|
|
|
|
case SpawnType.Polygon:
|
|
|
|
DrawGizmosPoly(color,transform);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void DrawComposite(Color color, Transform transform)
|
|
|
|
{
|
|
|
|
foreach (var zone in composite)
|
|
|
|
zone.DrawGizmos(color, transform);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void DrawGizmosCircle(Color color, Transform transform)
|
|
|
|
{
|
|
|
|
Gizmos.color = color;
|
|
|
|
SpawnCircle(transform, (point, dir) =>
|
|
|
|
{
|
2021-01-09 17:18:29 +01:00
|
|
|
Gizmos.DrawSphere( transform.position + point, 0.25f);
|
2021-01-05 13:10:20 +01:00
|
|
|
if (color.a > 0.5f)
|
2021-01-09 17:18:29 +01:00
|
|
|
Gizmos.DrawRay( transform.position + point, new Vector3(dir.x, 0, dir.y));
|
2021-01-05 13:10:20 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void DrawGizmosPoly(Color color, Transform transform)
|
|
|
|
{
|
|
|
|
Gizmos.color = color;
|
|
|
|
SpawnPoly(transform, (point, dir) =>
|
|
|
|
{
|
2021-01-09 17:18:29 +01:00
|
|
|
Gizmos.DrawSphere(transform.position + point, 0.25f);
|
2021-01-05 13:10:20 +01:00
|
|
|
if (color.a > 0.5f)
|
2021-01-09 17:18:29 +01:00
|
|
|
Gizmos.DrawRay(transform.position + point, new Vector3(dir.x, 0, dir.y));
|
2021-01-05 13:10:20 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void DrawGizmosSquare(Color color, Transform transform)
|
|
|
|
{
|
|
|
|
Gizmos.color = color;
|
|
|
|
SpawnSquare(transform, (point, dir) =>
|
|
|
|
{
|
2021-01-09 17:18:29 +01:00
|
|
|
Gizmos.DrawSphere(transform.position + point, 0.25f);
|
2021-01-05 13:10:20 +01:00
|
|
|
if (color.a > 0.5f)
|
2021-01-09 17:18:29 +01:00
|
|
|
Gizmos.DrawRay(transform.position + point, new Vector3(dir.x, 0, dir.y));
|
2021-01-05 13:10:20 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|