powerfun-unity/Assets/AR/ARLaneGameObjectsController.cs
2023-04-18 17:10:48 +08:00

259 lines
11 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()
{
var 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)
{
var num1 = cameraDistance - ARGameObject.MaxDistanceVisibilityModels;
var num2 = cameraDistance + ARGameObject.MaxDistanceVisibilityModels;
this.collisionList.Clear();
foreach (var 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;
}));
var deltaTime = Time.deltaTime;
for (int index = 0; index < this.collisionList.Count; ++index)
{
var collision = this.collisionList[index];
var lane = collision.Lane;
var 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;
var num6 = this.Route.LeftHanded ? this.GetRouteLeftOffset(collision.Frame) : this.GetRouteRightOffset(collision.Frame);
var 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)
{
var deltaTime = Time.deltaTime;
for (var index = 0; index < this.collisionList.Count; ++index)
{
var collision = this.collisionList[index];
var flag1 = collision.StartPosition == this.FollowedRiderId;
var x = Math.Abs(collision.Distance - cameraDistance);
var 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
{
var num1 = PFMath.Lerp(0.0f, 1f, x2, 0.0f, x);
var num2 = collision.Lane * collision.LaneWidth - collision.BaseOffset;
var num3 = 0.75f;
if (this.NearViewMode && !flag1)
{
num2 += num3 / 2f;
num3 *= 1.5f;
}
var flag2 = (double)collision.LaneCamera < 0.0 || (double)collision.LaneCamera <= 0.0 && (double)num2 < 0.0;
var a1 = (float)(-(double)num2 - (double)num1 * (double)num3) / collision.LaneWidth;
var a2 = (num1 * num3 - num2) / collision.LaneWidth;
if (this.NearViewMode & flag1)
{
var 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()
{
var deltaTime = Time.deltaTime;
foreach (ARLaneGameObject laneObject in this.riderObjects.Values)
{
var num1 = laneObject.Speed * deltaTime;
if ((double)num1 == 0.0)
{
laneObject.Curvature = 0.0f;
laneObject.LaneChangingDirection = 0.0f;
}
else
{
var num2 = (this.Route.LeftHanded ? -1f : 1f) * laneObject.DeltaLane * laneObject.LaneWidth * deltaTime;
if ((double)laneObject.LaneCamera != 0.0)
num2 = 0.0f;
var curvature = 0.0f;
if ((double)num1 > 0.0)
{
var 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);
var angle = -57.29578f * Mathf.Atan(num2 / num1);
this.UpdateLaneChangingDirection(laneObject, angle, deltaTime);
}
}
}
protected void UpdateRiderCurvature(ARLaneGameObject laneObject, float curvature, float deltaTime)
{
var num = 6f;
laneObject.Curvature = Mathf.Lerp(laneObject.Curvature, curvature, num * deltaTime);
}
protected void UpdateLaneChangingDirection(
ARLaneGameObject laneObject,
float angle,
float deltaTime)
{
var 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;
var overtakingThreshold = this.GetOvertakingThreshold(routeDistance);
var b = 0.0f;
for (int index = count - 1; index >= 0; --index)
{
var collision = this.collisionList[index];
if ((double)collision.Lane + 1.0 >= (double)b)
{
var 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)
{
var 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;
var 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)
{
var 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?.GetLeftSideOffset(frame) ?? 0.0f;
private float GetRouteRightOffset(float frame) => this.Route?.GetRightSideOffset(frame) ?? 0.0f;
}
}