void Start() { Rd = Road.Instance; AdjustedTurninXSec = Road.Instance.XSecs[0]; _playerGPS = DrivingPlayManager.Current.PlayerCarManager.Gps; _rb = GetComponent <Rigidbody>(); }
public static XSec CalcXSecPerp(int PathId, int RoadWidth) { XSec rtn = new XSec(PathId); BezierLine Bez = BezierLine.Instance; Vector3 Path3d; if (PathId == Bez.Path.Count) { Path3d = Bez.CtrlPts[Bez.CtrlPts.Count - 2].Pos; } else { Path3d = Bez.Path[PathId]; } Vector2 Path2d = Convert2d(Path3d); Vector2 Perp1 = Perpndclr(PathId); Vector2 KerbR2d = Path2d + Perp1 * RoadWidth; Vector2 KerbL2d = Path2d - Perp1 * RoadWidth; Vector3 KerbR = new Vector3(KerbR2d.x, Path3d.y, KerbR2d.y); Vector3 KerbL = new Vector3(KerbL2d.x, Path3d.y, KerbL2d.y); rtn.TerrainL = (KerbL - Path3d) * 1.3f + Path3d; //Here's where ther terrain is slightly wider than the road rtn.TerrainR = (KerbR - Path3d) * 1.3f + Path3d; //Here's where ther terrain is slightly wider than the road rtn.KerbL = KerbL; rtn.KerbR = KerbR; rtn.MidPt = Path3d; return(rtn); }
public void Encode(XSec X) { Idx = X.Idx; KerbL = new Vector3Serial(X.KerbL); KerbR = new Vector3Serial(X.KerbR); TerrainL = new Vector3Serial(X.TerrainL); TerrainR = new Vector3Serial(X.TerrainR); MidPt = new Vector3Serial(X.MidPt); }
public void AddXSecs(int segCount) { XSecs = new List <XSec>(); for (int i = 0; i < segCount; i++) { XSec X = new XSec(Road.Instance.XSecs.Count); Road.Instance.XSecs.Add(X); //this.XSecs.Add(X); } }
public XSec Decode() { XSec rtn = new XSec(Idx); rtn.KerbL = KerbL.V3; rtn.KerbR = KerbR.V3; rtn.TerrainL = TerrainL.V3; rtn.TerrainR = TerrainR.V3; rtn.MidPt = MidPt.V3; return(rtn); }
void CalcBrakePoint() { //Accel coeffs a,b,c Brake Coeffs f,g,h float a, b, c, f, g, h; float St = _nextBend.Speed; float DistToTurnin = Vector3.Distance(transform.position, AdjustedTurninPt); switch (_gps.RoadMat) { case "Dirt": a = 0.125f; b = 0f; break; case "DirtyRoad": a = 0.2764f; b = -2.4993f; break; case "Washboard": a = 0.1606f; b = -1.0945f; break; case "Tarmac": a = 0.1070f; b = -0.2337f; break; default: a = 0.3236f; b = -2.1428f; break; } switch (Rd.Segments[_nextBend.TurninSegIdx].roadMaterial) { case "Dirt": f = -0.0832f; g = 0f; break; case "DirtyRoad": f = -0.05432f; g = -0.1585f; break; case "Washboard": f = -0.04990f; g = -0.2070f; break; case "Tarmac": f = -0.04776f; g = -0.2191f; break; default: f = -0.08367f; g = 0.02521f; break; } float _adjSpeed = _nextBend.Speed * SpeedAdj; c = -a * _speed * _speed - b * _speed; h = DistToTurnin - f * _adjSpeed * _adjSpeed - g * _adjSpeed; //Sl is the liftoff speed LiftOffSpeed = (-(b - g) + Mathf.Sqrt((b - g) * (b - g) - 4 * (a - f) * (c - h))) / (2 * (a - f)); //Dl is the liftoff dist DistToBrakePt = a * LiftOffSpeed * LiftOffSpeed + b * LiftOffSpeed + c; if (DistToBrakePt < DistToTurnin) { //Enough time to accelerate before braking int SegsToBrakePt = Mathf.RoundToInt(DistToBrakePt * Rd.XSecs.Diff(_currXSec, AdjustedTurninXSec) / DistToTurnin); BrakeXSec = Rd.XSecs[_currXSec.Idx + SegsToBrakePt]; TurnInSpeed = _adjSpeed; } else //going too slow. No need to brake { DistToBrakePt = DistToTurnin; TurnInSpeed = Mathf.Sqrt(_speed * _speed + 2 * a * DistToTurnin); BrakeXSec = AdjustedTurninXSec; } }
public XSec XSecPlusOne(XSec XS) { int Idx = XS.Idx + 1; if (Idx == _XSecs.Count) { return(_XSecs[0]); } else { return(_XSecs[Idx]); } }
public void Init(bool LerpToStart) { if (_replayer.State == "Playing" || _replayer.State == "PlayingSloMo") { FutureFrame = Recrdng.Current.CurrFrame + 200; EndFrame = FutureFrame + 50; } if (_replayer.State == "Rewind" || _replayer.State == "Reverse") { FutureFrame = Recrdng.Current.CurrFrame - 200; EndFrame = FutureFrame - 50; } FutureFrame = Mathf.Clamp(FutureFrame, 0, Recrdng.Current.FrameCount - 1); EndFrame = Mathf.Clamp(EndFrame, 0, Recrdng.Current.FrameCount - 1); List <RecFrameData> FrameData = Recrdng.Current.Data[FutureFrame]; CamStartPos = FrameData[Recrdng.Current.PlayerCarId].Pos; Ray _r = new Ray(CamStartPos + Vector3.up * 0.2f, Vector3.down); int LayerMask = ~((1 << 8) + (1 << 10) + (1 << 13)); RaycastHit hit; if (Physics.Raycast(_r, out hit, 2, LayerMask)) { if (hit.collider.name.StartsWith("Road")) { XSec xs = Road.Instance.XSecs[System.Convert.ToInt16(hit.collider.name.Substring(7))]; if (Vector3.Distance(CamStartPos, xs.KerbR) > Vector3.Distance(CamStartPos, xs.KerbL)) { CamEndPos = CamStartPos + (xs.MidLeft - CamStartPos).normalized * 2f + Vector3.up * 0.2f; CamStartPos = xs.KerbR + Vector3.up * 0.2f; } else { CamEndPos = CamStartPos + (xs.MidRight - CamStartPos).normalized * 2f + Vector3.up * 0.2f; CamStartPos = xs.KerbL + Vector3.up * 0.2f; } } else { CamEndPos = CamStartPos + Vector3.right * 2; } } else { CamEndPos = CamStartPos + Vector3.right * 2; } }
private void AnalyseTurnin() { return; int Adj = Mathf.RoundToInt(Mathf.Abs(RacelineAnglePerSeg) * 5 - 5); // for hairpins, shift the turnin earlier so it doesnt hit the fence switch (Rd.Segments[TurninSegIdx].roadMaterial) { case "Tarmac": Adj = Mathf.RoundToInt(Mathf.Abs(RacelineAnglePerSeg) * 5 - 5); break; case "Washboard": Adj = Mathf.RoundToInt(Mathf.Abs(RacelineAnglePerSeg) * 5 - 5); break; case "DirtyRoad": Adj = Mathf.RoundToInt(Mathf.Abs(RacelineAnglePerSeg) * 5 - 5); break; case "Dirt": Adj = Mathf.RoundToInt(Mathf.Abs(RacelineAnglePerSeg) * 5 - 7); break; } TurninXSec = Rd.XSecs[TurninSegIdx - Adj]; TurninSegIdx = TurninXSec.Idx; }
private void PopulateXSecCurrBends() { foreach (Bend _bend in Bends) { //These two saved a massive performance hit Bend _nb = Bends.Next(_bend); for (XSec x = _bend.TurninXSec; x != _bend.ExitXSec; x = XSecs.Next(x)) { x.CurrBend = _bend; } if (_nb.TurninXSec == null) { Debug.Log("BendId" + _bend.BendId + " no turnin"); } else { for (XSec x = _bend.TurninXSec; x != _nb.TurninXSec; x = XSecs.Next(x)) { x.NextBend = _nb; } } } }
/// <summary> /// Calculates the Kerb positions for the segments leading up to the controlpoint /// <para>Ascertains if its possible first so it never crashes</para> /// </summary> public static void CalcXSecs(int CtrlPtIdx, int RoadWidth, bool FrstHlf = true, bool SecndHlf = true) { BezierLine Bez = BezierLine.Instance; Road Rd = Road.Instance; //If this is Idx1 then calculate the last visible one if (CtrlPtIdx == 1 && Rd.IsCircular) { CtrlPtIdx = Bez.CtrlPts.Count - 2; } //if (CtrlPtIdx == Bez.CtrlPts.Count-1 && Rd.IsCircular) CtrlPtIdx = 1; //doesnt work if (CtrlPtIdx < 2) { return; } if (CtrlPtIdx > Bez.CtrlPts.Count - 2) { return; } int CP1XId = Bez.CtrlPts[CtrlPtIdx - 2].SegStartIdx; int CP2XId = Bez.CtrlPts[CtrlPtIdx - 1].SegStartIdx; int CP3XId = Bez.CtrlPts[CtrlPtIdx].SegStartIdx; int CP4XId = Bez.CtrlPts[CtrlPtIdx + 1].SegStartIdx; if (Bez.CtrlPts[CtrlPtIdx - 1].SegCount == 0) { CP2XId = CP3XId; } if (Bez.CtrlPts[CtrlPtIdx - 2].SegCount == 0) { CP1XId = CP2XId; } if (Rd.IsCircular && CP2XId == Rd.XSecs.Count) { CP2XId = Bez.CtrlPts[2].SegStartIdx; CP3XId = Bez.CtrlPts[2].SegStartIdx; CP4XId = Bez.CtrlPts[3].SegStartIdx; } //because of the overlap if (Rd.IsCircular && CP3XId == Rd.XSecs.Count) { CP3XId = Bez.CtrlPts[1].SegStartIdx; CP4XId = Bez.CtrlPts[2].SegStartIdx; } //because of the overlap if (Rd.IsCircular && CtrlPtIdx == 2) { CP1XId = Bez.CtrlPts[Rd.Sectns.Count - 2].SegStartIdx; } //if (Bez.CtrlPts[CtrlPtIdx + 1].SegCount == 0) CP4XId = CP3XId; XSec XSec1 = CalcXSecPerp(CP1XId, RoadWidth); XSec XSec2 = CalcXSecPerp(CP2XId, RoadWidth); XSec XSec3 = CalcXSecPerp(CP3XId, RoadWidth); XSec XSec4 = CalcXSecPerp(CP4XId, RoadWidth); Vector3 RKerb1; Vector3 RKerb2; Vector3 RKerb3; Vector3 RKerb4; Vector3 LKerb1; Vector3 LKerb2; Vector3 LKerb3; Vector3 LKerb4; RKerb1 = XSec1.KerbR; RKerb2 = XSec2.KerbR; RKerb3 = XSec3.KerbR; RKerb4 = XSec4.KerbR; LKerb1 = XSec1.KerbL; LKerb2 = XSec2.KerbL; LKerb3 = XSec3.KerbL; LKerb4 = XSec4.KerbL; //this worked on the flat road. Now we have to bank the road Vector3 _bankDirection; try { //This will fail at some point if you are moving a cone at the end - its OK tho _bankDirection = (Bez.PathPlusOne(CP1XId) - Bez.Path[CP1XId]).normalized * Bez.CtrlPts[CtrlPtIdx - 2].BankAngle; if (Bez.CtrlPts[CtrlPtIdx - 2].BankAngle < 0) { LKerb1 = VectGeom.RotatePointAroundPivot(LKerb1, Bez.Path[CP1XId], _bankDirection); } else { RKerb1 = VectGeom.RotatePointAroundPivot(RKerb1, Bez.Path[CP1XId], _bankDirection); } _bankDirection = (Bez.PathPlusOne(CP2XId) - Bez.Path[CP2XId]).normalized * Bez.CtrlPts[CtrlPtIdx - 1].BankAngle; if (Bez.CtrlPts[CtrlPtIdx - 1].BankAngle < 0) { LKerb2 = VectGeom.RotatePointAroundPivot(LKerb2, Bez.Path[CP2XId], _bankDirection); } else { RKerb2 = VectGeom.RotatePointAroundPivot(RKerb2, Bez.Path[CP2XId], _bankDirection); } _bankDirection = (Bez.PathPlusOne(CP3XId) - Bez.Path[CP3XId]).normalized * Bez.CtrlPts[CtrlPtIdx].BankAngle; if (Bez.CtrlPts[CtrlPtIdx].BankAngle < 0) { LKerb3 = VectGeom.RotatePointAroundPivot(LKerb3, Bez.Path[CP3XId], _bankDirection); } else { RKerb3 = VectGeom.RotatePointAroundPivot(RKerb3, Bez.Path[CP3XId], _bankDirection); } _bankDirection = (Bez.PathPlusOne(CP4XId) - Bez.Path[CP4XId]).normalized * Bez.CtrlPts[CtrlPtIdx + 1].BankAngle; if (Bez.CtrlPts[CtrlPtIdx + 1].BankAngle < 0) { LKerb4 = VectGeom.RotatePointAroundPivot(LKerb4, Bez.Path[CP4XId], _bankDirection); } else { RKerb4 = VectGeom.RotatePointAroundPivot(RKerb4, Bez.Path[CP4XId], _bankDirection); } } catch (System.Exception e) { Debug.Log(e.ToString()); } int NumXSecsToAdjust; //Catmull Rom up to the control pt //RIGHT KERB try { NumXSecsToAdjust = Bez.CtrlPts[CtrlPtIdx - 1].SegCount; } catch (System.Exception e) { NumXSecsToAdjust = 0; } int AdjustStartIdx = CP2XId; Vector3 a = RKerb1; Vector3 b = RKerb2; Vector3 c = RKerb3; Vector3 d = RKerb4; float t = 0.5f; //if (Vector3.Angle(c - b, d - c) > 135 || Vector3.Angle(b - a, c - b) > 135) t = 2.5f; for (int p = 0; p < NumXSecsToAdjust; p++) { float u = (float)p / NumXSecsToAdjust; //Coeffs for the catmullrom equation Vector3 c0 = b; Vector3 c1 = -t * a + t * c; Vector3 c2 = 2f * t * a + (t - 3f) * b + (3f - 2f * t) * c - t * d; Vector3 c3 = -t * a + (2f - t) * b + (t - 2f) * c + t * d; Vector3 temp = c0 + c1 * u + c2 * u * u + c3 * u * u * u; //Vector3 temp = .5f * ((-a + 3f * b - 3f * c + d) * (u * u * u) + (2f * a - 5f * b + 4f * c - d) * (u * u) + (-a + c) * u + 2f * b); Vector3 newKerb = temp; //PlaceMarker(temp); Rd.XSecs[AdjustStartIdx + p].KerbR = temp; } //Catmull Rom up to the control pt //LEFT KERB a = LKerb1; b = LKerb2; c = LKerb3; d = LKerb4; //if (Vector3.Angle(c - b, d - c) > 135 || Vector3.Angle(b - a, c - b) > 135) t = 2.5f; for (int p = 0; p < NumXSecsToAdjust; p++) { float u = (float)p / NumXSecsToAdjust; //Coeffs for the catmullrom equation Vector3 c0 = b; Vector3 c1 = -t * a + t * c; Vector3 c2 = 2f * t * a + (t - 3f) * b + (3f - 2f * t) * c - t * d; Vector3 c3 = -t * a + (2f - t) * b + (t - 2f) * c + t * d; Vector3 temp = c0 + c1 * u + c2 * u * u + c3 * u * u * u; //Vector3 temp = .5f * ((-a + 3f * b - 3f * c + d) * (u * u * u) + (2f * a - 5f * b + 4f * c - d) * (u * u) + (-a + c) * u + 2f * b); Vector3 newKerb = temp; //PlaceMarker(temp); Rd.XSecs[AdjustStartIdx + p].KerbL = temp; Rd.XSecs[AdjustStartIdx + p].TerrainL = (Rd.XSecs[AdjustStartIdx + p].KerbL - Bez.Path[AdjustStartIdx + p]) * 1.3f + Bez.Path[AdjustStartIdx + p]; Rd.XSecs[AdjustStartIdx + p].TerrainR = (Rd.XSecs[AdjustStartIdx + p].KerbR - Bez.Path[AdjustStartIdx + p]) * 1.3f + Bez.Path[AdjustStartIdx + p]; Rd.XSecs[AdjustStartIdx + p].MidPt = (Rd.XSecs[AdjustStartIdx + p].KerbL + Rd.XSecs[AdjustStartIdx + p].KerbR) / 2; Rd.XSecs[AdjustStartIdx + p].MidPt = new Vector3(Rd.XSecs[AdjustStartIdx + p].MidPt.x, Bez.Path[AdjustStartIdx + p].y, Rd.XSecs[AdjustStartIdx + p].MidPt.z); } }
void Update() { if (CR_Running) { return; } if (Timer == 0) { Timer = 10; } Timer--; if (Timer != 0) { return; } Accel = 0.9f; BrakeForce = 0; Steer = 0; SegIdx = _gps.CurrSegIdx; _currXSec = _gps.CurrXSec; _nextBend = _gps.NextBend; _currBend = _gps.CurrBend; bool FirstHalfOfBend = _currBend != null && _currXSec.IsBefore(_currBend.ApexXSec); //Vector3 B = Road.Instance.Segments[SegIdx].verts[4]; Vector3 SegFwdDir = Road.Instance.XSecs[SegIdx].Forward; Vector3 Heading = transform.forward; HeadingAngle = Vector3.Angle(Heading, SegFwdDir); Vector3 cross = Vector3.Cross(Heading, SegFwdDir); if (cross.y > 0) { HeadingAngle = -HeadingAngle; } //Postition across the cross sec Vector3 L = Road.Instance.XSecs[SegIdx].KerbL; Vector3 R = Road.Instance.XSecs[SegIdx].KerbR; float DistFromLKerb = Vector3.Distance(L, transform.position); float DistFromRKerb = Vector3.Distance(R, transform.position); //Calculate entry speed for next bend float _entrySpeed = Mathf.Abs(50 / _nextBend.AnglePerSeg); //Coming into a sharp bend too fast slow down if (_gps.SegsPerSec - _entrySpeed > (_nextBend.StartSegIdx > _gps.CurrSegIdx?_nextBend.StartSegIdx - _gps.CurrSegIdx: _nextBend.StartSegIdx + Rd.Segments.Count - _gps.CurrSegIdx)) { Accel = 0; BrakeForce = 1f; } else { Accel = 1; BrakeForce = 0; } //Aim for the middle of the 10th segment in front XSec AimSec = Road.Instance.XSecCircular(SegIdx + 20); Vector3 AimPoint = AimSec.MidPt; if (FirstHalfOfBend) { if (_currBend.AnglePerSeg > 1) { if (_currBend.Type == BendType.Left) { AimPoint = AimSec.MidLeft; } if (_currBend.Type == BendType.Right) { AimPoint = AimSec.MidRight; } } } Vector3 LongAimPoint = Road.Instance.XSecCircular(SegIdx + 40).MidPt; //steer round the car in front Vector3 FrontOfCar = transform.position + transform.up * 0.5f + transform.forward * 2.5f; _collisionRay = new Ray(FrontOfCar, AimPoint + Vector3.up - FrontOfCar); int layerMask = (1 << 8); if (Physics.Raycast(_collisionRay, out CollisionHit, 50, layerMask)) { if (CollisionHit.collider.name != this.name) { if (CollisionHit.rigidbody.velocity.sqrMagnitude < 1) { StartCoroutine(ThreePointTurn("R")); } else { AimPoint = (Road.Instance.XSecCircular(SegIdx + 10).MidPt + Road.Instance.XSecCircular(SegIdx + 10).KerbR) / 2; } } } //Debug.DrawRay(FrontOfCar, AimPoint + Vector3.up - FrontOfCar, Color.red); //*********************************************************************************** //Steer towards the aim point float DesiredHeadingAngle = Vector3.Angle(AimPoint - transform.position, SegFwdDir); Vector3 crossDes = Vector3.Cross(AimPoint - transform.position, SegFwdDir); if (crossDes.y > 0) { DesiredHeadingAngle = -DesiredHeadingAngle; } // Pointing towards kerb - do a 3 point turn if (HeadingAngle > -100 && HeadingAngle < -80 && DistFromLKerb < 3) { StartCoroutine(ThreePointTurn("L")); return; } if (HeadingAngle < 100 && HeadingAngle > 80 && DistFromRKerb < 3) { StartCoroutine(ThreePointTurn("R")); return; } //Coming up to a hill, put your foot down if (LongAimPoint.y - SegFwdDir.y > 0) { Accel = ((LongAimPoint.y - SegFwdDir.y) * 0.005f) + 0.9f; } //coming up to a hill bend slow down if (Mathf.Abs(_nextBend.Angle) > 10 && _gps.NextHill > 2 && _gps.Speed > 10) { Accel = 0; BrakeForce = 0.5f; } //Positive steer = right Steer = (DesiredHeadingAngle - HeadingAngle); //Start of bend - flick the wheel //copied from CarAIInput /* * //Slide the Adjusted turnin point along the gate * SlideFrac = Mathf.Sqrt(Mathf.Clamp01(TurnInSpeed / _nextBend.Speed)); // - Mathf.Abs(Mathf.Sin(DriftAngle)) * 1.5f); //SlideFrac=1 for a big swingout * //Debug.Log("SlideFrac=" + TurnInSpeed + "/" + _nextBend.Speed + "=" + SlideFrac); * AdjustedTurninPt = Vector3.Lerp(_nextBend.MinTurninPos, _nextBend.TurninPos, SlideFrac); * AdjustedTurninXSec = Rd.XSecs[Mathf.RoundToInt(Mathf.Lerp(_nextBend.StartSegIdx, _nextBend.TurninSegIdx, SlideFrac))]; */ if (_opponentCollisionDirec == CollisionDirection.Left && Steer < 10) { Steer = 10; } if (_opponentCollisionDirec == CollisionDirection.Right && Steer > -10) { Steer = -10; } }
internal void CalcTurnin() { //GameObject goCirc; //CapsuleCollider Circ; //goCirc = GameObject.CreatePrimitive(PrimitiveType.Cube); //goCirc.GetComponent<BoxCollider>().enabled = false; //Circ = goCirc.AddComponent<CapsuleCollider>(); //goCirc.name = "CircColl" + BendId; //Circ.height = 100; Radius = SqrtRad * SqrtRad; Vector3 Centre = new Vector3(0, 0, 0); Vector3 C = new Vector3(0, 0, 0); Vector3 AP = VectGeom.Convert2d(ApexPos); Vector3 TP = new Vector3(0, 0, 0); Vector3 EP = new Vector3(0, 0, 0); int e = 0; float ExitFrac = 1;//1 is a wide turn, 0 is tight float SmallestRadErr = 1000; PossBendCircle bbc = new PossBendCircle(); Vector3 ApexPos2d = VectGeom.Convert2d(ApexPos); float NxtBndDist = Rd.XSecs.Diff(ApexXSec, NextBend.ApexXSec); //Method: //Try a range of turnin segs //For each Turnin seg, draw a line perpendicular to the fwd direction //and find the turninPt (TP) //Find the midpoint (MP) of the line from apex to turninPoint and draw a line perpendicular to this (MPerp) //Where MPerp crosses TPerp is the centre of the circle, C /// <image url="$(SolutionDir)\CommonImages\CalcTurninAlgorithm.png" scale="1.2"/> if (Type == BendType.Right) { if (NextBend.Type == BendType.Left && NxtBndDist < 200) { ExitFrac = NxtBndDist / 200; } for (XSec tx = Rd.XSecs[StartSegIdx - 70]; tx.IsBefore(Rd.XSecs[StartSegIdx]); tx = Rd.XSecs.Next(tx)) //removed circlebug { Vector2 TPerp = VectGeom.Convert2d(Vector3.Cross(Vector3.up, tx.Forward)); TP = VectGeom.Convert2d(tx.KerbL + (tx.KerbR - tx.KerbL).normalized * TurninGap); Vector2 MP = (ApexPos2d + TP) / 2; Vector2 MPerp = new Vector2((ApexPos2d - TP).y, -(ApexPos2d - TP).x); if (VectGeom.LineLineIntersection(out C, TP, TPerp, MP, MPerp)) //these vars are all Vector3(x,0,y) { float biggestCos = 0; float R = Vector2.Distance(TP, C); PossBendCircle pbc = new PossBendCircle(); float RadErr = 1000; for (e = EndXSec.Idx + 70; e > EndXSec.Idx; e--) //bugbugbug circlebug { Vector2 WideExitPt = VectGeom.Convert2d(Rd.XSecs[e].KerbL + (Rd.XSecs[e].KerbR - Rd.XSecs[e].KerbL).normalized * 2); Vector2 TightExitPoint = VectGeom.Convert2d(Rd.XSecs[e].KerbR + (Rd.XSecs[e].KerbL - Rd.XSecs[e].KerbR).normalized * 2); EP = Vector2.Lerp(TightExitPoint, WideExitPt, ExitFrac); Vector3 EPerp = VectGeom.Convert2d(-Rd.XSecs[e].Right).normalized; float cos = Mathf.Abs(Vector2.Dot((EP - C).normalized, EPerp)); if (cos > biggestCos) { RadErr = Mathf.Abs(Vector3.Distance(EP, C) - R); pbc = new PossBendCircle { C = C, RSq = 0, RadErr = RadErr, EP = EP, EX = Rd.XSecs[e], TP = TP, TX = tx }; biggestCos = cos; } } if (RadErr < SmallestRadErr) { bbc = new PossBendCircle { C = pbc.C, RSq = 0, RadErr = pbc.RadErr, EP = pbc.EP, EX = pbc.EX, TP = pbc.TP, TX = pbc.TX }; SmallestRadErr = pbc.RadErr; } } } Centre = new Vector3(bbc.C.x, ApexPos.y, bbc.C.y); Radius = Vector2.Distance(bbc.TP, bbc.C); TurninXSec = bbc.TX; TurninSegIdx = TurninXSec.Idx; TurninPos = new Vector3(bbc.TP.x, ApexPos.y, bbc.TP.y); ExitXSec = bbc.EX; ExitPos = new Vector3(bbc.EP.x, ApexPos.y, bbc.EP.y); goto FoundCentre; //Not found Centre Debug.Log("No Centre for Bend" + BendId); ExitXSec = Rd.XSecs[e]; Debug.Break(); } if (Type == BendType.Left) { if (NextBend.Type == BendType.Right && NxtBndDist < 200) { ExitFrac = NxtBndDist / 200; } for (int t = StartSegIdx - 70; t < StartSegIdx; t++) //bugbugbug circlebug { Vector2 TPerp = VectGeom.Convert2d(Vector3.Cross(Vector3.up, Rd.XSecs[t].Forward)); TP = VectGeom.Convert2d(Rd.XSecs[t].KerbR + (Rd.XSecs[t].KerbL - Rd.XSecs[t].KerbR).normalized * TurninGap); Vector2 MP = (ApexPos2d + TP) / 2; Vector2 MPerp = new Vector2((ApexPos2d - TP).y, -(ApexPos2d - TP).x); if (VectGeom.LineLineIntersection(out C, TP, TPerp, MP, MPerp)) //these vars are all Vector3(x,0,y) { float biggestCos = 0; float R = Vector2.Distance(TP, C); PossBendCircle pbc = new PossBendCircle(); float RadErr = 1000; for (e = EndXSec.Idx + 70; e > EndXSec.Idx; e--) //bugbugbug circlebug { Vector2 WideExitPt = VectGeom.Convert2d(Rd.XSecs[e].KerbR + (Rd.XSecs[e].KerbL - Rd.XSecs[e].KerbR).normalized * 2); Vector2 TightExitPoint = VectGeom.Convert2d(Rd.XSecs[e].KerbL + (Rd.XSecs[e].KerbR - Rd.XSecs[e].KerbL).normalized * 2); EP = Vector2.Lerp(TightExitPoint, WideExitPt, ExitFrac); Vector3 EPerp = VectGeom.Convert2d(Rd.XSecs[e].Right).normalized; float cos = Mathf.Abs(Vector2.Dot((EP - C).normalized, EPerp)); if (cos > biggestCos) { RadErr = Mathf.Abs(Vector3.Distance(EP, C) - R); pbc = new PossBendCircle { C = C, RSq = 0, RadErr = RadErr, EP = EP, EX = Rd.XSecs[e], TP = TP, TX = Rd.XSecs[t] }; biggestCos = cos; } } if (RadErr < SmallestRadErr) { bbc = new PossBendCircle { C = pbc.C, RSq = 0, RadErr = pbc.RadErr, EP = pbc.EP, EX = pbc.EX, TP = pbc.TP, TX = pbc.TX }; SmallestRadErr = pbc.RadErr; } } } Centre = new Vector3(bbc.C.x, ApexPos.y, bbc.C.y); Radius = Vector2.Distance(bbc.TP, bbc.C); TurninXSec = bbc.TX; TurninSegIdx = TurninXSec.Idx; TurninPos = new Vector3(bbc.TP.x, ApexPos.y, bbc.TP.y); ExitXSec = bbc.EX; ExitPos = new Vector3(bbc.EP.x, ApexPos.y, bbc.EP.y); goto FoundCentre; //Not found Centre Debug.Log("No Centre for Bend" + BendId); ExitXSec = Rd.XSecs[e]; Debug.Break(); } FoundCentre: //goCirc.transform.position = Centre; //Circ.radius = Radius; Angle = VectGeom.SignedAngle(TurninXSec.Forward, ExitXSec.Forward); float RacelineSegCount = Rd.XSecs.Diff(TurninXSec, ExitXSec);; RacelineAnglePerSeg = Angle / RacelineSegCount; RacelineSegLength = Angle * Mathf.Deg2Rad * Radius / RacelineSegCount; CalculateSpeed(); //Circ.enabled = false; //cos the gameobject doesnt get destroyed till end of frame //GameObject.Destroy(goCirc); return; NoTurnin: if (TurninXSec == null) { TurninXSec = Rd.XSecs[ApexSegIdx - 50]; TurninSegIdx = TurninXSec.Idx; ExitXSec = Rd.XSecs[ApexSegIdx + (ApexSegIdx - TurninSegIdx)]; if (Type == BendType.Right) { TurninPos = TurninXSec.KerbL + (TurninXSec.KerbR - TurninXSec.KerbL).normalized * 4f; } else { TurninPos = TurninXSec.KerbR + (TurninXSec.KerbL - TurninXSec.KerbR).normalized * 4f; } Radius = 100; AnalyseTurnin(); CalculateSpeed(); } //Circ.enabled = false; //cos the gameobject doesnt get destroyed till end of frame //GameObject.Destroy(goCirc); }
public void UpdateSegIdx() { //raycast to see which segment is underneath us if (Physics.Raycast(_goVehicle.transform.position + Vector3.up * 3 + _goVehicle.transform.forward, Vector3.down, out hit, 8, layerMask)) { RaycastHitPos = hit.point; if (hit.collider.name.Contains("Seg")) { CurrSegIdx = System.Convert.ToInt16(hit.collider.name.Substring(7)); CurrXSec = Rd.XSecs[CurrSegIdx]; CurrBend = CurrXSec.CurrBend; RoadMat = Rd.Segments[CurrSegIdx].roadMaterial; IsOnRoad = true; } else { IsOnRoad = false; } } else { IsOnRoad = false; } //Calculate How long to change segments if (PrevSegIdx != CurrSegIdx) { _segsPerSec = (CurrSegIdx - PrevSegIdx) / (Time.time - SegTime); SegTime = Time.time; } PrevSegIdx = CurrSegIdx; if (Time.time - SegTime > 5 && Player == true && RecoveryAllowed) { //SHOW THE RECOVERY PANEL RecoveryAllowed = false; MusicPlayer.Instance.StepDown(); Transform canv = GameObject.FindObjectOfType <Canvas>().transform; GameObject pnlRecover = (GameObject)GameObject.Instantiate(Resources.Load("Prefabs/pnlRecover"), canv); //pnlRecover.transform.localScale = Vector3.one; //pnlRecover.GetComponent<RectTransform>().anchoredPosition = Vector2.up; //pnlRecover.GetComponent<RectTransform>().offsetMin = new Vector2(0, 350); //pnlRecover.GetComponent<RectTransform>().offsetMax = Vector2.zero; pnlRecover.GetComponent <RecoverPanel>().Init(this, _goVehicle, CurrSegIdx); } //See if we are in the air - raycast to see if there is anything at all below us by one metre if (Physics.Raycast(_goVehicle.transform.position + Vector3.up + _goVehicle.transform.forward, Vector3.down, out hit, 2, airLayerMask)) { if (IsInAir) { Land(); } IsInAir = false; if (hit.collider.name.Contains("Terrain")) { RoadMat = "Dirt"; } } else { if (!IsInAir) { TakeOff(); } IsInAir = true; } if (JustLanded) { AirRecoveryTimer++; Vector3 RoadVector = Road.Instance.XSecs[CurrSegIdx].Forward; Vector3 VehVector = _goVehicle.transform.forward; float Angl = Vector3.Angle(RoadVector, VehVector); float DiffAngl = Angl - PrevAngle; if (AirRecoveryTimer > 30 && Angl < 20 && DiffAngl > -30 && DiffAngl < 30) { Recovery(); JustLanded = false; } PrevAngle = Angl; } //Drift measurement if (IsOnRoad && _rb.velocity.sqrMagnitude > 0.2f) { float _driftAngle = Vector3.Angle(_goVehicle.transform.forward, _rb.velocity); if (_drifting && _driftAngle > 90) { DriftFail(); } if (_driftAngle > 20 && !IsInAir) { Vector3 SegFwd = Rd.XSecs[CurrSegIdx].Forward; int _segIdxPlusOne = CurrSegIdx + 1; if (_segIdxPlusOne > Rd.Segments.Count - 1) { _segIdxPlusOne = _segIdxPlusOne - Rd.Segments.Count; } Vector3 SegPlusOneFwd = Rd.XSecs[_segIdxPlusOne].Forward; Vector3 cross = Vector3.Cross(SegPlusOneFwd, SegFwd); Vector3 vehcross = Vector3.Cross(_goVehicle.transform.forward, _rb.velocity); if (Mathf.Sign(vehcross.y) == Mathf.Sign(cross.y)) // { Debug.Log("OK"); } else { Debug.Log("Fail"); } { if (!_drifting) { Drift(); } } else { if (_drifting) { EndDrift(); } } } else if (_drifting) { EndDrift(); } } else if (_drifting) { DriftFail(); } /* * if (_drifting) * { * _driftRecoveryTimer++; * Vector3 RoadVector = Road.Instance.XSecs[SegIdx].Forward; * Vector3 VehVector = _goVehicle.transform.forward; * float Angl = Vector3.Angle(RoadVector, VehVector); * float DiffAngl = Angl - PrevAngle; * * if (_driftRecoveryTimer > 100 && Angl < 10 && DiffAngl > 0 && DiffAngl < 10) * { * DriftRecovery(); * _drifting = false; * } * PrevAngle = Angl; * } */ }
public void Decode() { Road Rd = Road.Instance; Rd.Segments.Clear(); Rd.XSecs.Clear(); Rd.Sectns.Clear(); if (XSecs == null) { //in case we are loading a blank track Rd.Init(); } else { Rd.StartingLineSegIdx = StartingLineSegIdx; if (BuilderPos != null) { Rd.BuilderPos = BuilderPos.V3; } else { Rd.BuilderPos = new Vector3(0, 50f, 0); } if (BuilderRot != null) { Rd.BuilderRot = BuilderRot.Decode; } Rd.IsCircular = IsCircular; foreach (XSecSerial XS in XSecs) { XSec X = XS.Decode(); Rd.XSecs.Add(X); } foreach (RoadSectionSerial RSS in Sectns) { RoadSectn RS = RSS.Decode(); Rd.Sectns.Add(RS); } foreach (RoadSegmentSerial SegS in Segs) { RoadSegment Seg = SegS.Decode(); Rd.Segments.Add(Seg); } //Build the meshes for all the segments for (int Idx = 0; Idx < Segs.Length; Idx++) { RoadSegment seg = Road.Instance.Segments[Idx]; if (seg.HasMesh) { SegVerts Verts = XSecCalculator.SegmentVertices(Idx); seg.BuildMeshes(Verts); } //seg.GetTerrainHeights(); //seg.AdjustTerrain(); //seg.SetMaterial(); //seg.DeleteFence(); //seg.CreateFence(); } Rd.CalculateBends(); } }
public static void AdjustHairpin(BezierLine Bez, int CtlPtIdx) { return; if (CtlPtIdx < 2) { return; } //Adjusts the Road.Instance.XSecs around the controlpoint string Hand; Road Rd = Road.Instance; //SegAdj=new List<SegVerts>(); Vector2 PivotStart2d = Vector2.zero; Vector2 PivotEnd2d = Vector2.zero; int PrevCtrlPtSegId = Bez.CtrlPts[CtlPtIdx - 1].SegStartIdx; int PivotStartIdx = Bez.CtrlPts[CtlPtIdx].SegStartIdx; int PivotEndIdx = Bez.CtrlPts[CtlPtIdx].SegStartIdx; int NxtCtrlPtSegId = Bez.CtrlPts[CtlPtIdx + 1].SegStartIdx; if (CtlPtIdx < 2) { return; } //See if its a right or a left hand curve Vector2 Path2d = Convert2d(Rd.XSecs[PivotStartIdx].MidPt); Vector2 PrvPath2d = Convert2d(Rd.XSecs[PivotStartIdx - 1].MidPt); Vector2 NxtPath2d = Convert2d(Rd.XSecs[PivotStartIdx + 1].MidPt); Vector3 cross = Vector3.Cross(PrvPath2d - Path2d, NxtPath2d - Path2d); if (cross.z > 0) { Hand = "R"; } else { Hand = "L"; } //Right Edge if (Hand == "R") { //Catmull Rom up to the control pt int NumXSecsToAdjust = Bez.CtrlPts[CtlPtIdx - 1].SegCount / 2; int AdjustStartIdx = (PrevCtrlPtSegId + PivotStartIdx) / 2; Vector3 a = Rd.XSecs[PrevCtrlPtSegId].KerbR; Vector3 b = Rd.XSecs[(PrevCtrlPtSegId + PivotStartIdx) / 2].KerbR; Vector3 c = Rd.XSecs[PivotStartIdx].KerbR; Vector3 d = Rd.XSecs[(PivotStartIdx + NxtCtrlPtSegId) / 2].KerbR; c = new Vector3(c.x, (b.y + d.y) / 2, c.z); float t = 0.5f; //if (Vector3.Angle(c - b, d - c) > 135 || Vector3.Angle(b - a, c - b) > 135) t = 2.5f; for (int p = 0; p < NumXSecsToAdjust; p++) { float u = (float)p / NumXSecsToAdjust; //Coeffs for the catmullrom equation Vector3 c0 = b; Vector3 c1 = -t * a + t * c; Vector3 c2 = 2f * t * a + (t - 3f) * b + (3f - 2f * t) * c - t * d; Vector3 c3 = -t * a + (2f - t) * b + (t - 2f) * c + t * d; Vector3 temp = c0 + c1 * u + c2 * u * u + c3 * u * u * u; //Vector3 temp = .5f * ((-a + 3f * b - 3f * c + d) * (u * u * u) + (2f * a - 5f * b + 4f * c - d) * (u * u) + (-a + c) * u + 2f * b); Vector3 newKerb = temp; XSec X = new XSec((CtlPtIdx - 1) * 20 - 10 + p); X.KerbR = temp - Rd.XSecs[AdjustStartIdx + p].KerbR; Road.Instance.XSecs[AdjustStartIdx + p].Adjust(X); } //Catmull ROm after the control point NumXSecsToAdjust = Bez.CtrlPts[CtlPtIdx].SegCount / 2; AdjustStartIdx = (PivotStartIdx) / 2; a = b; b = c; c = d; d = Rd.XSecs[NxtCtrlPtSegId].KerbR; //if (Vector3.Angle(c - b, d - c) > 135 || Vector3.Angle(b - a, c - b) > 135) t = 2.5f; for (int p = 0; p < NumXSecsToAdjust; p++) { float u = (float)p / NumXSecsToAdjust; //Coeffs for the catmullrom equation Vector3 c0 = b; Vector3 c1 = -t * a + t * c; Vector3 c2 = 2f * t * a + (t - 3f) * b + (3f - 2f * t) * c - t * d; Vector3 c3 = -t * a + (2f - t) * b + (t - 2f) * c + t * d; Vector3 temp = c0 + c1 * u + c2 * u * u + c3 * u * u * u; //Vector3 temp = .5f * ((-a + 3f * b - 3f * c + d) * (u * u * u) + (2f * a - 5f * b + 4f * c - d) * (u * u) + (-a + c) * u + 2f * b); Vector3 newKerb = temp; XSec X = new XSec((CtlPtIdx - 1) * 20 + p); X.KerbR = temp - Rd.XSecs[AdjustStartIdx + p].KerbR; Road.Instance.XSecs[AdjustStartIdx + p].Adjust(X); } } if (Hand == "L") { for (int Idx1 = (CtlPtIdx - 2) * 20 + 1; Idx1 < (CtlPtIdx - 1) * 20 - 1; Idx1++) { for (int Idx2 = (CtlPtIdx) * 20 - 1; Idx2 > (CtlPtIdx - 1) * 20; Idx2--) { Vector2 PrevKerb12d = Convert2d(XSecCalculator.CalcXSecPerp(Idx1 - 1, 8).KerbL); Vector2 PrevKerb22d = Convert2d(XSecCalculator.CalcXSecPerp(Idx2 - 1, 8).KerbL); Vector2 Kerb12d = Convert2d(XSecCalculator.CalcXSecPerp(Idx1, 8).KerbL); Vector2 Kerb22d = Convert2d(XSecCalculator.CalcXSecPerp(Idx2, 8).KerbL); if (VectGeom.LinesIntersect2d(PrevKerb12d, Kerb12d, PrevKerb22d, Kerb22d)) { //We've found the crossing point // where Hand = "L"; //Take 2 steps back cos the curve would be too tight PivotStartIdx = Idx1 - 2; PivotEndIdx = Idx2 + 1; PivotStart2d = Convert2d(Road.Instance.XSecs[PivotStartIdx].KerbL); PivotEnd2d = Convert2d(Road.Instance.XSecs[PivotEndIdx].KerbL); //Now move the closest pivot back so its the same distance from the control point //Which is the closest? Vector2 CtrlPt2d = Convert2d(Bez.CtrlPts[CtlPtIdx].Pos); float DistS = Vector2.Distance(PivotStart2d, CtrlPt2d); float DistE = Vector2.Distance(PivotEnd2d, CtrlPt2d); PlaceMarker(CtrlPt2d); if (DistS > DistE) { //Debug.Log("ClosestPivotIdx = PivotEndIdx"); PivotEnd2d = Vector2.Lerp(CtrlPt2d, PivotEnd2d, DistS / DistE); Rd.XSecs[PivotEndIdx].KerbL = new Vector3(PivotEnd2d.x, 0, PivotEnd2d.y); //Todo1 } else { //Debug.Log("ClosestPivotIdx = PivotStartIdx"); PivotStart2d = CtrlPt2d + (PivotStart2d - CtrlPt2d) * DistE / DistS; Rd.XSecs[PivotStartIdx].KerbL = new Vector3(PivotStart2d.x, 0, PivotStart2d.y); //Todo1 } PlaceMarker(PivotStart2d); PlaceMarker(PivotEnd2d); } } } } if (PivotStartIdx != PivotEndIdx) { //Adjust all the right kerbs around the pivot //lets just lerp the kerb from pivotstart to pivotend //Todo: would be nice to do a catmul-rom curve around the pivot float TotLerp = (float)(PivotEndIdx - PivotStartIdx); for (int Idx = PivotStartIdx + 1; Idx < PivotEndIdx; Idx++) { float LerpFrac = (float)(Idx - PivotStartIdx) / TotLerp; Vector2 Kerb2d; if (Hand == "R") { //Todo1 Kerb2d = Vector2.Lerp(Convert2d(Road.Instance.XSecs[PivotStartIdx].KerbR), (Convert2d(Road.Instance.XSecs[PivotEndIdx].KerbR)), LerpFrac); Rd.XSecs[Idx].KerbR = new Vector3(Kerb2d.x, Bez.Path[Idx].y, Kerb2d.y); //Todo1 } else { //Todo1 Kerb2d = Vector2.Lerp(Convert2d(Road.Instance.XSecs[PivotStartIdx].KerbL), (Convert2d(Road.Instance.XSecs[PivotEndIdx].KerbL)), LerpFrac); Rd.XSecs[Idx].KerbL = new Vector3(Kerb2d.x, Bez.Path[Idx].y, Kerb2d.y); //Todo1 } } } //Even if there is no hairpin we still might have a steep inner slope //So find where the steepness starts and finishes if (PivotStartIdx == PivotEndIdx) { Vector3 K1; Vector3 K2; bool PivotStarted = false; for (int i = (CtlPtIdx - 1) * 20 - 5; i < (CtlPtIdx - 1) * 20 + 5; i++) { if (Hand == "L") { K1 = Road.Instance.XSecs[i].KerbL; K2 = Road.Instance.XSecs[i + 1].KerbL; } else { K1 = Road.Instance.XSecs[i].KerbR; K2 = Road.Instance.XSecs[i + 1].KerbR; } if ((K2.y - K1.y) / Vector2.Distance(Convert2d(K2), Convert2d(K1)) > 0.4f) { if (PivotStarted == false) { PivotStartIdx = i; PivotStarted = true; } if (PivotStarted == true) { PivotEndIdx = i; } } else { if (PivotStarted == true) { break; } } } } //Adjust the heights so we don't get steps in the road //we adjust the inner slope before and after the pivot uaing a smoothstep function int NoOfSegmentsToAdjust = Mathf.CeilToInt(Mathf.Abs((Bez.Path[PivotEndIdx].y - Bez.Path[PivotStartIdx].y) / 2)); int AdjStartIdx = PivotStartIdx - NoOfSegmentsToAdjust; if (AdjStartIdx < 0) { AdjStartIdx = 0; } int AdjEndIdx = PivotEndIdx + NoOfSegmentsToAdjust; float AdjStarty; float AdjEndy; float TotAdjDist = 0; if (Hand == "L") { AdjStarty = Road.Instance.XSecs[AdjStartIdx].KerbL.y; AdjEndy = Road.Instance.XSecs[AdjEndIdx].KerbL.y; for (int i = AdjStartIdx + 1; i <= AdjEndIdx; i++) { TotAdjDist += Vector2.Distance(Convert2d(Road.Instance.XSecs[i].KerbL), Convert2d(Road.Instance.XSecs[i - 1].KerbL)); } float delta = 0; for (int i = AdjStartIdx + 1; i <= AdjEndIdx; i++) { delta += Vector2.Distance(Convert2d(Road.Instance.XSecs[i].KerbL), Convert2d(Road.Instance.XSecs[i - 1].KerbL)); float NewY = Mathf.SmoothStep(AdjStarty, AdjEndy, delta / TotAdjDist); float AdjY = NewY - Road.Instance.XSecs[i].KerbL.y; XSec X = new XSec(i); X.KerbL = new Vector3(0, AdjY, 0); Road.Instance.XSecs[i].Adjust(X); } } if (Hand == "R") { AdjStarty = Road.Instance.XSecs[AdjStartIdx].KerbR.y; AdjEndy = Road.Instance.XSecs[AdjEndIdx].KerbR.y; for (int i = AdjStartIdx + 1; i <= AdjEndIdx; i++) { TotAdjDist += Vector2.Distance(Convert2d(Road.Instance.XSecs[i].KerbR), Convert2d(Road.Instance.XSecs[i - 1].KerbR)); } float delta = 0; for (int i = AdjStartIdx + 1; i <= AdjEndIdx; i++) { delta += Vector2.Distance(Convert2d(Road.Instance.XSecs[i].KerbR), Convert2d(Road.Instance.XSecs[i - 1].KerbR)); float NewY = Mathf.SmoothStep(AdjStarty, AdjEndy, delta / TotAdjDist); float AdjY = NewY - Road.Instance.XSecs[i].KerbR.y; XSec X = new XSec(i); X.KerbR = new Vector3(0, AdjY, 0); Road.Instance.XSecs[i].Adjust(X); } } }
void Update() { _speed = _gps.Speed; _currXSec = _gps.CurrXSec; PrevSegIdx = SegIdx; SegIdx = _currXSec.Idx; if (CR_Running) { return; } if (Timer == 0) { Timer = 5; } Timer--; if (Timer != 4) { goto DoThisEveryFrame; } //This bit only runs every 5 frames _currBend = _gps.CurrBend; _nextBend = _gps.NextBend; _gpsNextBendAngle = _nextBend.Angle; SegFwdDir = _currXSec.Forward; Vector3 Heading = transform.forward; HeadingAngle = Vector3.Angle(Heading, SegFwdDir); Vector3 cross = Vector3.Cross(Heading, SegFwdDir); if (cross.y > 0) { HeadingAngle = -HeadingAngle; } //Postition across the cross sec Vector3 L = Road.Instance.XSecs[SegIdx].KerbL; Vector3 R = Road.Instance.XSecs[SegIdx].KerbR; DistFromLKerb = Vector3.Distance(_currXSec.KerbL, transform.position); DistFromRKerb = Vector3.Distance(_currXSec.KerbR, transform.position); _bendPhase = BendPhase.Straight; int ApproachSegs = Mathf.RoundToInt(0.5f * _speed * _speed + _speed / 2); XSec _approachXSec = Rd.XSecs[SegIdx + ApproachSegs]; XSec _decisionXSec = Rd.XSecs[SegIdx + Mathf.RoundToInt(_speed * 2)]; bool FirstHalfOfBend = _currBend != null && _currXSec.IsBefore(_currBend.ApexXSec); if (!FirstHalfOfBend) { _approachBend = _nextBend; if (_approachBend.TurninXSec.IsBefore(_approachXSec)) { _bendPhase = BendPhase.Approach; SpeedAdj = 1f; DriftAngle = _approachBend.DriftAngle * Mathf.Pow(TurnInSpeed / _approachBend.Speed, 2.8f) * _approachBend.Sign; //this is cool //Slide the Adjusted turnin point along the gate SlideFrac = Mathf.Sqrt(Mathf.Clamp01(TurnInSpeed / _nextBend.Speed)); // - Mathf.Abs(Mathf.Sin(DriftAngle)) * 1.5f); //SlideFrac=1 for a big swingout //Debug.Log("SlideFrac=" + TurnInSpeed + "/" + _nextBend.Speed + "=" + SlideFrac); AdjustedTurninPt = Vector3.Lerp(_nextBend.MinTurninPos, _nextBend.TurninPos, SlideFrac); AdjustedTurninXSec = Rd.XSecs[Mathf.RoundToInt(Mathf.Lerp(_nextBend.StartSegIdx, _nextBend.TurninSegIdx, SlideFrac))]; CalcBrakePoint(); //Have we reached the decision point? We only decide the flickSegs once we reach the decision point if ((_approachBend.TurninXSec.IsBefore(_decisionXSec) && FlickXSec == null) || (FlickXSec != null && _currXSec.IsOnOrBefore(FlickXSec))) { FlickSegs = 0; ReachedFlickEnd = false; //This is the basic flickseg pre-calculation = 150/Radius*FlickSegMultiplier FlickSegs = _approachBend.FlickSegs; //Are we approaching at an angle or spinning? float FlickSegAdj = Rd.XSecs.Diff(AdjustedTurninXSec, _approachBend.ApexXSec) * (TurnInSpeed - _approachBend.Speed) / _approachBend.Speed; // (HeadingAngle + _rb.angularVelocity.y * 20) * _approachBend.FlickSegsMultiplier * -_approachBend.Sign; //if (_approachBend.Type == BendType.Right) FlickSegAdj = -FlickSegAdj; //Debug.Log("FlickSegs = " + FlickSegs + " FlickSegAdj=(" + Rd.XSecs.Diff(AdjustedTurninXSec, _approachBend.ApexXSec) + " * " + (TurnInSpeed - _approachBend.Speed) / _approachBend.Speed + " = " + FlickSegAdj + "\nTotal=" + (FlickSegs + FlickSegAdj)); FlickSegs += FlickSegAdj; //Too slow, the flick will be too harsh //Debug.Log("FlickSegs*=" + TurnInSpeed + "^2/225=" + FlickSegs); //Wrong siede of the road if (_approachBend.Type == BendType.Right ? (DistFromLKerb > DistFromRKerb) : (DistFromRKerb > DistFromLKerb)) { FlickSegs = 0; } //Is there a long curve on the turnin? //Debug.Log("TurninCurve=" + Vector3.Angle(_approachBend.StartXSec.Forward, _approachBend.TurninXSec.Forward) + "\nFlickSegs=" + FlickSegs); //RequiredRotation worked ok but didnt take into account the initial rotation //float RequiredRotation = Vector3.Angle(transform.forward, _approachBend.ApexXSec.Forward); //FlickXSec = Rd.XSecs[Mathf.RoundToInt(_approachBend.TurninSegIdx - Mathf.Abs(RequiredRotation) / 2.8f)]; FlickXSec = Rd.XSecs[AdjustedTurninXSec.Idx - Mathf.RoundToInt(FlickSegs)]; } //End of Decision if (_currXSec.IsAfter(BrakeXSec) && _currXSec.IsBefore(FlickXSec)) { _bendPhase = BendPhase.Brake; } if (FlickXSec != null && _currXSec.IsAfter(FlickXSec)) { _bendPhase = BendPhase.Turnin; } PrevFrac = SlideFrac; //used in the turnin }//end if Approach } //end if !FirstHalfOfBend else { //if FIrstHalfOfBend _approachBend = _currBend; _bendPhase = BendPhase.Turnin; } if (_currBend != null && !FirstHalfOfBend) { if (_bendPhase != BendPhase.Approach) { _bendPhase = BendPhase.Exit; FlickXSec = null; } } if (_bendPhase == BendPhase.Straight) { Vector3 _apprXSecFwd = _approachXSec.Forward; float _curveAngle = Vector3.Angle(SegFwdDir, _apprXSecFwd); if (Vector3.Cross(SegFwdDir, _apprXSecFwd).y > 0) { _curveAngle = -_curveAngle; } if (_curveAngle > 15) { _bendPhase = BendPhase.LCurve; } if (_curveAngle < -15) { _bendPhase = BendPhase.RCurve; } } //************************************************************************************************ DoThisEveryFrame: AimPoint = Rd.XSecs[SegIdx + 20].MidPt; SteerOverride = null; if (_bendPhase == BendPhase.Approach) { Accel = 1; BrakeForce = 0; float AvgApprSpeed = (_speed + LiftOffSpeed) / 2; float TimeToBrakePt = DistToBrakePt / AvgApprSpeed; //Aim for half the dist to the turnin XSec AimXSec = Rd.XSecs[_currXSec.Idx + Rd.XSecs.Diff(_currXSec, AdjustedTurninXSec) / 2]; Vector3 T = (AimXSec.KerbR - AimXSec.KerbL).normalized * _approachBend.TurninGap; if (_approachBend.Type == BendType.Right) { if (TimeToBrakePt < 1) { SlideFrac = DistFromRKerb / (DistFromLKerb + DistFromRKerb - _approachBend.TurninGap); } AimPoint = Vector3.Lerp(AimXSec.KerbR, AimXSec.KerbL + T, SlideFrac); } else { if (TimeToBrakePt < 1) { SlideFrac = DistFromLKerb / (DistFromLKerb + DistFromRKerb - _approachBend.TurninGap); } AimPoint = Vector3.Lerp(AimXSec.KerbL, AimXSec.KerbR - T, SlideFrac); } //I abandoned this because it never had time to straighten up /// <image url="$(SolutionDir)\CommonImages\SCurve.png" scale="0.7"/> } if (_bendPhase == BendPhase.Brake) { Accel = 0; BrakeForce = 1; AimPoint = (AdjustedTurninPt + transform.position + transform.forward) / 2; } int SegsToApex = 0; float diff = 0; if (_bendPhase == BendPhase.Turnin) { float TotSegsToApex = Rd.XSecs.Diff(AdjustedTurninXSec, _approachBend.ApexXSec); float SegFrac = 1 - SegsToApex / TotSegsToApex; //SegFrac starts at 0 at the turninPt and ends at 1 at the apex float TotalRequiredRotation = VectGeom.SignedAngle(AdjustedTurninXSec.Forward, _approachBend.ApexXSec.Forward) + DriftAngle; float CurrRotation = VectGeom.SignedAngle(AdjustedTurninXSec.Forward, transform.forward); float da = (Mathf.Abs(DriftAngle) < 20 && SegFrac > 0.5f) ? DriftAngle / 2 : DriftAngle; float RequiredRotation = VectGeom.SignedAngle(transform.forward, _approachBend.ApexXSec.Forward) + DriftAngle; SegsToApex = Rd.XSecs.Diff(_currXSec, _approachBend.ApexXSec); float TimeToApex = SegsToApex / _gps.SegsPerSec; float ProjectedRotation = _rb.angularVelocity.y * 57.3f * TimeToApex; float ProjectedRotation2 = CurrRotation / SegFrac; diff = ProjectedRotation - RequiredRotation; Accel = 1; BrakeForce = 0; if (_speed < 8) { AimPoint = _approachBend.Type == BendType.Right ? Rd.XSecs[SegIdx + 10].MidRight : Rd.XSecs[SegIdx + 10].MidLeft; BrakeForce = 0; } else { AimPoint = _approachBend.ApexPos; //Debug.Log("rotdiff=" + ProjectedRotation + " - " + RequiredRotation + " = " + diff); if (_approachBend.Type == BendType.Right) { /* * //Manage the Fractional Distance * if (PrevSegIdx != SegIdx) * { * FracPerSeg = (Frac - PrevFrac) / (SegIdx - PrevSegIdx); * ProjectedFrac = Frac + FracPerSeg * SegsToApex; * //Debug.Log("ProjectedFrac=" + ProjectedFrac); * PrevFrac = Frac; * } */ //Stop understeer if (diff < 0) { BrakeForce = Mathf.Clamp01(-diff / 80); Accel = 1 - BrakeForce; SteerOverride = 40; } if (diff < -40) { BrakeForce = Mathf.Clamp01(-diff / 40); Accel = 1; } if (_rb.angularVelocity.y < 0) { BrakeForce = 0; AimPoint = _approachBend.ApexPos; } //stop the backskid } if (_approachBend.Type == BendType.Left) { if (diff > 0) { BrakeForce = Mathf.Clamp01(diff / 80); Accel = 1 - BrakeForce; SteerOverride = -40; } if (diff > 40) { BrakeForce = Mathf.Clamp01(diff / 40); Accel = 1; } if (_rb.angularVelocity.y > 0) { BrakeForce = 0; AimPoint = _approachBend.ApexPos; } //stop the backskid //if (SegsToApex > 40) { BrakeForce = 0; Accel = 1; AimPoint = Rd.XSecs[SegIdx + 10].MidPt; } //Stop the serious oversteer } } } if (_bendPhase == BendPhase.Exit) { Accel = 1; Vector3 _transverse = (_currXSec.KerbR - _currXSec.KerbL).normalized; float SpeedTwdRKerb = Vector3.Dot(_rb.velocity, _transverse); //Debug.Log("SpeedTwdKerb=" + SpeedTwdRKerb); AimPoint = _currBend.ExitPos; BrakeForce = 0; if (_currBend.Type == BendType.Right) { if (Rd.XSecs.Diff(_currXSec, _currBend.ExitXSec) > 5) { AimPoint = _currBend.ExitXSec.MidRight; } } if (_currBend.Type == BendType.Left) { if (Rd.XSecs.Diff(_currXSec, _currBend.ExitXSec) > 5) { AimPoint = _currBend.ExitXSec.MidLeft; } } } XSec LongAimXSec = Rd.XSecs[SegIdx + 40]; Vector3 LongAimPoint = LongAimXSec.MidPt; if (_bendPhase == BendPhase.Straight) { Accel = 1; BrakeForce = 0; if (_nextBend == null) { Debug.Log("nbnull"); } if (_nextBend.Type == BendType.Right) { AimPoint = Rd.XSecs[SegIdx + 20].MidLeft; } else { AimPoint = Rd.XSecs[SegIdx + 20].MidRight; } } if (_bendPhase == BendPhase.RCurve) { Accel = 1; BrakeForce = 0; AimPoint = Rd.XSecs[SegIdx + 20].MidRight; } if (_bendPhase == BendPhase.LCurve) { Accel = 1; BrakeForce = 0; AimPoint = Rd.XSecs[SegIdx + 20].MidLeft; } //steer round the car in front Vector3 FrontOfCar = transform.position + transform.up * 0.5f + transform.forward * 2.5f; CollisionRay = new Ray(FrontOfCar, AimPoint + Vector3.up - FrontOfCar); int layerMask = (1 << 8); if (Physics.Raycast(CollisionRay, out CollisionHit, 50, layerMask)) { if (CollisionHit.collider.name != this.name && CollisionHit.collider.name != "ColldrF") { if (CollisionHit.rigidbody.velocity.sqrMagnitude < 1) { StartCoroutine(ThreePointTurn("R")); } else { AimPoint = Rd.XSecs[SegIdx + 10].MidRight; } } } //Debug.DrawRay(FrontOfCar, AimPoint + Vector3.up - FrontOfCar, Color.red); //************************************************************************************** //Coming up to a hill, put your foot down if (LongAimPoint.y - SegFwdDir.y > 0) { //Accel = ((LongAimPoint.y - SegFwdDir.y) * 0.005f) + 0.9f; } //coming up to a hill bend slow down if (Mathf.Abs(_gpsNextBendAngle) > 10 && _gps.NextHill > 2 && _gps.Speed > 10) { // Accel = 0; BrakeForce = 0.5f; } //*********************************************************************************** // Pointing towards kerb - do a 3 point turn if (HeadingAngle > -100 && HeadingAngle < -80 && DistFromLKerb < 3) { StartCoroutine(ThreePointTurn("L")); return; } if (HeadingAngle < 100 && HeadingAngle > 80 && DistFromRKerb < 3) { StartCoroutine(ThreePointTurn("R")); return; } if (SteerOverride == null) { //Steer towards the aim point float DesiredHeadingAngle = Vector3.Angle(AimPoint - transform.position, SegFwdDir); Vector3 crossDes = Vector3.Cross(AimPoint - transform.position, SegFwdDir); if (crossDes.y > 0) { DesiredHeadingAngle = -DesiredHeadingAngle; } //Positive steer = right Steer = (DesiredHeadingAngle - HeadingAngle); } else { Steer = (float)SteerOverride; } //if (_bendPhase == BendPhase.Flick) Steer = _gpsNextBendAngle > 0 ? 40 : -40; if (_opponentCollisionDirec == CollisionDirection.Left && Steer < 0) { Steer = 10; } if (_opponentCollisionDirec == CollisionDirection.Right && Steer > 0) { Steer = -10; } if (_playerCollision) { if (Time.time - _playerCollisionTime > 3) { if (_playerGPS.IsOnRoad) { if (!_gps.IsOnRoad) { Main.Instance.PopupMsg("Road Rage Bonus\n$20", Color.red); Race.Current.HogBonus += 20; UserDataManager.Instance.Data.Coins += 10; } else if (_playerGPS.CurrSegIdx - _gps.CurrSegIdx > 12 && _playerGPS.CurrSegIdx - _gps.CurrSegIdx < 100) { int pts = (_playerGPS.CurrSegIdx - _gps.CurrSegIdx) / 6; Race.Current.HogBonus += pts; Main.Instance.PopupMsg("Road Hog Bonus\n$" + pts.ToString(), Color.red); UserDataManager.Instance.Data.Coins += pts; } } _playerCollision = false; } } _inputBuffer.RecordInput(Accel, BrakeForce, Steer, Time.time); }
/// <summary> /// Used for ChaseCamera to stop it flying upwards /// </summary> /// <summary> /// Calculate the fence vertices after the control point /// </summary> public void CalcVisibleFenceVerts() { //This uses the XSecs to fill the two lists LFenceVerts and RFenceVerts //These are used to create the two gameobjects, LFence and RFence //The verts are always 3m apart. RaycastHit _hit; if (Segments.Count > 1) { Road Rd = Road.Instance; LFenceVerts.Clear(); RFenceVerts.Clear(); List <Vector3> LKerbs = (from x in Rd.XSecs where x.Idx >= Segments[0].Idx && x.Idx <= Segments.Last().Idx + 1 select x.KerbL).ToList <Vector3>(); if (RoadMaterial == "Air") { LKerbs = LKerbs.Select(k => Gnd(k)).ToList(); } //See I added the first xsec of the next section //if (Rd.Sectns[Idx + 1].Segments.Count==0) return; //So we don't try to calculate for the last section Vector3 CurrPos = LKerbs[0]; LFenceVerts.Add(CurrPos); int NxtKerbIdx = 1; float SegLength; float TotDist; float Bckdist; float DistRem = Vector3.Distance(CurrPos, LKerbs.Last()); while (DistRem > 3.0f) { //Find the next kerb point 3 meters along SegLength = 0; TotDist = Vector3.Distance(CurrPos, LKerbs[NxtKerbIdx]); if (TotDist > 3) { SegLength = Vector3.Distance(CurrPos, LKerbs[NxtKerbIdx]); } while (TotDist < 3) { CurrPos = LKerbs[NxtKerbIdx]; //Yeah but the air road fences should be on the ground NxtKerbIdx++; SegLength = Vector3.Distance(CurrPos, LKerbs[NxtKerbIdx]); TotDist += SegLength; } //Now we've got to the KerbPoint after the 3m mark. //We have to go backward to the 3m mark Bckdist = TotDist - 3; CurrPos = Vector3.Lerp(LKerbs[NxtKerbIdx], CurrPos, Bckdist / SegLength); LFenceVerts.Add(CurrPos); DistRem = Vector3.Distance(CurrPos, LKerbs.Last()); } //Add the first kerb point of the next section XSec LastXSec = Rd.XSecs[Segments.Last().Idx]; LFenceVerts.Add(RoadMaterial == "Air"? Gnd(Rd.XSecPlusOne(LastXSec).KerbL): Rd.XSecPlusOne(LastXSec).KerbL); //Right Kerbs List <Vector3> RKerbs = (from x in Rd.XSecs where x.Idx >= Segments[0].Idx && x.Idx <= Segments.Last().Idx + 1 //See I added the first xsec of the next section select x.KerbR).ToList <Vector3>(); if (RoadMaterial == "Air") { RKerbs = RKerbs.Select(k => Gnd(k)).ToList(); } CurrPos = RKerbs[0]; RFenceVerts.Add(CurrPos); NxtKerbIdx = 1; DistRem = Vector3.Distance(CurrPos, RKerbs.Last()); while (DistRem > 3.0f) { //Find the next kerb point 3 meters along SegLength = 0; TotDist = Vector3.Distance(CurrPos, RKerbs[NxtKerbIdx]); if (TotDist > 3) { SegLength = Vector3.Distance(CurrPos, RKerbs[NxtKerbIdx]); } while (TotDist < 3) { CurrPos = RKerbs[NxtKerbIdx]; NxtKerbIdx++; SegLength = Vector3.Distance(CurrPos, RKerbs[NxtKerbIdx]); TotDist += SegLength; } //Now we've got to the KerbPoint after the 3m mark. //We have to go backward to the 3m mark Bckdist = TotDist - 3; CurrPos = Vector3.Lerp(RKerbs[NxtKerbIdx], CurrPos, Bckdist / SegLength); RFenceVerts.Add(CurrPos); DistRem = Vector3.Distance(CurrPos, RKerbs.Last()); } RFenceVerts.Add(RoadMaterial == "Air" ? Gnd(Rd.XSecPlusOne(LastXSec).KerbR): Rd.XSecPlusOne(LastXSec).KerbR); } }
void Update() { if (CR_Running) { return; } if (Timer == 0) { Timer = 10; } Timer--; if (Timer != 0) { return; } Accel = 0.9f; BrakeForce = 0; Steer = 0; SegIdx = _gps.CurrSegIdx; _gpsNextBend = _gps.NextBend; _gpsCurrentBend = _gps.CurrBend; //Vector3 B = Road.Instance.Segments[SegIdx].verts[4]; Vector3 SegFwdDir = Road.Instance.XSecs[SegIdx].Forward; Vector3 Heading = transform.forward; HeadingAngle = Vector3.Angle(Heading, SegFwdDir); Vector3 cross = Vector3.Cross(Heading, SegFwdDir); if (cross.y > 0) { HeadingAngle = -HeadingAngle; } //Postition across the cross sec Vector3 L = Road.Instance.XSecs[SegIdx].KerbL; Vector3 R = Road.Instance.XSecs[SegIdx].KerbR; float DistFromLKerb = Vector3.Distance(L, transform.position); float DistFromRKerb = Vector3.Distance(R, transform.position); //Calculate entry speed for next bend float _entrySpeed = Mathf.Abs(50 / _gpsNextBend.AnglePerSeg); //Coming into a sharp bend too fast slow down if (_gps.SegsPerSec - _entrySpeed > (_gpsNextBend.StartSegIdx > _gps.CurrSegIdx?_gpsNextBend.StartSegIdx - _gps.CurrSegIdx: _gpsNextBend.StartSegIdx + Rd.Segments.Count - _gps.CurrSegIdx)) { Accel = 0; BrakeForce = 1f; } else { Accel = 1; BrakeForce = 0; } //Aim for the middle of the 10th segment in front XSec AimSec = Road.Instance.XSecCircular(SegIdx + 20); Vector3 AimPoint = AimSec.MidPt; Vector3 LongAimPoint = Road.Instance.XSecCircular(SegIdx + 40).MidPt; //steer round the car in front Vector3 FrontOfCar = transform.position + transform.up * 0.5f + transform.forward * 2.5f; _collisionRay = new Ray(FrontOfCar, AimPoint + Vector3.up - FrontOfCar); int layerMask = (1 << 8); if (Physics.Raycast(_collisionRay, out CollisionHit, 50, layerMask)) { if (CollisionHit.collider.name != this.name) { if (CollisionHit.rigidbody.velocity.sqrMagnitude < 1) { StartCoroutine(ThreePointTurn("R")); } else { AimPoint = (Road.Instance.XSecCircular(SegIdx + 10).MidPt + Road.Instance.XSecCircular(SegIdx + 10).KerbR) / 2; } } } //Debug.DrawRay(FrontOfCar, AimPoint + Vector3.up - FrontOfCar, Color.red); //*********************************************************************************** //Steer towards the aim point float DesiredHeadingAngle = Vector3.Angle(AimPoint - transform.position, SegFwdDir); Vector3 crossDes = Vector3.Cross(AimPoint - transform.position, SegFwdDir); if (crossDes.y > 0) { DesiredHeadingAngle = -DesiredHeadingAngle; } // Pointing towards kerb - do a 3 point turn if (HeadingAngle > -100 && HeadingAngle < -80 && DistFromLKerb < 3) { StartCoroutine(ThreePointTurn("L")); return; } if (HeadingAngle < 100 && HeadingAngle > 80 && DistFromRKerb < 3) { StartCoroutine(ThreePointTurn("R")); return; } //Coming up to a hill, put your foot down if (LongAimPoint.y - AimPoint.y > 0) { Accel = ((LongAimPoint.y - AimPoint.y) * 0.005f) + 0.9f; } //coming up to a hill bend slow down if (Mathf.Abs(_gpsNextBend.Angle) > 10 && _gps.NextHill > 2 && _gps.Speed > 10) { Accel = 0; BrakeForce = 0.5f; } //Positive steer = right Steer = (DesiredHeadingAngle - HeadingAngle) * 1.5f; //Start of bend - flick the wheel /*if ((_gpsNextBend.StartSegIdx - _gps.SegIdx) / _gps.SegsPerSec < 0.5f) * { * Steer += (1.5f * _gpsNextBend.AnglePerSeg * _gps.SegsPerSec); * } * if ((_gps.SegIdx - _gpsCurrentBend.StartSegIdx) / _gps.SegsPerSec < 5f) * { * Steer += (_gpsCurrentBend.AnglePerSeg * _gps.SegsPerSec); * }*/ if (_opponentCollisionDirec == CollisionDirection.Left && Steer < 10) { Steer = 10; } if (_opponentCollisionDirec == CollisionDirection.Right && Steer > -10) { Steer = -10; } }