259 lines
12 KiB
C#
259 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Assets.AR
|
|
{
|
|
public abstract class ARLaneGameObjectsController : ARGameObjectsController
|
|
{
|
|
protected const float LaneWidth = 0.7f;
|
|
protected const float StartRegionDistance = 200f;
|
|
private const float StartRowsGap = 2.2f;
|
|
private const float StartRowsRandomDistance = 0.4f;
|
|
private const float StartRowsRandomWidth = 0.15f;
|
|
private const float MinCollisionDistance = 1.33f;
|
|
protected readonly Dictionary<int, ARLaneGameObject> riderObjects = new Dictionary<int, ARLaneGameObject>();
|
|
private readonly Dictionary<int, Vector2> randomizedStartOffsets = new Dictionary<int, Vector2>();
|
|
private readonly List<ARLaneGameObject> collisionList = new List<ARLaneGameObject>();
|
|
|
|
public bool AllowStartOrder { get; set; } = true;
|
|
|
|
protected float StartRegionRouteWidth { get; private set; }
|
|
|
|
protected int RiderCountInStartRow { get; private set; }
|
|
|
|
public float OvertakingThreshold { get; set; } = 5f;
|
|
|
|
public bool NearViewMode { get; set; }
|
|
|
|
public int FollowedRiderId { get; set; }
|
|
|
|
public IReadOnlyDictionary<int, ARLaneGameObject> ArRiders => (IReadOnlyDictionary<int, ARLaneGameObject>)this.riderObjects;
|
|
|
|
protected virtual void Start()
|
|
{
|
|
float frame = 100f;
|
|
this.StartRegionRouteWidth = this.GetRouteLeftOffset(frame) + this.GetRouteRightOffset(frame);
|
|
this.RiderCountInStartRow = Mathf.Max(1, Mathf.CeilToInt(this.StartRegionRouteWidth / 0.7f));
|
|
}
|
|
|
|
protected override void UpdateGameObjects(
|
|
float videoFrame,
|
|
float visibilityRear,
|
|
float visibilityFront)
|
|
{
|
|
base.UpdateGameObjects(videoFrame, visibilityRear, visibilityFront);//控制3d物体显示隐藏
|
|
if (this.Route == null || this.videoSync == null)
|
|
return;
|
|
this.DetectRidersCollisions(this.CameraDistance);//计算3d物体的位置和转向
|
|
}
|
|
//检测碰撞
|
|
private void DetectRidersCollisions(float cameraDistance)
|
|
{
|
|
float num1 = cameraDistance - ARGameObject.MaxDistanceVisibilityModels;
|
|
float num2 = cameraDistance + ARGameObject.MaxDistanceVisibilityModels;
|
|
this.collisionList.Clear();
|
|
foreach (ARLaneGameObject arLaneObject in this.riderObjects.Values)
|
|
{
|
|
if (arLaneObject.gameObject.activeSelf && !arLaneObject.IsAtFinish)
|
|
{
|
|
if ((double)arLaneObject.Distance >= (double)num1 && (double)arLaneObject.Distance <= (double)num2)
|
|
{
|
|
this.collisionList.Add(arLaneObject);
|
|
arLaneObject.DistanceSort = arLaneObject.Distance;
|
|
}
|
|
}
|
|
}
|
|
foreach (ARLaneGameObject collision in this.collisionList)
|
|
{
|
|
if ((double)collision.RouteDistance < 200.0)
|
|
{
|
|
collision.Distance = this.GetRouteDistance(collision.StartPosition, collision.RouteDistance);
|
|
collision.DistanceSort = collision.Distance;
|
|
}
|
|
}
|
|
this.collisionList.Sort((Comparison<ARLaneGameObject>)((r1, r2) =>
|
|
{
|
|
int num3 = r1.Lane.CompareTo(r2.Lane);
|
|
if (num3 == 0)
|
|
num3 = r2.DistanceSort.CompareTo(r1.DistanceSort);
|
|
return num3;
|
|
}));
|
|
float deltaTime = Time.deltaTime;
|
|
for (int index = 0; index < this.collisionList.Count; ++index)
|
|
{
|
|
ARLaneGameObject collision = this.collisionList[index];
|
|
float lane = collision.Lane;
|
|
float num4 = this.GetLane(collision.RouteDistance, collision.DistanceSort, index);
|
|
if ((double)collision.LaneWidth != 0.0)
|
|
{
|
|
float num5 = 0.02f * deltaTime * Mathf.Log(collision.Speed + 5f, 1.1f);
|
|
num4 = Mathf.Clamp(num4, lane - num5, lane + num5 * 1.5f);
|
|
collision.DeltaLane = (num4 - lane) / deltaTime;
|
|
}
|
|
collision.Lane = num4;
|
|
}
|
|
this.CalculateOvertakingParameters();
|
|
foreach (ARLaneGameObject collision in this.collisionList)
|
|
{
|
|
collision.LaneWidth = 0.7f;
|
|
float num6 = this.Route.LeftHanded ? this.GetRouteLeftOffset(collision.Frame) : this.GetRouteRightOffset(collision.Frame);
|
|
float num7 = Mathf.Lerp(this.GetStartOffset(collision.StartPosition).x, 0.0f, collision.Distance / 200f);
|
|
collision.BaseOffset = num6 + num7;
|
|
}
|
|
this.CalculateCameraAvoidance(cameraDistance);
|
|
}
|
|
//摄像机障碍物避免
|
|
private void CalculateCameraAvoidance(float cameraDistance)
|
|
{
|
|
float deltaTime = Time.deltaTime;
|
|
for (int index = 0; index < this.collisionList.Count; ++index)
|
|
{
|
|
ARLaneGameObject collision = this.collisionList[index];
|
|
bool flag1 = collision.StartPosition == this.FollowedRiderId;
|
|
float x = Math.Abs(collision.Distance - cameraDistance);
|
|
float x2 = 4f;
|
|
if (this.NearViewMode && !flag1)
|
|
x2 = 5.5f;
|
|
if ((double)x > (double)x2)
|
|
{
|
|
if ((double)collision.LaneCamera > 0.0)
|
|
collision.LaneCamera = Mathf.Max(0.0f, collision.LaneCamera - deltaTime);
|
|
else if ((double)collision.LaneCamera < 0.0)
|
|
collision.LaneCamera = Mathf.Min(0.0f, collision.LaneCamera + deltaTime);
|
|
}
|
|
else
|
|
{
|
|
float num1 = PFMath.Lerp(0.0f, 1f, x2, 0.0f, x);
|
|
float num2 = collision.Lane * collision.LaneWidth - collision.BaseOffset;
|
|
float num3 = 0.75f;
|
|
if (this.NearViewMode && !flag1)
|
|
{
|
|
num2 += num3 / 2f;
|
|
num3 *= 1.5f;
|
|
}
|
|
bool flag2 = (double)collision.LaneCamera < 0.0 || (double)collision.LaneCamera <= 0.0 && (double)num2 < 0.0;
|
|
float a1 = (float)(-(double)num2 - (double)num1 * (double)num3) / collision.LaneWidth;
|
|
float a2 = (num1 * num3 - num2) / collision.LaneWidth;
|
|
if (this.NearViewMode & flag1)
|
|
{
|
|
float num4 = Mathf.Max(a1 - collision.LaneCamera, -deltaTime);
|
|
collision.LaneCamera = Mathf.Min(collision.LaneCamera + num4, -1.401298E-45f);
|
|
}
|
|
else
|
|
collision.LaneCamera = !flag2 ? Mathf.Max(a2, float.Epsilon) : Mathf.Min(a1, -1.401298E-45f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CalculateOvertakingParameters()
|
|
{
|
|
float deltaTime = Time.deltaTime;
|
|
foreach (ARLaneGameObject laneObject in this.riderObjects.Values)
|
|
{
|
|
float num1 = laneObject.Speed * deltaTime;
|
|
if ((double)num1 == 0.0)
|
|
{
|
|
laneObject.Curvature = 0.0f;
|
|
laneObject.LaneChangingDirection = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
float num2 = (this.Route.LeftHanded ? -1f : 1f) * laneObject.DeltaLane * laneObject.LaneWidth * deltaTime;
|
|
if ((double)laneObject.LaneCamera != 0.0)
|
|
num2 = 0.0f;
|
|
float curvature = 0.0f;
|
|
if ((double)num1 > 0.0)
|
|
{
|
|
float num3 = Mathf.Atan(num2 / num1);
|
|
curvature = (float)(0.039999999105930328 * (double)PFMath.Lerp(0.0f, 3f, 20f, 1f, laneObject.Speed)) * num3;
|
|
}
|
|
this.UpdateRiderCurvature(laneObject, curvature, deltaTime);
|
|
float angle = -57.29578f * Mathf.Atan(num2 / num1);
|
|
this.UpdateLaneChangingDirection(laneObject, angle, deltaTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void UpdateRiderCurvature(ARLaneGameObject laneObject, float curvature, float deltaTime)
|
|
{
|
|
float num = 6f;
|
|
laneObject.Curvature = Mathf.Lerp(laneObject.Curvature, curvature, num * deltaTime);
|
|
}
|
|
|
|
protected void UpdateLaneChangingDirection(
|
|
ARLaneGameObject laneObject,
|
|
float angle,
|
|
float deltaTime)
|
|
{
|
|
float num = 10f * deltaTime;
|
|
laneObject.LaneChangingDirection = Mathf.Clamp(angle, laneObject.LaneChangingDirection - num, laneObject.LaneChangingDirection + num);
|
|
}
|
|
|
|
protected float GetLane(float routeDistance, float modelDistance, int count = -1)
|
|
{
|
|
if (count == -1)
|
|
count = this.collisionList.Count;
|
|
float overtakingThreshold = this.GetOvertakingThreshold(routeDistance);
|
|
float b = 0.0f;
|
|
for (int index = count - 1; index >= 0; --index)
|
|
{
|
|
ARLaneGameObject collision = this.collisionList[index];
|
|
if ((double)collision.Lane + 1.0 >= (double)b)
|
|
{
|
|
float collisionParameter = ARLaneGameObjectsController.GetCollisionParameter(modelDistance, collision.DistanceSort, overtakingThreshold);
|
|
if ((double)collisionParameter > 0.0)
|
|
b = Mathf.Max(collision.Lane + collisionParameter, b);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
return b;
|
|
}
|
|
|
|
protected float GetOvertakingThreshold(float routeDistance)
|
|
{
|
|
float b = this.OvertakingThreshold;
|
|
if (this.AllowStartOrder && (double)routeDistance < 200.0)
|
|
b = Mathf.Lerp(1.33f, b, routeDistance / 200f);
|
|
return b;
|
|
}
|
|
|
|
private Vector2 GetStartOffset(int atIndex)
|
|
{
|
|
Vector2 startOffset;
|
|
if (this.randomizedStartOffsets.TryGetValue(atIndex, out startOffset))
|
|
return startOffset;
|
|
startOffset = new Vector2(UnityEngine.Random.Range(-0.15f, 0.15f), UnityEngine.Random.Range(-0.4f, 0.4f));
|
|
this.randomizedStartOffsets.Add(atIndex, startOffset);
|
|
return startOffset;
|
|
}
|
|
|
|
public float GetRouteDistance(int startPosition, float routeDistance)
|
|
{
|
|
if (!this.AllowStartOrder || (double)routeDistance >= 200.0)
|
|
return routeDistance;
|
|
float num = Mathf.Lerp((float)((double)(RiderCountInStartRow == 0 ? 0 :(startPosition - 1) / this.RiderCountInStartRow) * 2.2000000476837158 + 6.0) + this.GetStartOffset(startPosition).y, 0.0f, routeDistance / 200f);
|
|
return routeDistance + num;
|
|
}
|
|
|
|
//计算碰撞距离
|
|
protected static float GetCollisionParameter(
|
|
float distSource,
|
|
float distOther,
|
|
float maxDistance)
|
|
{
|
|
float x = distSource - distOther;
|
|
if ((double)x < 0.0)
|
|
x = -x;
|
|
if ((double)x < 1.0)
|
|
return 1f;
|
|
return (double)x > (double)maxDistance ? 0.0f : PFMath.SmoothStep(1f, 1f, maxDistance, 0.0f, x);
|
|
}
|
|
|
|
private float GetRouteLeftOffset(float frame) => this.Route == null ? 0.0f : this.Route.GetLeftSideOffset(frame);
|
|
|
|
private float GetRouteRightOffset(float frame) => this.Route == null ? 0.0f : this.Route.GetRightSideOffset(frame);
|
|
}
|
|
}
|