BikeSpeedBooster.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Controller.Bicycle
  5. {
  6. internal readonly struct Booster
  7. {
  8. public float StartTime { get; }
  9. public float EndTime { get; }
  10. public float StartValue { get; }
  11. public float EndValue { get; }
  12. public Booster(float startTime, float duration, float startValue, float endValue)
  13. {
  14. StartTime = startTime;
  15. EndTime = startTime + duration;
  16. StartValue = startValue;
  17. EndValue = endValue;
  18. }
  19. public override string ToString()
  20. {
  21. return $"Booster({StartValue}-{EndValue} between Time({StartTime}, {EndTime}))";
  22. }
  23. }
  24. public class BikeSpeedBooster
  25. {
  26. public const float MaxBoost = 1.4f;
  27. public const float MinBoost = 0.6f;
  28. public const float ThresholdZero = 0.05f;
  29. private const float DURATION_BOOST_STRAIGHT_UPHILL = 2.5f;
  30. private const float DURATION_BOOST_UPHILL_STRAIGHT = 1.5f;
  31. private const float DURATION_BOOST_STRAIGHT_DOWNHILL = 3.5f;
  32. private const float DURATION_BOOST_DOWNHILL_STRAIGHT = 5f;
  33. private float fixedBoost = 1;
  34. private readonly float maxSlopeDeg = 8.7f;
  35. public float Boost
  36. {
  37. get
  38. {
  39. var boost = fixedBoost;
  40. var toDelete = new Stack<Booster>();
  41. var t = Time.time;
  42. foreach (var b in activeBooster)
  43. {
  44. if (b.EndTime < t)
  45. {
  46. toDelete.Push(b);
  47. continue;
  48. }
  49. if (b.StartTime > t) continue;
  50. var add = Mathf.Lerp(b.StartValue, b.EndValue,
  51. (Time.time - b.StartTime) / (b.EndTime - b.StartTime));
  52. boost *= add;
  53. }
  54. foreach (var d in toDelete) activeBooster.Remove(d);
  55. return Mathf.Clamp(boost, MinBoost, MaxBoost);
  56. }
  57. }
  58. public void AddBoosterForFirstAndSlope(float slopeDegree)
  59. {
  60. //going from straight to downhill -> increase speed from straight to slope
  61. //-> inverse fixed boost first, then 1*fixedBoost
  62. //going from straight to uphill -> decrease speed from straight to slope
  63. //-> inverse fixed boost first, then 1*fixedBoost
  64. var booster = new Booster(Time.time,
  65. slopeDegree < 0 ? DURATION_BOOST_STRAIGHT_DOWNHILL : DURATION_BOOST_STRAIGHT_UPHILL,
  66. 1f / fixedBoost, 1f);
  67. //Debug.Log($"Adding Booster: {booster}");
  68. activeBooster.Add(booster);
  69. }
  70. public void AddBoosterForLastAndSlope(float slopeDegree)
  71. {
  72. //going from downhill to straight -> let the bike roll -> boost starts at fixedBoost and decreases to 1
  73. //going from uphill to straight -> don't go to 1 immediately
  74. //-> boost starts at fixedBoost and increases to 1
  75. var booster = new Booster(Time.time,
  76. slopeDegree < 0 ? DURATION_BOOST_DOWNHILL_STRAIGHT : DURATION_BOOST_UPHILL_STRAIGHT,
  77. fixedBoost, 1f);
  78. //Debug.Log($"Adding Booster: {booster}");
  79. activeBooster.Add(booster);
  80. }
  81. public void SetFixedBoostForSlope(float slopeDegree)
  82. {
  83. var max = slopeDegree < 0 ? -maxSlopeDeg : maxSlopeDeg;
  84. fixedBoost = Mathf.Lerp(1f, slopeDegree < 0 ? MaxBoost : MinBoost, slopeDegree / max);
  85. }
  86. public void ResetFixedBoost()
  87. {
  88. fixedBoost = 1;
  89. }
  90. #region singleton
  91. private static readonly Lazy<BikeSpeedBooster>
  92. lazy =
  93. new Lazy<BikeSpeedBooster>
  94. (() => new BikeSpeedBooster());
  95. public static BikeSpeedBooster Instance => lazy.Value;
  96. private readonly List<Booster> activeBooster = new List<Booster>();
  97. #endregion
  98. }
  99. }