Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / camera / GameCamera.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using Godot;
  4.  
  5. /// <summary>
  6. /// 游戏相机
  7. /// </summary>
  8. public partial class GameCamera : Camera2D
  9. {
  10. private class ShakeData
  11. {
  12. public Vector2 Value;
  13. public bool Decline;
  14. public float DataDelta;
  15.  
  16. public ShakeData(Vector2 value, bool decline, float dataDelta)
  17. {
  18. Value = value;
  19. Decline = decline;
  20. DataDelta = dataDelta;
  21. }
  22. }
  23. /// <summary>
  24. /// 当前场景的相机对象
  25. /// </summary>
  26. public static GameCamera Main { get; private set; }
  27.  
  28. /// <summary>
  29. /// 相机坐标更新完成事件
  30. /// </summary>
  31. public event Action<float> OnPositionUpdateEvent;
  32.  
  33. /// <summary>
  34. /// 恢复系数
  35. /// </summary>
  36. [Export]
  37. public float RecoveryCoefficient = 25f;
  38. /// <summary>
  39. /// 抖动开关
  40. /// </summary>
  41. public bool EnableShake { get; set; } = true;
  42.  
  43. /// <summary>
  44. /// 镜头跟随鼠标进度 (0 - 1)
  45. /// </summary>
  46. public float FollowsMouseAmount = 0.15f;
  47. /// <summary>
  48. /// 相机跟随目标
  49. /// </summary>
  50. private Role _followTarget;
  51. // 3.5
  52. //public Vector2 SubPixelPosition { get; private set; }
  53.  
  54. private long _index = 0;
  55. private Vector2 _processDistanceSquared = Vector2.Zero;
  56. private Vector2 _processDirection = Vector2.Zero;
  57. //抖动数据
  58. private readonly Dictionary<long, ShakeData> _shakeMap = new Dictionary<long, ShakeData>();
  59. private Vector2 _camPos;
  60. private Vector2 _shakeOffset = Vector2.Zero;
  61.  
  62. public GameCamera()
  63. {
  64. Main = this;
  65. }
  66. public override void _Ready()
  67. {
  68. _camPos = GlobalPosition;
  69. }
  70. //_PhysicsProcess
  71. public override void _PhysicsProcess(double delta)
  72. {
  73. var newDelta = (float)delta;
  74. _Shake(newDelta);
  75. // 3.5 写法
  76. // var player = GameApplication.Instance.RoomManager.Player;
  77. // var viewportContainer = GameApplication.Instance.SubViewportContainer;
  78. // var camPos = player.GlobalPosition;
  79. // _camPos = _camPos.Lerp(camPos, Mathf.Min(6 * newDelta, 1)) + _shakeOffset;
  80. // SubPixelPosition = _camPos.Round() - _camPos;
  81. // (viewportContainer.Material as ShaderMaterial)?.SetShaderParameter("offset", SubPixelPosition);
  82. // GlobalPosition = _camPos.Round();
  83.  
  84.  
  85. var world = GameApplication.Instance.World;
  86. if (world != null && !world.Pause && _followTarget != null)
  87. {
  88. var mousePosition = InputManager.CursorPosition;
  89. var targetPosition = _followTarget.GlobalPosition;
  90. //if (targetPosition.DistanceSquaredTo(mousePosition) >= 39999.992F) // >= (60 / 0.3f) * (60 / 0.3f)
  91. if (targetPosition.DistanceSquaredTo(mousePosition) >= (60 / FollowsMouseAmount) * (60 / FollowsMouseAmount))
  92. {
  93. _camPos = targetPosition.MoveToward(mousePosition, 60);
  94. }
  95. else
  96. {
  97. //targetPos = targetPosition.Lerp(mousePosition, 0.3f); //这里的0.3就是上面的 (60 / 0.3f) * (60 / 0.3f) 中的 0.3
  98. _camPos = targetPosition.Lerp(mousePosition, FollowsMouseAmount);
  99. }
  100. //_camPos = _camPos.Lerp(targetPos, 20 * newDelta);
  101. GlobalPosition = _camPos.Round();
  102.  
  103. Offset = _shakeOffset.Round();
  104.  
  105. //调用相机更新事件
  106. if (OnPositionUpdateEvent != null)
  107. {
  108. OnPositionUpdateEvent(newDelta);
  109. }
  110. }
  111. }
  112.  
  113. /// <summary>
  114. /// 设置相机跟随目标
  115. /// </summary>
  116. public void SetFollowTarget(Role target)
  117. {
  118. _followTarget = target;
  119. if (target != null)
  120. {
  121. _camPos = target.GlobalPosition;
  122. GlobalPosition = _camPos;
  123. }
  124. }
  125.  
  126. /// <summary>
  127. /// 获取相机跟随目标
  128. /// </summary>
  129. public Role GetFollowTarget()
  130. {
  131. return _followTarget;
  132. }
  133. /// <summary>
  134. /// 设置帧抖动, 结束后自动清零, 需要每一帧调用
  135. /// </summary>
  136. /// <param name="value">抖动的力度</param>
  137. public void Shake(Vector2 value)
  138. {
  139. if (value.LengthSquared() > _processDistanceSquared.LengthSquared())
  140. {
  141. _processDistanceSquared = value;
  142. }
  143. }
  144. /// <summary>
  145. /// 添加一个单方向上的抖动, 该帧结束后自动清零
  146. /// </summary>
  147. public void DirectionalShake(Vector2 value)
  148. {
  149. _processDirection += value;
  150. }
  151. /// <summary>
  152. /// 创建一个抖动, 并设置抖动时间
  153. /// </summary>
  154. public async void CreateShake(Vector2 value, float time, bool decline = false)
  155. {
  156. if (time > 0)
  157. {
  158. value.X = Mathf.Abs(value.X);
  159. value.Y = Mathf.Abs(value.Y);
  160. var tempIndex = _index++;
  161. var sceneTreeTimer = GetTree().CreateTimer(time);
  162. if (decline)
  163. {
  164. _shakeMap[tempIndex] = new ShakeData(value, true, value.Length() / time);
  165. }
  166. else
  167. {
  168. _shakeMap[tempIndex] = new ShakeData(value, false, 0);
  169. }
  170.  
  171. await ToSignal(sceneTreeTimer, Timer.SignalName.Timeout);
  172. _shakeMap.Remove(tempIndex);
  173. }
  174. }
  175.  
  176. /// <summary>
  177. /// 播放玩家死亡特写镜头
  178. /// </summary>
  179. public void PlayPlayerDieFeatures()
  180. {
  181. }
  182.  
  183. //抖动调用
  184. private void _Shake(float delta)
  185. {
  186. if (EnableShake)
  187. {
  188. var distance = _CalculateDistanceSquared(delta);
  189. distance = new Vector2(Mathf.Sqrt(distance.X), Mathf.Sqrt(distance.Y));
  190. _shakeOffset += _processDirection + new Vector2(
  191. (float)GD.RandRange(-distance.X, distance.X) - Offset.X,
  192. (float)GD.RandRange(-distance.Y, distance.Y) - Offset.Y
  193. );
  194. _processDistanceSquared = Vector2.Zero;
  195. _processDirection = _processDirection.Lerp(Vector2.Zero, RecoveryCoefficient * delta);
  196. }
  197. else
  198. {
  199. _shakeOffset = _shakeOffset.Lerp(Vector2.Zero, RecoveryCoefficient * delta);
  200. }
  201. }
  202.  
  203. //计算相机需要抖动的值
  204. private Vector2 _CalculateDistanceSquared(float delta)
  205. {
  206. var temp = Vector2.Zero;
  207. float length = 0;
  208.  
  209. foreach (var keyValuePair in _shakeMap)
  210. {
  211. var shakeData = keyValuePair.Value;
  212. var tempLenght = shakeData.Value.LengthSquared();
  213. if (tempLenght > length)
  214. {
  215. length = tempLenght;
  216. temp = shakeData.Value;
  217. if (shakeData.Decline)
  218. {
  219. shakeData.Value = shakeData.Value.MoveToward(Vector2.Zero, shakeData.DataDelta * delta);
  220. //Debug.Log("shakeData.Value: " + shakeData.Value + ", _processDistanceSquared: " + _processDistanceSquared);
  221. }
  222. }
  223. }
  224.  
  225. //return temp;
  226. return _processDistanceSquared.LengthSquared() > length ? _processDistanceSquared : temp;
  227. }
  228. }