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 riderObjects = new Dictionary(); private readonly Dictionary randomizedStartOffsets = new Dictionary(); private readonly List collisionList = new List(); 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 ArRiders => (IReadOnlyDictionary)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)((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); } }