Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / camera / GameCamera.cs
@小李xl 小李xl on 1 Nov 2023 7 KB 制作爆炸特效
  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.  
  71. public override void _Process(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. Vector2 targetPos;
  91. //if (targetPosition.DistanceSquaredTo(mousePosition) >= 39999.992F) // >= (60 / 0.3f) * (60 / 0.3f)
  92. if (targetPosition.DistanceSquaredTo(mousePosition) >= (60 / FollowsMouseAmount) * (60 / FollowsMouseAmount))
  93. {
  94. targetPos = targetPosition.MoveToward(mousePosition, 60);
  95. }
  96. else
  97. {
  98. //targetPos = targetPosition.Lerp(mousePosition, 0.3f); //这里的0.3就是上面的 (60 / 0.3f) * (60 / 0.3f) 中的 0.3
  99. targetPos = targetPosition.Lerp(mousePosition, FollowsMouseAmount);
  100. }
  101. _camPos = _camPos.Lerp(targetPos, 20 * newDelta);
  102. GlobalPosition = _camPos.Round();
  103.  
  104. Offset = _shakeOffset.Round();
  105. //_temp = _camPos - targetPosition;
  106.  
  107. //调用相机更新事件
  108. if (OnPositionUpdateEvent != null)
  109. {
  110. OnPositionUpdateEvent(newDelta);
  111. }
  112. }
  113. }
  114.  
  115. /// <summary>
  116. /// 设置相机跟随目标
  117. /// </summary>
  118. public void SetFollowTarget(Role target)
  119. {
  120. _followTarget = target;
  121. if (target != null)
  122. {
  123. _camPos = target.GlobalPosition;
  124. GlobalPosition = _camPos;
  125. }
  126. }
  127.  
  128. /// <summary>
  129. /// 获取相机跟随目标
  130. /// </summary>
  131. public Role GetFollowTarget()
  132. {
  133. return _followTarget;
  134. }
  135. /// <summary>
  136. /// 设置帧抖动, 结束后自动清零, 需要每一帧调用
  137. /// </summary>
  138. /// <param name="value">抖动的力度</param>
  139. public void Shake(Vector2 value)
  140. {
  141. if (value.LengthSquared() > _processDistanceSquared.LengthSquared())
  142. {
  143. _processDistanceSquared = value;
  144. }
  145. }
  146. /// <summary>
  147. /// 添加一个单方向上的抖动, 该帧结束后自动清零
  148. /// </summary>
  149. public void DirectionalShake(Vector2 value)
  150. {
  151. _processDirection += value;
  152. }
  153. /// <summary>
  154. /// 创建一个抖动, 并设置抖动时间
  155. /// </summary>
  156. public async void CreateShake(Vector2 value, float time, bool decline = false)
  157. {
  158. if (time > 0)
  159. {
  160. value.X = Mathf.Abs(value.X);
  161. value.Y = Mathf.Abs(value.Y);
  162. var tempIndex = _index++;
  163. var sceneTreeTimer = GetTree().CreateTimer(time);
  164. if (decline)
  165. {
  166. _shakeMap[tempIndex] = new ShakeData(value, true, value.Length() / time);
  167. }
  168. else
  169. {
  170. _shakeMap[tempIndex] = new ShakeData(value, false, 0);
  171. }
  172.  
  173. await ToSignal(sceneTreeTimer, Timer.SignalName.Timeout);
  174. _shakeMap.Remove(tempIndex);
  175. }
  176. }
  177.  
  178. /// <summary>
  179. /// 播放玩家死亡特写镜头
  180. /// </summary>
  181. public void PlayPlayerDieFeatures()
  182. {
  183. }
  184.  
  185. //抖动调用
  186. private void _Shake(float delta)
  187. {
  188. if (EnableShake)
  189. {
  190. var distance = _CalculateDistanceSquared(delta);
  191. distance = new Vector2(Mathf.Sqrt(distance.X), Mathf.Sqrt(distance.Y));
  192. _shakeOffset += _processDirection + new Vector2(
  193. (float)GD.RandRange(-distance.X, distance.X) - Offset.X,
  194. (float)GD.RandRange(-distance.Y, distance.Y) - Offset.Y
  195. );
  196. _processDistanceSquared = Vector2.Zero;
  197. _processDirection = _processDirection.Lerp(Vector2.Zero, RecoveryCoefficient * delta);
  198. }
  199. else
  200. {
  201. _shakeOffset = _shakeOffset.Lerp(Vector2.Zero, RecoveryCoefficient * delta);
  202. }
  203. }
  204.  
  205. //计算相机需要抖动的值
  206. private Vector2 _CalculateDistanceSquared(float delta)
  207. {
  208. var temp = Vector2.Zero;
  209. float length = 0;
  210.  
  211. foreach (var keyValuePair in _shakeMap)
  212. {
  213. var shakeData = keyValuePair.Value;
  214. var tempLenght = shakeData.Value.LengthSquared();
  215. if (tempLenght > length)
  216. {
  217. length = tempLenght;
  218. temp = shakeData.Value;
  219. if (shakeData.Decline)
  220. {
  221. shakeData.Value = shakeData.Value.MoveToward(Vector2.Zero, shakeData.DataDelta * delta);
  222. //Debug.Log("shakeData.Value: " + shakeData.Value + ", _processDistanceSquared: " + _processDistanceSquared);
  223. }
  224. }
  225. }
  226.  
  227. //return temp;
  228. return _processDistanceSquared.LengthSquared() > length ? _processDistanceSquared : temp;
  229. }
  230. }