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