您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
240 行
5.5 KiB
240 行
5.5 KiB
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
using Random = UnityEngine.Random;
|
|
using System.Linq;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace BoatAttack
|
|
{
|
|
[Serializable]
|
|
public class WaypointGroup : MonoBehaviour
|
|
{
|
|
static WaypointGroup Instance = null;
|
|
public static float raceDelay = 4f;
|
|
|
|
public int WaypointGroupID = 0;
|
|
public Color WaypointColour = Color.yellow;
|
|
public bool Loop = false;
|
|
public float NextWPradius = 5f;
|
|
|
|
public bool raceStarted = false;
|
|
|
|
[NonSerialized]
|
|
public bool reverse = false;
|
|
|
|
[NonSerialized]
|
|
public Matrix4x4[] startingPositons = new Matrix4x4[4];
|
|
|
|
[SerializeField] public List<Waypoint> WPs = new List<Waypoint>();
|
|
private int curWpID;
|
|
|
|
public static WaypointGroup instance => Instance;
|
|
|
|
// Use this for initialization
|
|
void Awake()
|
|
{
|
|
Instance = this;
|
|
}
|
|
|
|
public void Setup()
|
|
{
|
|
if (reverse)
|
|
{
|
|
WPs.Reverse();
|
|
WPs.Insert(0, WPs[WPs.Count - 1]);
|
|
WPs.RemoveAt(WPs.Count - 1);
|
|
}
|
|
|
|
GetStartPositions();
|
|
}
|
|
|
|
[Serializable]
|
|
public class Waypoint
|
|
{
|
|
public Vector3 point;
|
|
[FormerlySerializedAs("WPradius")] public float WPwidth;
|
|
public Quaternion rotation = Quaternion.identity;
|
|
public int WPnumber;
|
|
public int WPgroup;
|
|
|
|
public Waypoint(Vector3 position, float radius, int ID, int group)
|
|
{
|
|
|
|
point = position;
|
|
WPwidth = radius;
|
|
WPnumber = ID;
|
|
WPgroup = group;
|
|
}
|
|
}
|
|
|
|
|
|
public void CreateWaypoint()
|
|
{
|
|
Vector3 Pos = gameObject.transform.position;
|
|
float Rad = NextWPradius;
|
|
int ID = curWpID;
|
|
|
|
Waypoint WP = new Waypoint(Pos, Rad, ID, WaypointGroupID);
|
|
|
|
WPs.Add(WP);
|
|
|
|
curWpID++;
|
|
}
|
|
|
|
public Vector3 GetWaypointDestination(int index)
|
|
{
|
|
Waypoint wp;
|
|
if (index > 0 && index < WPs.Count - 1)
|
|
wp = WPs[index];
|
|
else
|
|
wp = null;
|
|
return wp.point + (Random.insideUnitSphere * wp.WPwidth);
|
|
}
|
|
|
|
public Waypoint GetWaypoint(int index)
|
|
{
|
|
return WPs[index];
|
|
}
|
|
|
|
public Waypoint GetNextWaypoint(Waypoint wp)
|
|
{
|
|
var index = WPs.IndexOf(wp);
|
|
index = (int)Mathf.Repeat(index + 1, WPs.Count);
|
|
return GetWaypoint(index);
|
|
}
|
|
|
|
public Waypoint GetClosestWaypoint(Vector3 point)
|
|
{
|
|
Waypoint closest = null;
|
|
Waypoint[] sortedWPs = WPs.OrderBy(wp => Vector3.Distance(point, wp.point)).ToArray();
|
|
|
|
if (sortedWPs[0].WPnumber < sortedWPs[1].WPnumber && !reverse)
|
|
closest = sortedWPs[1];
|
|
else
|
|
closest = sortedWPs[0];
|
|
|
|
return closest;
|
|
}
|
|
|
|
public Matrix4x4 GetClosestPointOnWaypoint(Vector3 point)
|
|
{
|
|
Vector3 respawnPoint = Vector3.zero;
|
|
Waypoint wpA;
|
|
Waypoint wpB;
|
|
Waypoint[] sortedWPs = WPs.OrderBy(wp => Vector3.Distance(point, wp.point)).ToArray();
|
|
|
|
wpA = sortedWPs[0];
|
|
wpB = sortedWPs[1];
|
|
|
|
if (Mathf.Abs(wpA.WPnumber - wpB.WPnumber) > 1)
|
|
wpB = WPs[(int)Mathf.Repeat(wpA.WPnumber + 2, WPs.Count)];
|
|
|
|
var closetToLine = FindNearestPointOnLine(new Vector2(wpA.point.x, wpA.point.z),
|
|
new Vector2(wpB.point.x, wpB.point.z),
|
|
new Vector2(point.x, point.z));
|
|
|
|
var lookVec = Vector3.forward;
|
|
if (wpA.WPnumber > wpB.WPnumber)
|
|
{
|
|
lookVec = wpA.point - wpB.point;
|
|
}
|
|
else
|
|
{
|
|
lookVec = wpB.point - wpA.point;
|
|
}
|
|
|
|
if ((wpA.WPnumber == 0 && wpB.WPnumber == WPs.Count - 1) || (wpB.WPnumber == 0 && wpA.WPnumber == WPs.Count - 1)) // if at the loop point we need to revese the lookVec
|
|
lookVec = -lookVec;
|
|
|
|
Quaternion facing = Quaternion.LookRotation(Vector3.Normalize(lookVec * (reverse ? -1f : 1f)), Vector3.up);
|
|
|
|
respawnPoint.x = closetToLine.x;
|
|
respawnPoint.z = closetToLine.y;
|
|
|
|
Matrix4x4 matrix = Matrix4x4.TRS(respawnPoint, facing, Vector3.one);
|
|
|
|
return matrix;
|
|
}
|
|
|
|
public Matrix4x4[] GetStartPositions()
|
|
{
|
|
var position = WPs[0].point + Vector3.up;
|
|
var rotation = WPs[0].rotation;
|
|
if(reverse)
|
|
rotation *= Quaternion.AngleAxis(180f, Vector3.up);
|
|
|
|
for (int i = 0; i < startingPositons.Length; i++)
|
|
{
|
|
var pos = new Vector3(i % 2 == 0 ? 3f : -3f, 0f, i * 6f + 4f);
|
|
pos.z = -pos.z;
|
|
|
|
startingPositons[i].SetTRS(position, rotation, Vector3.one);
|
|
startingPositons[i] *= Matrix4x4.Translate(pos);
|
|
}
|
|
|
|
return startingPositons;
|
|
}
|
|
|
|
public void DeleteLastWaypoint()
|
|
{
|
|
WPs.RemoveAt(curWpID);
|
|
curWpID--;
|
|
}
|
|
|
|
public void DeleteAllWaypoints()
|
|
{
|
|
WPs.Clear();
|
|
curWpID = 0;
|
|
}
|
|
|
|
public Vector2 FindNearestPointOnLine(Vector2 origin, Vector2 end, Vector2 point)
|
|
{
|
|
//Get heading
|
|
Vector2 heading = (end - origin);
|
|
float magnitudeMax = heading.magnitude;
|
|
heading.Normalize();
|
|
|
|
//Do projection from the point but clamp it
|
|
Vector2 lhs = point - origin;
|
|
float dotP = Vector2.Dot(lhs, heading);
|
|
dotP = Mathf.Clamp(dotP, 0f, magnitudeMax);
|
|
return origin + heading * dotP;
|
|
}
|
|
|
|
void OnDrawGizmos()
|
|
{
|
|
var c = WaypointColour;
|
|
|
|
for (int i = 0; i < WPs.Count; i++)
|
|
{
|
|
Gizmos.matrix = Matrix4x4.TRS(WPs[i].point, WPs[i].rotation, Vector3.one);
|
|
var cube = new Vector3(WPs[i].WPwidth * 2f, 4f, 0.5f);
|
|
// Fill
|
|
c.a = 0.5f;
|
|
Gizmos.color = c;
|
|
Gizmos.DrawCube(Vector3.zero, cube);
|
|
// Outline
|
|
c.a = 1f;
|
|
Gizmos.color = c;
|
|
Gizmos.DrawWireCube(Vector3.zero, cube);
|
|
}
|
|
|
|
startingPositons = GetStartPositions();
|
|
|
|
c = Color.green;
|
|
var startBox = new Vector3(2f, 0.1f, 6f);
|
|
foreach (var startPos in startingPositons)
|
|
{
|
|
Gizmos.matrix = startPos;
|
|
c.a = 0.5f;
|
|
Gizmos.color = c;
|
|
Gizmos.DrawCube(Vector3.zero, startBox);
|
|
c.a = 1f;
|
|
Gizmos.color = c;
|
|
Gizmos.DrawWireCube(Vector3.zero, startBox);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|