52 lines
1.4 KiB
GDScript
52 lines
1.4 KiB
GDScript
extends ExplosiveProjectile
|
|
class_name BouncingProjectile
|
|
|
|
var fuse_time: float = -1.0 # -1 means no fuse started yet
|
|
var bounce_fuse_delay: float = 3.0 # How long to wait after bouncing
|
|
var impact_detonate_time: float = 2.0
|
|
var bounciness: float = 0.4
|
|
var flight_time: float = 0.0
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
flight_time += delta
|
|
|
|
if fuse_time > 0.0:
|
|
fuse_time -= delta
|
|
if fuse_time <= 0.0:
|
|
_explode(global_position)
|
|
destroy()
|
|
return
|
|
|
|
# Apply gravity drop if any
|
|
velocity.y -= drop_gravity * delta
|
|
|
|
var movement = velocity * delta
|
|
|
|
var space_state = get_world_3d().direct_space_state
|
|
var query = PhysicsRayQueryParameters3D.create(_previous_position, global_position + movement)
|
|
if owner_player:
|
|
query.exclude = [owner_player.get_rid()]
|
|
|
|
var result = space_state.intersect_ray(query)
|
|
if result:
|
|
if flight_time > impact_detonate_time:
|
|
# Explode on impact if flying long enough
|
|
_on_hit(result)
|
|
else:
|
|
# Bounce
|
|
global_position = result.position + result.normal * 0.05
|
|
_previous_position = global_position
|
|
|
|
# Reflect velocity
|
|
velocity = velocity.bounce(result.normal) * bounciness
|
|
|
|
# Start the fuse if it hasn't started
|
|
if fuse_time < 0.0:
|
|
fuse_time = bounce_fuse_delay
|
|
|
|
# If it hits an entity directly, still bounce, it's a heavy mortar shell!
|
|
else:
|
|
global_position += movement
|
|
distance_traveled += movement.length()
|
|
_previous_position = global_position
|