145 lines
4.5 KiB
GDScript
145 lines
4.5 KiB
GDScript
extends RigidBody2D
|
||
|
||
@export var speed = 400
|
||
@export var explosion_damage = 600
|
||
|
||
var velocity = Vector2.ZERO
|
||
var is_in_flight = false
|
||
var has_exploded = false # Flag to track if the bomb has exploded
|
||
|
||
@onready var sprite = $Sprite2D
|
||
@onready var collision = $CollisionShape2D
|
||
@onready var particles = $Explosion
|
||
@onready var explosion_sound = $AudioStreamPlayer2D
|
||
@onready var explosion_area = $ExplosionArea
|
||
@onready var timer = $Timer
|
||
@onready var camera = get_parent().get_parent().get_node("MultiTargetCamera")
|
||
@onready var tile_map_layer = get_parent().get_parent().get_node("TileMapLayer")
|
||
@export var off_screen_margin = 2000
|
||
|
||
# Called when the node enters the scene tree for the first time.
|
||
func _ready() -> void:
|
||
camera.add_target(self)
|
||
|
||
global_position = position
|
||
z_index = -1
|
||
# Disable the particles and audio on start
|
||
particles.emitting = false
|
||
explosion_sound.playing = false
|
||
|
||
# Connect the timer's timeout signal to the cleanup function
|
||
timer.connect("timeout", _on_timeout)
|
||
|
||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||
func _process(delta: float) -> void:
|
||
if is_in_flight:
|
||
# Explode if the bomb goes off-screen
|
||
if is_off_screen() and not has_exploded:
|
||
trigger_explosion()
|
||
|
||
# This function is used to set the velocity of the bomb when it’s thrown
|
||
func set_velocity(new_velocity: Vector2) -> void:
|
||
# Apply an impulse based on the new velocity
|
||
apply_central_impulse(new_velocity)
|
||
is_in_flight = true
|
||
|
||
|
||
# Function to trigger the explosion
|
||
func trigger_explosion():
|
||
if has_exploded:
|
||
return # Prevent multiple explosions
|
||
|
||
# Set the flag to true, indicating that the bomb has exploded
|
||
has_exploded = true
|
||
|
||
camera.remove_target(self)
|
||
|
||
# Play the explosion sound
|
||
explosion_sound.play()
|
||
|
||
# Enable and emit the particles
|
||
particles.emitting = true
|
||
|
||
# Push away players within the explosion radius
|
||
push_away_players()
|
||
|
||
# Destroy tiles in the explosion radius
|
||
destroy_tiles_in_explosion_area()
|
||
|
||
tile_map_layer.detect_and_make_tiles_fall()
|
||
|
||
# Start the timer to cleanup the explosion
|
||
timer.start()
|
||
|
||
sprite.hide()
|
||
|
||
func push_away_players():
|
||
if not explosion_area:
|
||
print("ExplosionArea2D is missing!")
|
||
return
|
||
|
||
var overlapping_bodies = explosion_area.get_overlapping_bodies()
|
||
print("Overlapping bodies:", overlapping_bodies)
|
||
|
||
|
||
for body in overlapping_bodies:
|
||
if body is RigidBody2D:
|
||
print("Pushing body:", body.name)
|
||
|
||
var direction = (body.global_position - global_position).normalized()
|
||
var impulse = direction * explosion_damage
|
||
body.apply_central_impulse(impulse)
|
||
|
||
func destroy_tiles_in_explosion_area():
|
||
var center = global_position # Explosion center in global coordinates
|
||
var radius = 150 # Explosion radius in pixels
|
||
|
||
# Convert center to map coordinates
|
||
var map_center = tile_map_layer.local_to_map(center)
|
||
print("Explosion center in map coordinates:", center, map_center)
|
||
|
||
# Tile dimensions
|
||
var tile_width = 16
|
||
var tile_height = 16
|
||
|
||
# Calculate bounds of explosion in tile coordinates
|
||
var min_x = int((center.x - radius) / tile_width)
|
||
var max_x = int((center.x + radius) / tile_width)
|
||
var min_y = int((center.y - radius) / tile_height)
|
||
var max_y = int((center.y + radius) / tile_height)
|
||
|
||
print("Explosion bounds in tile coordinates: ", Vector2i(min_x, min_y), Vector2i(max_x, max_y))
|
||
|
||
# Loop through the affected tiles
|
||
for x in range(min_x, max_x + 1):
|
||
for y in range(min_y, max_y + 1):
|
||
# Calculate the distance from the explosion center to the tile center
|
||
var tile_pos = tile_map_layer.map_to_local(Vector2i(x, y))
|
||
var dist = center.distance_to(tile_pos)
|
||
|
||
# Check if the tile is within the explosion radius
|
||
if dist <= radius:
|
||
print("Checking tile at:", Vector2i(x, y), "Distance:", dist)
|
||
print(tile_map_layer.get_cell_source_id(Vector2i(x, y)))
|
||
|
||
# Erase the tile if it exists
|
||
if tile_map_layer.get_cell_source_id(Vector2i(x, y)) != -1:
|
||
tile_map_layer.erase_cell(Vector2i(x, y))
|
||
print("Erased tile at:", Vector2i(x, y))
|
||
|
||
|
||
# Function to check if the bomb is off-screen
|
||
func is_off_screen() -> bool:
|
||
var screen_rect = Rect2(camera.position - camera.zoom * camera.get_viewport_rect().size / 2,
|
||
camera.zoom * camera.get_viewport_rect().size)
|
||
screen_rect = screen_rect.grow(off_screen_margin) # Expand the screen rectangle by the margin
|
||
return not screen_rect.has_point(global_position)
|
||
|
||
# Cleanup function called when the timer times out
|
||
func _on_timeout():
|
||
# Once the timer finishes, queue the particles for cleanup (optional)
|
||
particles.emitting = false
|
||
explosion_sound.stop() # Stop the sound if it's still playing
|
||
|
||
queue_free()
|