randomgeon/player/weapons/projectile_lightning.gd

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()