200 lines
5.9 KiB
GDScript
200 lines
5.9 KiB
GDScript
class_name ProjectileLightning
|
|
extends ProjectileBase
|
|
|
|
@export var line_width: float = 2
|
|
@onready var lightning: Array = get_children()
|
|
|
|
# Add variables to track collision state
|
|
var has_collided: bool = false
|
|
var collision_point: Vector2 = Vector2.ZERO
|
|
|
|
func _init() -> void:
|
|
#super._init()
|
|
Log.pr("ProjectileLightning _init")
|
|
|
|
func _ready():
|
|
Log.pr(ignore_target)
|
|
|
|
lifetime_timer = Timer.new()
|
|
add_child(lifetime_timer)
|
|
lifetime_timer.one_shot = true
|
|
lifetime_timer.wait_time = lifetime
|
|
lifetime_timer.connect("timeout", _on_lifetime_timeout)
|
|
lifetime_timer.start()
|
|
|
|
# Make sure we have a collision shape
|
|
ensure_collision_shape()
|
|
|
|
for child in lightning:
|
|
if child.has_method("set_line_width"):
|
|
child.set_line_width(line_width)
|
|
|
|
emit_signal("on_spawned", self)
|
|
connect("body_entered", _on_body_entered)
|
|
|
|
# Add a method to ensure we have a collision shape
|
|
func ensure_collision_shape():
|
|
# Check if we already have a collision shape
|
|
var has_collision_shape = false
|
|
var existing_shape = null
|
|
|
|
for child in get_children():
|
|
if child is CollisionShape2D:
|
|
has_collision_shape = true
|
|
existing_shape = child
|
|
break
|
|
|
|
# If no collision shape exists, create one
|
|
if not has_collision_shape:
|
|
var collision_shape = CollisionShape2D.new()
|
|
var capsule_shape = CapsuleShape2D.new()
|
|
|
|
# Set the shape properties
|
|
capsule_shape.radius = line_width / 2
|
|
collision_shape.shape = capsule_shape
|
|
|
|
add_child(collision_shape)
|
|
existing_shape = collision_shape
|
|
|
|
# Make sure the lightning area is set to detect the right objects
|
|
set_collision_mask_value(2, true) # Assuming layer 2 is for enemies
|
|
set_collision_mask_value(3, true) # Assuming layer 3 is for objects
|
|
|
|
# Update the collision shape dimensions and position
|
|
update_collision_shape(existing_shape)
|
|
|
|
# Combined method to update collision shape based on current state
|
|
func update_collision_shape(collision_shape = null):
|
|
if collision_shape == null:
|
|
# Find the collision shape if not provided
|
|
for child in get_children():
|
|
if child is CollisionShape2D:
|
|
collision_shape = child
|
|
break
|
|
|
|
if collision_shape:
|
|
var capsule = collision_shape.shape as CapsuleShape2D
|
|
if capsule:
|
|
var target = collision_point if has_collided else target_position
|
|
var distance = global_position.distance_to(target)
|
|
var dir = (target - global_position).normalized()
|
|
|
|
# Update capsule height to match exact distance
|
|
capsule.height = distance
|
|
|
|
# Fix rotation based on current direction
|
|
collision_shape.rotation = dir.angle() + PI / 2
|
|
|
|
# Fix position: Move the shape so it starts at origin
|
|
collision_shape.position = dir * (distance / 2)
|
|
|
|
|
|
func _process(delta):
|
|
# Update target positions for lightning bolts
|
|
for child in lightning:
|
|
if child is LightningBolt:
|
|
child.goal_point = collision_point if has_collided else target_position
|
|
|
|
# Update collision shape if it exists
|
|
update_collision_shape()
|
|
|
|
# Implement the body_entered signal handler
|
|
func _on_body_entered(body):
|
|
if ignore_target.has(body):
|
|
Log.pr("Ignoring body: ", body.name)
|
|
return
|
|
|
|
# Check if the colliding body is an enemy or object
|
|
if body.is_in_group("enemies"):
|
|
Log.pr("Hit enemy: ", body.name)
|
|
if not has_collided: # Only process the first collision
|
|
# Set collision state and point
|
|
has_collided = true
|
|
|
|
# Calculate the collision point
|
|
var direction_to_body = (body.global_position - global_position).normalized()
|
|
var body_radius = 10.0 # Adjust for your game
|
|
collision_point = body.global_position - (direction_to_body * body_radius)
|
|
Log.pr("Collision point updated to: ", collision_point)
|
|
|
|
# Debug output
|
|
Log.pr("Lightning hit: " + body.name + " at point: " + str(collision_point))
|
|
|
|
# IMPORTANT: Immediately update the collision shape to stop at collision point
|
|
update_collision_shape()
|
|
|
|
#_trigger_explosion()
|
|
|
|
|
|
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)
|
|
|
|
# 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()
|
|
self.call_deferred("_trigger_explosion")
|
|
|
|
# Emit signal for modifiers to react to
|
|
emit_signal("on_hit", self, body)
|
|
|
|
|
|
func _spawn_explosion_projectiles():
|
|
for i in range(explosion_projectile_count):
|
|
var max_target_distance = 200 # Maximum distance to look for enemies
|
|
|
|
# Get all enemies in the scene
|
|
var potential_targets = get_tree().get_nodes_in_group("enemies")
|
|
var valid_targets = []
|
|
|
|
# Filter enemies to only include ones within range
|
|
for enemy in potential_targets:
|
|
var distance = enemy.global_position.distance_to(collision_point)
|
|
if distance <= max_target_distance:
|
|
valid_targets.append(enemy)
|
|
|
|
var random_point = Vector2.ZERO
|
|
|
|
# Check if we have any valid targets
|
|
if valid_targets.size() > 0:
|
|
# Pick a random enemy from valid targets
|
|
var random_enemy = valid_targets[randi() % valid_targets.size()]
|
|
random_point = random_enemy.global_position
|
|
else:
|
|
return
|
|
|
|
Log.pr("Spawning explosion projectile")
|
|
var new_proj = (load(scene_file_path) as PackedScene).instantiate()
|
|
Log.pr("New projectile: ", new_proj)
|
|
|
|
new_proj.global_position = collision_point
|
|
Log.pr("New projectile spawn: ", new_proj.global_position)
|
|
|
|
|
|
new_proj.target_position = random_point
|
|
|
|
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
|
|
|
|
Log.pr("New projectile: ", new_proj)
|
|
|
|
# Add to scene tree
|
|
get_tree().root.call_deferred("add_child", new_proj)
|
|
|
|
func _on_lifetime_timeout():
|
|
super._on_lifetime_timeout()
|