Refactors the lightning projectile to handle collisions more effectively. It now stops upon hitting an enemy or object, triggers an explosion, and spawns child projectiles from the collision point. The lightning bolt's collision shape is dynamically updated to match the remaining distance to the target or the collision point. Also adds more test enemies to the map for testing purposes.
101 lines
No EOL
2.9 KiB
GDScript
101 lines
No EOL
2.9 KiB
GDScript
class_name ProjectileBase
|
|
extends Area2D
|
|
|
|
signal on_hit(projectile, target)
|
|
signal on_spawned(projectile)
|
|
signal on_destroyed(projectile)
|
|
|
|
@export var speed: float = 500.0
|
|
@export var damage: float = 10.0
|
|
@export var lifetime: float = 5.0
|
|
@export var direction: Vector2 = Vector2.RIGHT
|
|
@export var target_position: Vector2
|
|
@export var is_friendly: bool = true
|
|
|
|
# Modifier-related properties
|
|
var pierce_count: int = 0
|
|
var has_explosive_impact: bool = true
|
|
var explosion_projectile_count: int = 3
|
|
var explosion_projectile_damage_mult: float = 0.5
|
|
var explosion_projectile_speed: float = 300.0
|
|
var explosion_spread_angle: float = 360.0 # Full circle by default
|
|
|
|
# References
|
|
var source_weapon: RangedWeapon # Reference to the weapon that fired this
|
|
var lifetime_timer: Timer
|
|
# Add a variable to track the entity that triggered the explosion
|
|
var ignore_target = []
|
|
|
|
func _on_body_entered(body):
|
|
if ignore_target.has(body):
|
|
Log.pr("Ignoring body: ", body.name)
|
|
return
|
|
|
|
if body.is_in_group("enemies") and is_friendly:
|
|
Log.pr("Hit enemy: ", body.name)
|
|
# Deal damage to enemy
|
|
if body.has_method("take_damage"):
|
|
body.take_damage(damage)
|
|
|
|
# Emit signal for modifiers to react to
|
|
emit_signal("on_hit", self, body)
|
|
|
|
# Handle piercing
|
|
if pierce_count > 0:
|
|
pierce_count -= 1
|
|
else:
|
|
# Handle explosive impact
|
|
if has_explosive_impact:
|
|
# Store the target that triggered the explosion
|
|
ignore_target.append(body)
|
|
_trigger_explosion()
|
|
|
|
# Destroy the projectile
|
|
destroy()
|
|
|
|
func _trigger_explosion():
|
|
# Create the explosion VFX
|
|
# var explosion = preload("res://scenes/explosion_effect.tscn").instantiate()
|
|
# explosion.global_position = global_position
|
|
# get_tree().root.add_child(explosion)
|
|
# Spawn the additional projectiles
|
|
if explosion_projectile_count > 0:
|
|
_spawn_explosion_projectiles()
|
|
|
|
func _spawn_explosion_projectiles():
|
|
for i in range(explosion_projectile_count):
|
|
# Create a new projectile
|
|
Log.pr("Spawning explosion projectile")
|
|
var new_proj = duplicate()
|
|
Log.pr("New projectile: ", new_proj)
|
|
new_proj.global_position = global_position
|
|
|
|
# Calculate new direction based on spread
|
|
var random_angle = randf_range(0, 2 * PI)
|
|
var new_dir = Vector2.RIGHT.rotated(random_angle)
|
|
|
|
# Set properties for the new projectile
|
|
new_proj.direction = new_dir
|
|
new_proj.damage = damage * explosion_projectile_damage_mult
|
|
new_proj.speed = explosion_projectile_speed
|
|
|
|
# Clear explosive properties so we don't get infinite loops
|
|
new_proj.has_explosive_impact = true
|
|
new_proj.explosion_projectile_count = 1
|
|
|
|
# Pass the ignore_target to the new projectiles
|
|
new_proj.ignore_target = ignore_target
|
|
|
|
# Add to scene tree
|
|
get_tree().root.call_deferred("add_child", new_proj)
|
|
|
|
func set_projectile_scale(new_scale: Vector2):
|
|
# Set the scale of the projectile
|
|
self.scale = new_scale
|
|
|
|
func destroy():
|
|
emit_signal("on_destroyed", self)
|
|
queue_free()
|
|
|
|
func _on_lifetime_timeout():
|
|
destroy() |