private float InterpolateY_NotUsed(Vector2 P2d) { // The two lines that cross the road (Verts.TerrainFL to Verts.TerrainFR and Verts.TerrainBL to Verts.TerrainBR are at different heights // GIven a point P2d we want to know what height it should be to fall on the plane float rtn = 0; //First make the two lines 2d Vector2 FL = new Vector2(Verts.TerrainFL.x, Verts.TerrainFL.z); Vector2 FR = new Vector2(Verts.TerrainFR.x, Verts.TerrainFR.z); Vector2 BL = new Vector2(Verts.TerrainBL.x, Verts.TerrainBL.z); Vector2 BR = new Vector2(Verts.TerrainBR.x, Verts.TerrainBR.z); Vector2 FM = new Vector2(Verts.MidPtF.x, Verts.MidPtF.z); Vector2 BM = new Vector2(Verts.MidPtB.x, Verts.MidPtB.z); //Then Measure the distance from the point onto the two lines at rightangle to the lines float Dist0 = VectGeom.DistPointToLine2D(P2d, FL, FR); float Dist1 = VectGeom.DistPointToLine2D(P2d, BL, BR); float Dist2 = VectGeom.DistPointToLine2D(P2d, BL, FL); float Dist3 = VectGeom.DistPointToLine2D(P2d, BR, FR); float yL = (Verts.TerrainBL.y - Verts.TerrainFL.y) * Dist0 / (Dist0 + Dist1) + Verts.TerrainFL.y; float yR = (Verts.TerrainBR.y - Verts.TerrainFR.y) * Dist0 / (Dist0 + Dist1) + Verts.TerrainFR.y; rtn = (yL - yR) * Dist3 / (Dist2 + Dist3) + yR; if (roadMaterial != "Dirt") { rtn = rtn - 0.12f; //Here's the bit where the terrain is slightly below the road. I'm always looking for this bit } return(rtn); }
void OnMouseDown() { MouseDown = true; _rb.Dragging = true; FPCam.transform.parent.GetComponent <BuilderCamController>().FreezeTilt = true; _startAngle = Bez.CtrlPts[Mrkr.Index].BankAngle * Mathf.Deg2Rad; Vector3 _bankDirection = AttachedTransform.forward * _startAngle; _untiltedPos = VectGeom.RotatePointAroundPivot(transform.position, OtherHandGizmo.position, -_bankDirection); Debug.Log("Start angle = " + Bez.CtrlPts[Mrkr.Index].BankAngle); Debug.Log("UntiltedPos = " + _untiltedPos); //Decide where to move the camera to... This is the nearest point perpendicular to the road and 30m from it Vector2 Perp2d = XSecCalculator.Perpndclr((AttachedTransform.GetComponent <RoadMarker>().Index - 1) * 20); Vector3 Perp = new Vector3(Perp2d.x, 0, Perp2d.y); Vector3 Dest1 = AttachedTransform.position + Perp * 30; Vector3 Dest2 = AttachedTransform.position - Perp * 30; if (Vector3.Distance(FPCam.transform.position, Dest1) < Vector3.Distance(FPCam.transform.position, Dest2)) { LerpEndPt = Dest1; } else { LerpEndPt = Dest2; } LerpStartRot = FPCam.transform.rotation; LerpStartPt = FPCam.transform.position; LerpStartTime = Time.time; Lerping = true; //Debug.Log("Lerp to " + LerpEndPt); }
public void GetTerrainHeights() { CreateTerrainMinimap(); for (int j = 0; j < _TerrainMinimap.Heights.GetLength(0); j++) { for (int k = 0; k < _TerrainMinimap.Heights.GetLength(1); k++) { Vector2 P2d = TerrainController.Instance.ConvertToWorldCoords(j + _TerrainMinimap.TerrainXBase, k + _TerrainMinimap.TerrainYBase); if (VectGeom.ContainsPoint(mesh2d, P2d)) { _TerrainMinimap.Heights[j, k] = CalcTerrainHeightUsingPlaneRaycasts(P2d); } } } /* * TerrainHeight TH = new TerrainHeight(); * TH.j = P.j; * TH.k = P.k; * Vector2 P2d = TerrainController.Instance.ConvertToWorldCoords(P.j, P.k); * TH.y = InterpolateY(P2d); * Heights.Add(TH); * //GameObject marker = GameObject.CreatePrimitive(PrimitiveType.Sphere); * //marker.transform.position = new Vector3(P2d.x, WorldHeight, P2d.y); */ }
public void ShowGizmo(string Gz) { HideAllGizmos(); if (PlayerManager.Type != "BuilderPlayer") { return; } UnityEngine.Object objGizmo = Resources.Load("Prefabs/Gizmos/Gizmo" + Gz); GameObject Gizmo = (GameObject)Object.Instantiate(objGizmo, Vector3.zero, Quaternion.identity); Gizmo.name = "Gizmo" + Gz; Gizmo.transform.SetParent(gameObject.transform); if (Gz == "Rotate" || Gz == "Scale") { Gizmo.transform.rotation = gameObject.transform.rotation; } if (Gz == "Scale") { Gizmo.transform.localScale = VectGeom.Reciprocal(gameObject.transform.localScale); } aGizmo G = Gizmo.GetComponent <aGizmo>(); G.OnGizmoMoved += G_OnGizmoMoved; G.AttachedTransform = gameObject.transform; G.AttachedObject = this; //this version puts the gizmo wherever you clicked on the collider RaycastHit Hit; FPCam = GameObject.Find("BuilderCamera").GetComponent <Camera>(); Ray R = FPCam.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(R, out Hit) && Hit.collider.transform.parent == gameObject.transform) //if clicked on this object { //put the gizmo where you clicked Gizmo.transform.position = Hit.point; } else { Collider TopC = gameObject.GetComponentsInChildren <Collider>().OrderBy(c => c.enabled == false ? -1000 : c.transform.position.y + c.bounds.max.y).LastOrDefault(); Gizmo.transform.position = TopC.transform.position + new Vector3(0, TopC.bounds.extents.y, 0); } if (Gz == "Move" || Gz == "Scale") { Gizmo.transform.position += Vector3.up * 2; } G.SetHoverPos(Gizmo.transform.position - gameObject.transform.position); }
public void RotateTop(Quaternion q) { Vector3 _eulr = q.eulerAngles; transform.rotation = Quaternion.Euler(new Vector3(0, _eulr.y, 0)); for (int n = 0; n < _verts.Length; n++) { if (_verts[n].y > _yThreshold) { _newVerts[n] = VectGeom.RotatePointAroundPivot(_verts[n], _pivotPos, q.eulerAngles * (_verts[n].y - _yThreshold) / (_maxY - _yThreshold)); _newVerts[n] = new Vector3(_verts[n].x, _newVerts[n].y, _verts[n].z); } } _mesh.vertices = _newVerts; }
public float Angle(Vector3 p0, Vector3 p1, Vector3 p2) { float rtn; Vector2 Pt0_2d = VectGeom.Convert2d(p0); Vector2 Pt1_2d = VectGeom.Convert2d(p1); Vector2 Pt2_2d = VectGeom.Convert2d(p2); rtn = Vector2.Angle(Pt0_2d - Pt1_2d, Pt2_2d - Pt1_2d); //Work out the sign of the angle b doing a cross product Vector3 cross = Vector3.Cross(Pt0_2d - Pt1_2d, Pt2_2d - Pt1_2d); if (cross.z > 0) { rtn = -rtn; } return(rtn); }
void OnMouseDrag() { if (Lerping) { return; } float MouseY = Input.mousePosition.y - _mouseOffsetY; float NewAngle; if (_hand == "L") { NewAngle = _startAngle + Mathf.Atan2(MouseY, Screen.width / 2); } else { NewAngle = _startAngle - Mathf.Atan2(MouseY, Screen.width / 2); } NewAngle = NewAngle * Mathf.Rad2Deg; //Debug.Log("New angle = " + NewAngle); Vector3 NewPos; Vector3 _bankDirection = AttachedTransform.forward * NewAngle; NewPos = VectGeom.RotatePointAroundPivot(_untiltedPos, OtherHandGizmo.position, _bankDirection); Bez.CtrlPts[Mrkr.Index].Pos = (NewPos + _otherHandStartPos) / 2; AttachedTransform.position = Bez.CtrlPts[Mrkr.Index].Pos; Bez.CtrlPts[Mrkr.Index].BankAngle = NewAngle; Bez.Interp(Mrkr.Index - 1); Bez.Interp(Mrkr.Index); Bez.Interp(Mrkr.Index + 1); Bez.DrawLine(); AttachedTransform.rotation = Quaternion.identity; try { AttachedTransform.LookAt(BezierLine.Instance.Path[Bez.CtrlPts[Mrkr.Index].SegStartIdx + 1]); AttachedTransform.Rotate(Vector3.forward, NewAngle); } catch (System.Exception e) { //Todo Find something for it to look at } transform.position = NewPos; OtherHandGizmo.position = _otherHandStartPos; transform.LookAt(OtherHandGizmo, AttachedTransform.up); OtherHandGizmo.LookAt(transform, AttachedTransform.up); }
public float Angle(int CtrlPtIdx) { float rtn; if (CtrlPtIdx < 2) { return(180); } Vector2 Pt0_2d = VectGeom.Convert2d(CtrlPts[CtrlPtIdx - 1].Pos); Vector2 Pt1_2d = VectGeom.Convert2d(CtrlPts[CtrlPtIdx].Pos); Vector2 Pt2_2d = VectGeom.Convert2d(CtrlPts[CtrlPtIdx + 1].Pos); rtn = Vector2.Angle(Pt0_2d - Pt1_2d, Pt2_2d - Pt1_2d); //Work out the sign of the angle b doing a cross product Vector3 cross = Vector3.Cross(Pt0_2d - Pt1_2d, Pt2_2d - Pt1_2d); if (cross.z > 0) { rtn = -rtn; } return(rtn); }
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); } } }
/// <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); } }
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 CalculateBends() { if (!IsCircular) { return; } Bends = new CircleList <Bend>(); Bend _bend = new Bend(); int BendId = 0; MovingAvgFloat AngleQueue = new MovingAvgFloat(5); _bez = BezierLine.Instance; int XSecCount = XSecs.Count(); Vector3 PrevMid; Vector3 ThisMid; Vector3 NextMid; BendType _bt = BendType.Unknown; BendType _prevbt = BendType.Unknown; int Incr = 1; float AngleThreshold = 1.34f; foreach (XSec X in XSecs) { PrevMid = XSecs.Prev(X).MidPt; ThisMid = X.MidPt; NextMid = XSecs.Next(X).MidPt; float Angle = VectGeom.SignedAngle(ThisMid + ThisMid - PrevMid, ThisMid, NextMid, Vector3.up); float _segDist = Vector3.Distance(ThisMid, NextMid); AngleQueue.Push(Angle); if (Mathf.Abs(AngleQueue.Avg) < AngleThreshold) { _bt = BendType.Straight; } else { _bt = AngleQueue.Avg > 0 ? BendType.Right : BendType.Left; } if (_prevbt == _bt) { _bend.Angle += Angle; } else { if (_prevbt == BendType.Left || _prevbt == BendType.Right) { //Finish off the previous bend if (Mathf.Abs(_bend.Angle) < 15) { //ignore small bends Bends.Remove(_bend); BendId--; } else { //take 2 off cos of moving avg _bend.EndXSec = XSecs[X.Idx - 2]; _bend.EndSegIdx = _bend.EndXSec.Idx; _bend.ApexXSec = XSecs[_bend.StartSegIdx + Mathf.RoundToInt(XSecs.Diff(_bend.StartXSec, _bend.EndXSec) / 2)]; _bend.ApexSegIdx = _bend.ApexXSec.Idx; if (_bend.Type == BendType.Right) { _bend.ApexPos = _bend.ApexXSec.KerbR + (_bend.ApexXSec.KerbL - _bend.ApexXSec.KerbR).normalized; _bend.MinTurninPos = _bend.StartXSec.KerbR + (_bend.StartXSec.KerbL - _bend.StartXSec.KerbR).normalized * (_bend.Concatenated ? 4 : 2); } if (_bend.Type == BendType.Left) { _bend.ApexPos = _bend.ApexXSec.KerbL + (_bend.ApexXSec.KerbR - _bend.ApexXSec.KerbL).normalized; _bend.MinTurninPos = _bend.StartXSec.KerbL + (_bend.StartXSec.KerbR - _bend.StartXSec.KerbL).normalized * (_bend.Concatenated ? 4 : 2); } //Fmax = mv^2/r float c = (_bend.EndSegIdx - _bend.StartSegIdx) * 360 / _bend.Angle; float r = Mathf.Abs(c) / Mathf.PI / 2f; //Debug.Log("Bend" + _bend.BendId + " radius = " + r); _bend.SqrtRad = Mathf.Sqrt(r); } } else { //We might be starting a new bend or carrying n the previous one if (_bt == BendType.Left || _bt == BendType.Right) { bool StartNewBend = true; if (BendId > 0 && X.Idx - Bends[BendId - 1].EndSegIdx < 15 && Bends[BendId - 1].Type == _bt) ///bugbugbug circle bug { //if the bend we've just finished is close to and the same sign as one before //We just carry on with this bend and dont create a new one StartNewBend = false; _bend.Concatenated = true; GameObject.Destroy(GameObject.Find("Turnin" + _bend.BendId)); GameObject.Destroy(GameObject.Find("Apex" + _bend.BendId)); GameObject.Destroy(GameObject.Find("BendStart" + _bend.BendId)); } if (StartNewBend) { //Create a new Bend _bend = new Bend(); _bend.Type = _bt; _bend.Sign = _bt == BendType.Right ? (Int16)1 : (Int16)(-1); _bend.StartXSec = XSecs[X.Idx - 2];//-2 cos of moving avg _bend.StartSegIdx = _bend.StartXSec.Idx; _bend.Angle = Angle; _bend.BendId = BendId; Bends.Add(_bend); BendId++; } } } //****************************************************************************************** } _prevbt = _bt; } //This is the last bend. NOt a brilliant bit but it doesn't crash if (_bt == BendType.Straight) { goto Finalise; } _bend.EndSegIdx = XSecs.Count - 1; _bend.EndXSec = XSecs[_bend.EndSegIdx]; if (_bend.EndSegIdx <= _bend.StartSegIdx && Bends.Count() > 0) { Bends.Remove(_bend); Bends.Last().EndSegIdx = XSecs.Count; } else { _bend.ApexSegIdx = Mathf.RoundToInt((_bend.EndSegIdx + _bend.StartSegIdx) / 2); _bend.ApexXSec = XSecs[_bend.ApexSegIdx]; if (_bend.Type == BendType.Right) { _bend.ApexPos = _bend.ApexXSec.KerbR + (_bend.ApexXSec.KerbL - _bend.ApexXSec.KerbR).normalized; } if (_bend.Type == BendType.Left) { _bend.ApexPos = _bend.ApexXSec.KerbL + (_bend.ApexXSec.KerbR - _bend.ApexXSec.KerbL).normalized; } } Finalise: CalculateTurninAndExitPoints(); PopulateXSecCurrBends(); }
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); }
public Vector3 LimitSlope(Vector3 Pt, float MaxSlope) { if (CtrlPts.Count == 2) { return(Pt); //Because the first click can be anywhere } BezCtrlPt PrevCtrlPt = CtrlPts[CtrlPts.Count - 2]; Vector3 Pt1 = PrevCtrlPt.Pos; Vector3 Pt2 = Pt; float HorizDist = Vector2.Distance(new Vector2(Pt1.x, Pt1.z), new Vector2(Pt2.x, Pt2.z)); //If point is too close move it further away if (HorizDist < 20) { Vector3 NewPt_3d = Pt1 + Vector3.Normalize(Pt2 - Pt1) * 20f; Pt2 = NewPt_3d; HorizDist = Vector2.Distance(new Vector2(Pt1.x, Pt1.z), new Vector2(Pt2.x, Pt2.z)); } //if point is too high lower it float VertDist = Pt2.y - Pt1.y; float Slope = 0; if (HorizDist > 0) { Slope = VertDist / HorizDist; } if (Slope > MaxSlope) { //Debug.Log("Lowering cos too steep"); Slope = MaxSlope; float NewVertDist = Slope * HorizDist; Pt2.y = Pt1.y + NewVertDist; } //Dont allow the angle less than 30 degrees float angle = 180; if (CtrlPts.Count > 3) { angle = Angle(CtrlPts[CtrlPts.Count - 3].Pos, PrevCtrlPt.Pos, Pt2); if (Mathf.Abs(angle) < 45) { //Debug.Log("Widening angle cos its too acute"); float RotAngle; if (angle > 0) { RotAngle = 45; } else { RotAngle = -45; } Quaternion Rot = Quaternion.Euler(0, RotAngle - angle, 0); Vector3 NewPt_3d = VectGeom.RotateAroundPoint(Pt2, Pt1, Rot); Pt2 = NewPt_3d; angle = RotAngle; } } //if hairpins are too sharp and too close together, spread them out if (HorizDist * Mathf.Abs(angle) < 1500) { //Debug.Log("Moving CtrlPt away from hairpin"); Vector3 NewPt_3d = Pt1 + Vector3.Normalize(Pt2 - Pt1) * 1500 / Mathf.Abs(angle); Pt2 = NewPt_3d; HorizDist = Vector2.Distance(new Vector2(Pt1.x, Pt1.z), new Vector2(Pt2.x, Pt2.z)); } if (Slope > 0 && Mathf.Abs(angle) / Slope < 270) { //Debug.Log("Flattening steep hairpin"); Slope = Mathf.Abs(angle) / 270; float NewVertDist = Slope * HorizDist; Pt2.y = Pt1.y + NewVertDist; } return(Pt2); //Debug.Log("Dist = " + HorizDist.ToString()); //Debug.Log("Slope = " + Slope.ToString()); //Debug.Log("Angle = " + angle.ToString()); //Typical values // Dist 10 - 30 // Slope < 0.3 }