Refactors projectile spawning to allow for customized spawn locations and stat assignment. Applies modifiers to projectiles at the time of spawning, enabling dynamic adjustments to projectile behavior.
136 lines
3.9 KiB
GDScript
136 lines
3.9 KiB
GDScript
class_name ProjectileBase
|
|
extends Area2D
|
|
|
|
signal on_hit(projectile, target)
|
|
signal on_spawned(projectile)
|
|
signal on_destroyed(projectile)
|
|
|
|
var stats = StatsComponent
|
|
var modifier_manager: ModifierManager
|
|
|
|
@export var speed: float = 500.0
|
|
@export var damage: float = 10.0
|
|
@export var lifetime: float = 2
|
|
@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: RangedWeaponComponent # 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 _init() -> void:
|
|
Log.pr('Setting up ModifierManager for projectile...')
|
|
modifier_manager = ModifierManager.new()
|
|
|
|
func _ready() -> void:
|
|
pass
|
|
|
|
func set_stats(setting_stats: StatsComponent) -> void:
|
|
Log.pr('Snapshotting stats for projectile:', setting_stats)
|
|
self.stats = setting_stats
|
|
modifier_manager.set_stats(stats)
|
|
|
|
# Set up the lifetime timer
|
|
lifetime_timer = Timer.new()
|
|
add_child(lifetime_timer)
|
|
lifetime_timer.one_shot = true
|
|
lifetime_timer.wait_time = lifetime
|
|
#lifetime_timer.connect("timeout", self, "_on_lifetime_timeout")
|
|
lifetime_timer.start()
|
|
|
|
# Ensure we have a collision shape
|
|
#ensure_collision_shape()
|
|
|
|
emit_signal("on_spawned", self)
|
|
#connect("body_entered", self, "_on_body_entered")
|
|
|
|
func add_modifier(modifier: Modifier) -> void:
|
|
modifier_manager.add_modifier(modifier)
|
|
|
|
func remove_modifier(modifier_id: String) -> void:
|
|
modifier_manager.remove_modifier(modifier_id)
|
|
|
|
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()
|