summaryrefslogtreecommitdiff
path: root/Bullet.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Bullet.cs')
-rw-r--r--Bullet.cs98
1 files changed, 82 insertions, 16 deletions
diff --git a/Bullet.cs b/Bullet.cs
index b131638..9202e3a 100644
--- a/Bullet.cs
+++ b/Bullet.cs
@@ -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;
+ }
+ }
+ }
}
}