Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / camera / GameCamera.cs
  1. using System.Collections.Generic;
  2. using Godot;
  3.  
  4. /// <summary>
  5. /// 游戏相机
  6. /// </summary>
  7. public partial class GameCamera : Camera2D
  8. {
  9. /// <summary>
  10. /// 当前场景的相机对象
  11. /// </summary>
  12. public static GameCamera Main { get; private set; }
  13.  
  14. /// <summary>
  15. /// 恢复系数
  16. /// </summary>
  17. [Export]
  18. public float RecoveryCoefficient = 100f;
  19. /// <summary>
  20. /// 抖动开关
  21. /// </summary>
  22. public bool Enable { get; set; } = true;
  23. public Vector2 SubPixelPosition { get; private set; }
  24.  
  25. private long _index = 0;
  26. private Vector2 _processDistance = Vector2.Zero;
  27. private Vector2 _processDirection = Vector2.Zero;
  28. private readonly Dictionary<long, Vector2> _shakeMap = new Dictionary<long, Vector2>();
  29. private Vector2 _camPos;
  30. private Vector2 _shakeOffset = Vector2.Zero;
  31.  
  32. public override void _Ready()
  33. {
  34. Main = this;
  35. _camPos = GlobalPosition;
  36. }
  37.  
  38. public override void _Process(double delta)
  39. {
  40. var newDelta = (float)delta;
  41. _Shake(newDelta);
  42. // 3.5 写法
  43. // var player = GameApplication.Instance.RoomManager.Player;
  44. // var viewportContainer = GameApplication.Instance.SubViewportContainer;
  45. // var camPos = player.GlobalPosition;
  46. // _camPos = _camPos.Lerp(camPos, Mathf.Min(6 * newDelta, 1)) + _shakeOffset;
  47. // SubPixelPosition = _camPos.Round() - _camPos;
  48. // (viewportContainer.Material as ShaderMaterial)?.SetShaderParameter("offset", SubPixelPosition);
  49. // GlobalPosition = _camPos.Round();
  50. var player = GameApplication.Instance.RoomManager.Player;
  51. var mousePosition = InputManager.GetViewportMousePosition();
  52. var playerPosition = player.GlobalPosition;
  53. Vector2 targetPos;
  54. if (playerPosition.DistanceSquaredTo(mousePosition) >= (60 / 0.3f) * (60 / 0.3f))
  55. {
  56. targetPos = playerPosition.MoveToward(mousePosition, 60);
  57. }
  58. else
  59. {
  60. targetPos = playerPosition.Lerp(mousePosition, 0.3f);
  61. }
  62. _camPos = _camPos.Lerp(targetPos, Mathf.Min(6 * newDelta, 1)) + _shakeOffset;
  63. SubPixelPosition = _camPos.Round() - _camPos;
  64. GlobalPosition = _camPos.Round();
  65. }
  66. /// <summary>
  67. /// 设置帧抖动, 结束后自动清零, 需要每一帧调用
  68. /// </summary>
  69. /// <param name="value">抖动的力度</param>
  70. public void ProcessShake(Vector2 value)
  71. {
  72. if (value.Length() > _processDistance.Length())
  73. {
  74. _processDistance = value;
  75. }
  76. }
  77.  
  78. public void ProcessDirectionalShake(Vector2 value)
  79. {
  80. _processDirection += value;
  81. }
  82.  
  83. /// <summary>
  84. /// 创建一个抖动, 并设置抖动时间
  85. /// </summary>
  86. /// <param name="value">抖动力度</param>
  87. /// <param name="time">抖动生效时间</param>
  88. public async void CreateShake(Vector2 value, float time)
  89. {
  90. if (time > 0)
  91. {
  92. long tempIndex = _index++;
  93. SceneTreeTimer sceneTreeTimer = GetTree().CreateTimer(time);
  94. _shakeMap[tempIndex] = value;
  95. await ToSignal(sceneTreeTimer, "timeout");
  96. _shakeMap.Remove(tempIndex);
  97. }
  98. }
  99.  
  100. //抖动调用
  101. private void _Shake(float delta)
  102. {
  103. if (Enable)
  104. {
  105. var distance = _CalculateDistance();
  106. _shakeOffset += _processDirection + new Vector2(
  107. Utils.RandfRange(-distance.X, distance.X) - _shakeOffset.X,
  108. Utils.RandfRange(-distance.Y, distance.Y) - _shakeOffset.Y
  109. );
  110. _processDistance = Vector2.Zero;
  111. _processDirection = Vector2.Zero;
  112. }
  113. else
  114. {
  115. _shakeOffset = _shakeOffset.Lerp(Vector2.Zero, RecoveryCoefficient * delta);
  116. }
  117. }
  118.  
  119. //计算相机需要抖动的值
  120. private Vector2 _CalculateDistance()
  121. {
  122. Vector2 temp = Vector2.Zero;
  123. float length = 0;
  124. foreach (var item in _shakeMap)
  125. {
  126. var value = item.Value;
  127. float tempLenght = value.Length();
  128. if (tempLenght > length)
  129. {
  130. length = tempLenght;
  131. temp = value;
  132. }
  133. }
  134. return _processDistance.Length() > length ? _processDistance : temp;
  135. }
  136.  
  137. }