diff --git a/DungeonShooting_Godot/src/framework/common/Utils.cs b/DungeonShooting_Godot/src/framework/common/Utils.cs index 7c58641..b102450 100644 --- a/DungeonShooting_Godot/src/framework/common/Utils.cs +++ b/DungeonShooting_Godot/src/framework/common/Utils.cs @@ -290,4 +290,20 @@ return isInside; } + + /// + /// 根据法线翻转向量 + /// + public static Vector2 ReflectByNormal(Vector2 vector, Vector2 normal) + { + return vector.Reflect(normal.Rotated(Mathf.Pi * 0.5f)); + } + + /// + /// 根据法线翻转角度, 弧度制 + /// + public static float ReflectByNormal(float rotation, Vector2 normal) + { + return ReflectByNormal(Vector2.FromAngle(rotation), normal).Angle(); + } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs b/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs index 20db6e4..56735dd 100644 --- a/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs +++ b/DungeonShooting_Godot/src/game/activity/bullet/laser/Laser.cs @@ -10,6 +10,11 @@ public partial class Laser : Area2D, IBullet { /// + /// 激光默认宽度 + /// + public const float LaserDefaultWidth = 3f; + + /// /// 子节点包含的例子特效, 在创建完成后自动播放 /// [Export] @@ -46,7 +51,7 @@ public void InitData(BulletData data, uint attackLayer) { - InitData(data, attackLayer, 5); + InitData(data, attackLayer, LaserDefaultWidth); } public void InitData(BulletData data, uint attackLayer, float width) @@ -75,11 +80,17 @@ var parameters = PhysicsRayQueryParameters2D.Create(data.Position, targetPosition, PhysicsLayer.Wall); var result = GetWorld2D().DirectSpaceState.IntersectRay(parameters); float distance; - if (result != null && result.TryGetValue("position", out var point)) + var doRebound = false; //是否需要执行反弹 + Vector2? reboundPosition = null; + Vector2? reboundNormal = null; + if (result != null && result.TryGetValue("position", out var point)) //撞到墙壁 { - distance = Position.DistanceTo((Vector2)point); + doRebound = true; + reboundPosition = (Vector2)point; + reboundNormal = (Vector2)result["normal"]; + distance = Position.DistanceTo(reboundPosition.Value); } - else + else //没撞到墙壁 { distance = data.MaxDistance; } @@ -113,6 +124,11 @@ // tween.Chain(); _tween.TweenCallback(Callable.From(() => { + //执行反弹 + if (doRebound) + { + OnRebound(reboundPosition.Value, reboundNormal.Value); + } Collision.SetDeferred(CollisionShape2D.PropertyName.Disabled, false); })); _tween.Chain(); @@ -148,6 +164,34 @@ QueueFree(); } + + //激光撞墙反弹逻辑 + private void OnRebound(Vector2 position, Vector2 normal) + { + if (BulletData.BounceCount > 0) + { + var newDistance = BulletData.MaxDistance - BulletData.Position.DistanceTo(position); + if (newDistance > 0) + { + float rotation; + if (normal.X == 0 && normal.Y == 0) + { + rotation = (BulletData.Rotation + Mathf.Pi) % (Mathf.Pi * 2); + } + else + { + rotation = Utils.ReflectByNormal(BulletData.Rotation, normal); + } + + var bulletData = BulletData.Clone(); + bulletData.Position = position; + bulletData.BounceCount -= 1; + bulletData.MaxDistance = newDistance; + bulletData.Rotation = rotation; + FireManager.ShootBullet(bulletData, AttackLayer); + } + } + } private void OnArea2dEntered(Area2D other) { diff --git a/DungeonShooting_Godot/src/game/manager/FireManager.cs b/DungeonShooting_Godot/src/game/manager/FireManager.cs index 1a77262..65e7fa8 100644 --- a/DungeonShooting_Godot/src/game/manager/FireManager.cs +++ b/DungeonShooting_Godot/src/game/manager/FireManager.cs @@ -78,6 +78,9 @@ return null; } + /// + /// 计算进行抛物线运动的子弹击中目标所需要的速度等数据, 并设置 + /// public static void SetParabolaTarget(BulletData bulletData, Vector2 targetPosition) { var distance = bulletData.Position.DistanceTo(targetPosition); @@ -161,7 +164,7 @@ //创建激光 var laser = ObjectManager.GetLaser(bulletData.BulletBase.Prefab); laser.AddToActivityRoot(RoomLayerEnum.YSortLayer); - laser.InitData(bulletData, attackLayer, 3); + laser.InitData(bulletData, attackLayer, Laser.LaserDefaultWidth); return laser; }