diff options
| author | alex <[email protected]> | 2026-09-21 12:19:15 +0200 |
|---|---|---|
| committer | alex <[email protected]> | 2026-09-21 12:19:15 +0200 |
| commit | f0c870bb9dcffd79d0ad4e361d9f9f2a2ff807f8 (patch) | |
| tree | 02a46e0ed70171a679dbd69f435a2a8e1a3a0959 /Bullet.cs | |
| parent | 0c5df1e068ff8865545b7e1b3629377089c8b965 (diff) | |
| download | godot-testing-f0c870bb9dcffd79d0ad4e361d9f9f2a2ff807f8.tar.xz godot-testing-f0c870bb9dcffd79d0ad4e361d9f9f2a2ff807f8.zip | |
Diffstat (limited to 'Bullet.cs')
| -rw-r--r-- | Bullet.cs | 98 |
1 files changed, 82 insertions, 16 deletions
@@ -1,37 +1,103 @@ using Godot; using testing.interfaces; + public partial class Bullet : Area2D { [Export] public float Speed { get; set; } = 600.0f; [Export] public float Damage { get; set; } = 10.0f; public bool PierceEntity { get; set; } = false; public bool PierceTerrain { get; set; } = false; + public bool ricochet { get; set; } = true; + public int BounceLimit { get; set; } = 5; + private int bounces; public Vector2 Direction { get; set; } = Vector2.Zero; public override void _Ready() { - // Subscribe to the built-in BodyEntered event when the bullet is spawned - BodyEntered += OnBodyEntered; - - Rotation = Direction.Angle(); + bounces = 0; + if (Direction != Vector2.Zero) + { + Direction = Direction.Normalized(); + Rotation = Direction.Angle(); + } } public override void _PhysicsProcess(double delta) { - Position += Direction * Speed * (float)delta; - } + if (Direction == Vector2.Zero) return; - // This method is triggered automatically when the bullet hits a physics body - private void OnBodyEntered(Node2D body) - { - if (body is IDamageable target) + float remainingDistance = Speed * (float)delta; + int maxSteps = 4; + + while (remainingDistance > 0.001f && maxSteps > 0) { - // If it does, deal damage! - target.TakeDamage(Damage); - if(!PierceEntity){QueueFree();} - } - else{if(!PierceTerrain){QueueFree();}} - + maxSteps--; + Vector2 motion = Direction * remainingDistance; + + // Cast a ray along the motion path plus a small buffer offset (5 units) + Vector2 rayEnd = GlobalPosition + motion + Direction * 5.0f; + var spaceState = GetWorld2D().DirectSpaceState; + var query = PhysicsRayQueryParameters2D.Create(GlobalPosition, rayEnd, CollisionMask); + query.Exclude = new Godot.Collections.Array<Rid> { GetRid() }; + query.HitFromInside = true; + + var result = spaceState.IntersectRay(query); + + if (result.Count == 0) + { + GlobalPosition += motion; + break; + } + + Vector2 hitPos = result["position"].AsVector2(); + Vector2 hitNormal = result["normal"].AsVector2(); + GodotObject colliderObj = result["collider"].AsGodotObject(); + Node2D collider = colliderObj as Node2D; + + float distToHit = GlobalPosition.DistanceTo(hitPos); + float distMoved = Mathf.Min(remainingDistance, distToHit); + remainingDistance -= distMoved; + + if (collider is IDamageable target) + { + target.TakeDamage(Damage); + if (!PierceEntity) + { + QueueFree(); + return; + } + GlobalPosition = hitPos + Direction * 0.1f; + } + else + { + if (ricochet && bounces < BounceLimit) + { + if (hitNormal == Vector2.Zero) + { + Direction = -Direction; + } + else + { + Direction = Direction.Bounce(hitNormal).Normalized(); + } + + Rotation = Direction.Angle(); + bounces++; + + // Offset position slightly outward along hitNormal to avoid sticking inside geometry + GlobalPosition = hitPos + (hitNormal != Vector2.Zero ? hitNormal : Direction) * 2.0f; + } + else if (!PierceTerrain) + { + QueueFree(); + return; + } + else + { + GlobalPosition = hitPos + Direction * 0.1f; + } + } + } } } |
