public ArcData(ArcRaw arc) { this.start = Conversion.GetWorldPos(math.float2(arc.startX, arc.startY)); this.end = Conversion.GetWorldPos(math.float2(arc.endX, arc.endY)); this.easing = arc.easing; this.startTiming = arc.timing; this.endTiming = arc.endTiming; }
private static Vector3 EaseSinus(Vector3 p1, Vector3 p2, float t, ArcEasing easing) { var y = MathHelper.Lerp(p1.Y, p2.Y, t); float sx, sz; switch (easing) { case ArcEasing.Si: case ArcEasing.SiSi: case ArcEasing.SiSo: sx = MathF.Sin(t * MathHelper.PiOver2); break; case ArcEasing.So: case ArcEasing.SoSi: case ArcEasing.SoSo: sx = 1 - MathF.Cos(t * MathHelper.PiOver2); break; default: throw new ArgumentOutOfRangeException(nameof(easing), easing, null); } switch (easing) { case ArcEasing.Si: case ArcEasing.So: // Credit: @18111398 sz = t; break; case ArcEasing.SoSi: case ArcEasing.SiSi: sz = MathF.Sin(t * MathHelper.PiOver2); break; case ArcEasing.SiSo: case ArcEasing.SoSo: sz = 1 - MathF.Cos(t * MathHelper.PiOver2); break; default: throw new ArgumentOutOfRangeException(nameof(easing), easing, null); } var dx = p2.X - p1.X; var x = p1.X + dx * sx; var dz = p2.Z - p1.Z; var z = p1.Z + dz * sz; return(new Vector3(x, y, z)); }
public static float GetYAt(float t, float startY, float endY, ArcEasing easing) { switch (easing) { case ArcEasing.s: case ArcEasing.si: case ArcEasing.so: return(math.lerp(startY, endY, t)); case ArcEasing.b: return(B(startY, endY, t)); case ArcEasing.sisi: case ArcEasing.sosi: return(I(startY, endY, t)); case ArcEasing.siso: case ArcEasing.soso: return(O(startY, endY, t)); } //Not possible, just here to make the compiler smile return(float.PositiveInfinity); }
/// <summary> /// Calculates the eased value of a pair of coordinates. /// </summary> /// <param name="start">Start position.</param> /// <param name="end">End position.</param> /// <param name="t">A value increasing from 0 to 1 while moving from <see cref="start"/> to <see cref="end"/>.</param> /// <param name="easing">Easing method.</param> /// <returns>Eased coordinate.</returns> public static Vector3 Ease(Vector3 start, Vector3 end, float t, ArcEasing easing) { t = MathHelper.Clamp(t, 0, 1); switch (easing) { case ArcEasing.S: return(EaseLinear(start, end, t)); case ArcEasing.CubicBezier: return(EaseCubicBezier(start, end, t)); case ArcEasing.Si: case ArcEasing.So: case ArcEasing.SiSo: case ArcEasing.SoSi: case ArcEasing.SoSo: case ArcEasing.SiSi: return(EaseSinus(start, end, t, easing)); default: throw new ArgumentOutOfRangeException(nameof(easing), easing, null); } }
private void DrawArc([NotNull] BasicEffect effect, int segmentCount, Vector3 start, Vector3 end, ArcEasing easing, Color color, float alpha, Vector2 arcSectionSize, bool castShadow) { var lastPoint = start; var zeroY = _metrics.FinishLineY; var trackEndY = _metrics.TrackLength; for (var i = 1; i <= segmentCount; ++i) { if (lastPoint.Y > trackEndY) { // This segment and later segments have not entered the track yet. break; } Vector3 currentPoint; if (i == segmentCount) { currentPoint = end; } else { var ratio = (float)i / segmentCount; currentPoint = ArcEasingHelper.Ease(start, end, ratio, easing); } if (lastPoint.Y < zeroY && currentPoint.Y < zeroY) { // This segment has passed. continue; } Vector3 fixedLastPoint, fixedCurrentPoint; // Recalculate the segment's start and end if needed. // However, we must ensure that the movement of the intersection of the arc and XoZ plane is always continuous, // therefore we must call the easing function again to retrieve its precise new location, instead of learping // inside the segment's start and end (shows recognizable "shaking" effect). // Credit: @18111398 if (lastPoint.Y < zeroY) { var ratio = (zeroY - start.Y) / (end.Y - start.Y); fixedLastPoint = ArcEasingHelper.Ease(start, end, ratio, easing); } else { fixedLastPoint = lastPoint; } if (currentPoint.Y > trackEndY) { var ratio = (trackEndY - start.Y) / (end.Y - start.Y); fixedCurrentPoint = ArcEasingHelper.Ease(start, end, ratio, easing); } else { fixedCurrentPoint = currentPoint; } _arcMesh.SetVerticesXY(fixedLastPoint, fixedCurrentPoint, color, arcSectionSize.X); effect.TextureEnabled = false; effect.VertexColorEnabled = true; effect.Alpha = alpha; _arcMesh.Draw(effect.CurrentTechnique); // Draw shadow if needed. if (castShadow) { _shadow.SetVerticesXYParallel(fixedLastPoint.XY(), fixedCurrentPoint.XY(), arcSectionSize.X, Color.Gray, ShadowZ); effect.TextureEnabled = false; effect.VertexColorEnabled = true; effect.Alpha = 0.5f; _shadow.Draw(effect.CurrentTechnique); } // Update the point. lastPoint = currentPoint; } }
public static float2 GetPosAt(float t, float2 start, float2 end, ArcEasing easing) => new float2(GetXAt(t, start.x, end.x, easing), GetYAt(t, start.y, end.y, easing));