diff --git a/asteroid.gd b/asteroid.gd index 3d373af..d4accb5 100644 --- a/asteroid.gd +++ b/asteroid.gd @@ -1,43 +1,41 @@ extends StaticBody2D -@export var max_health: float = 100.0 # Maximum health for the asteroid +@export var max_health: float = 100.0 var current_health: float -var is_destroyed: bool = false # Track if the asteroid has already been destroyed +var is_destroyed: bool = false +var event_bus: EventBus func _ready(): current_health = max_health - update_health_label() # Update the health display when the game starts + event_bus = get_node("/root/Main/MainEventBus") + event_bus.subscribe_to(get_node("/root/Main/DamageEventScope"), "DamageEvent", Callable(self, "on_damage_event")) + add_to_group("asteroids") + update_health_label() -# Function to handle taking damage -func take_damage(damage: float): - if is_destroyed: # Prevent taking damage if already destroyed - return +func on_damage_event(event: DamageEvent) -> EventResult.ResultType: + if event.target != self or is_destroyed: + return EventResult.ResultType.KEEP_SUBSCRIPTION + + apply_damage(event.damage_value) - current_health -= damage # Subtract the damage from current health - current_health = max(current_health, 0) # Ensure health doesn't drop below 0 - update_health_label() # Update the label to reflect new health value - if current_health <= 0.0: - break_apart() - -# Function to handle when the asteroid is destroyed -func break_apart(): - is_destroyed = true # Mark the asteroid as destroyed - queue_free() # Remove the asteroid from the scene - print("Asteroid mined!") + emit_asteroid_destroyed() + return EventResult.ResultType.DISPOSE_SUBSCRIPTION - # Load the Cheese scene - var cheese_scene = load("res://Cheese.tscn") - - # Instance the cheese - var cheese_instance = cheese_scene.instantiate() - - # Set the position where the cheese should spawn (at the asteroid's position) - cheese_instance.global_position = global_position + Vector2(randf() * 50 - 25, randf() * 50 - 25) + return EventResult.ResultType.KEEP_SUBSCRIPTION - # Add the cheese instance to the scene - get_parent().add_child(cheese_instance) +func apply_damage(damage: float) -> void: + current_health = max(current_health - damage, 0) + update_health_label() -# Function to update the health label display -func update_health_label(): +func emit_asteroid_destroyed() -> void: + is_destroyed = true + queue_free() + publish_destroyed_event() + +func publish_destroyed_event() -> void: + var destroyed_event = DestroyedEvent.new(self, "asteroid", global_position, "laser") + event_bus.publish(get_node("/root/Main/DestroyedEventScope"), destroyed_event) + +func update_health_label() -> void: $AsteroidHealthLabel.text = str(round(current_health)) + " / " + str(max_health) diff --git a/asteroid.tscn b/asteroid.tscn new file mode 100644 index 0000000..21b0f73 --- /dev/null +++ b/asteroid.tscn @@ -0,0 +1,31 @@ +[gd_scene load_steps=4 format=3 uid="uid://dcq5a8tewppk1"] + +[ext_resource type="Script" path="res://asteroid.gd" id="1_spmxj"] +[ext_resource type="Texture2D" uid="uid://buirp1h6onqai" path="res://images/AsteroidBrown.png" id="2_hb7w5"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_w58nc"] +radius = 86.093 + +[node name="asteroid" type="StaticBody2D"] +position = Vector2(564, 144) +collision_mask = 2 +script = ExtResource("1_spmxj") + +[node name="Sprite2D" type="Sprite2D" parent="."] +position = Vector2(1.00006, -3.99998) +scale = Vector2(1.2, 1.181) +texture = ExtResource("2_hb7w5") + +[node name="AsteroidCollisionPolygon2D" type="CollisionPolygon2D" parent="."] +position = Vector2(-519, -164) +polygon = PackedVector2Array(548, 101, 613, 169, 597, 210, 548, 240, 462, 221, 431, 184, 434, 133, 497, 90) + +[node name="AsteroidHealthLabel" type="Label" parent="."] +offset_left = 105.0 +offset_top = 38.0 +offset_right = 181.0 +offset_bottom = 80.0 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(0, 2) +shape = SubResource("CircleShape2D_w58nc") diff --git a/cheeseCollision.gd b/cheeseCollision.gd index ebaadf4..8ad7ea2 100644 --- a/cheeseCollision.gd +++ b/cheeseCollision.gd @@ -1,18 +1,12 @@ extends Area2D - - func _ready(): - pass # Replace with function body. + pass - -# Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): pass - func _on_body_entered(body): if body.name == "spaceship": - queue_free() # This removes the cheese from the scene - print("Cheese collected!") # Replace this with actual game logic - + queue_free() + print("Cheese collected!") diff --git a/damage_event.gd b/damage_event.gd new file mode 100644 index 0000000..569cab2 --- /dev/null +++ b/damage_event.gd @@ -0,0 +1,10 @@ +class_name DamageEvent +extends Event + +var damage_value: float +var target: Node + +func _init(_damage_value: float, _target: Node): + damage_value = _damage_value + target = _target + type = "DamageEvent" diff --git a/destroyed_event.gd b/destroyed_event.gd new file mode 100644 index 0000000..b163a89 --- /dev/null +++ b/destroyed_event.gd @@ -0,0 +1,22 @@ +class_name DestroyedEvent +extends Event + +var destroyed_object: Node +var object_type: String +var position: Vector2 +var destruction_cause: String + +func _init(_destroyed_object: Node, _object_type: String, _position: Vector2, _destruction_cause: String = ""): + destroyed_object = _destroyed_object + object_type = _object_type + position = _position + destruction_cause = _destruction_cause + type = "DestroyedEvent" + +func get_event_details() -> Dictionary: + return { + "object": destroyed_object, + "type": object_type, + "position": position, + "cause": destruction_cause + } diff --git a/laser.gd b/laser.gd index 27068be..4b716b4 100644 --- a/laser.gd +++ b/laser.gd @@ -7,12 +7,14 @@ extends Node2D var hardpoint = null # Reference to the attached hardpoint var is_firing = false # Track the laser's firing state var current_damage_output: float = 0.0 # Track the current damage output +var event_bus: EventBus func _ready(): # Register the laser to the "weapons" group add_to_group("weapons") # Connect to the correct hardpoint when ready call_deferred("_connect_to_hardpoint") + event_bus = get_node("/root/Main/MainEventBus") # Initialize LaserLine2D with two points (origin and target) $LaserLine2D.clear_points() @@ -32,16 +34,16 @@ func _connect_to_hardpoint(): func fire(): is_firing = true + current_damage_output = laser_damage + $DamageOutputLabel.text = str(current_damage_output) _process_laser(true) - current_damage_output = laser_damage - $DamageOutputLabel.text = str(current_damage_output) func cease_fire(): is_firing = false + current_damage_output = 0.0 + $DamageOutputLabel.text = str(current_damage_output) _process_laser(false) - current_damage_output = 0.0 - $DamageOutputLabel.text = str(current_damage_output) func _process(delta: float) -> void: if is_firing: @@ -52,27 +54,21 @@ func _process_laser(active: bool): var raycast = $LaserBeam2D raycast.enabled = active - if active: - raycast.force_raycast_update() if raycast.is_colliding(): - var collision_point = raycast.get_collision_point() - $LaserLine2D.set_point_position(0, Vector2.ZERO) - $LaserLine2D.set_point_position(1, to_local(collision_point)) - + $LaserLine2D.set_point_position(0, Vector2.ZERO) + $LaserLine2D.set_point_position(1, to_local(collision_point)) var collider = raycast.get_collider() - if collider.has_method("take_damage"): - collider.take_damage(laser_damage) + if collider: + var damage_event = DamageEvent.new(laser_damage, collider) + event_bus.publish(get_node("/root/Main/DamageEventScope"), damage_event) else: - - $LaserLine2D.set_point_position(0, Vector2.ZERO) - $LaserLine2D.set_point_position(1, Vector2(0, -laser_range)) + $LaserLine2D.set_point_position(1, Vector2(0, -laser_range)) else: - $LaserLine2D.clear_points() - $LaserLine2D.add_point(Vector2.ZERO) # Re-add the origin point - $LaserLine2D.add_point(Vector2.ZERO) # Reset target point to origin + $LaserLine2D.add_point(Vector2.ZERO) + $LaserLine2D.add_point(Vector2.ZERO) diff --git a/main.gd b/main.gd index aa8774f..ebb22cf 100644 --- a/main.gd +++ b/main.gd @@ -12,12 +12,24 @@ func _init() -> void: node = EventScope.new() node.set_name("InputEventScope") add_child(node) + + node = EventScope.new() + node.set_name("DamageEventScope") + add_child(node) + + node = EventScope.new() + node.set_name("DestroyedEventScope") + add_child(node) + + # Instantiate and add the RewardSpawner + node = RewardSpawner.new() + node.set_name("RewardSpawner") + add_child(node) # Called when the node enters the scene tree for the first time. func _ready() -> void: pass # Replace with function body. - # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta: float) -> void: var actions = [ @@ -33,3 +45,36 @@ func _process(delta: float) -> void: elif Input.is_action_just_released(action): get_node("/root/Main/MainEventBus").publish(get_node("/root/Main/InputEventScope"), KeyboardInputEvent.new(action, false)) pass + +# Spawn function and random position logic are placed here +func spawn_asteroid(): + var asteroid_scene = preload("res://asteroid.tscn") + var asteroid_instance = asteroid_scene.instantiate() + + # Generate random positions within a defined area + var spawn_position = get_random_position() + + # Check that it's not too close to the player or other asteroids + while !is_valid_position(spawn_position): + spawn_position = get_random_position() + + asteroid_instance.global_position = spawn_position + add_child(asteroid_instance) + +func get_random_position() -> Vector2: + var screen_size = get_viewport().size + return Vector2(randf_range(0, screen_size.x), randf_range(0, screen_size.y)) + +func is_valid_position(spawn_position: Vector2) -> bool: + var player = get_node("spaceship") # Adjust the path to your player node + var player_distance = player.global_position.distance_to(spawn_position) + + if player_distance < 200: + return false + + var asteroids = get_tree().get_nodes_in_group("asteroids") + for asteroid in asteroids: + if asteroid.global_position.distance_to(spawn_position) < 150: + return false + + return true diff --git a/main.tscn b/main.tscn index 6cff3f0..122934a 100644 --- a/main.tscn +++ b/main.tscn @@ -1,14 +1,13 @@ -[gd_scene load_steps=13 format=3 uid="uid://8ocp10j32f62"] +[gd_scene load_steps=11 format=3 uid="uid://8ocp10j32f62"] [ext_resource type="Script" path="res://main.gd" id="1_eedai"] [ext_resource type="Texture2D" uid="uid://y6phkg4twpdm" path="res://images/bg_space_seamless.png" id="1_rpyi5"] [ext_resource type="Texture2D" uid="uid://cran7fr1i2qou" path="res://images/spaceship-placeholder.png" id="2_f2x66"] [ext_resource type="Script" path="res://spaceship.gd" id="3_ttkgl"] [ext_resource type="Script" path="res://laser.gd" id="4_uhf7q"] -[ext_resource type="Script" path="res://asteroid.gd" id="6_n4dsl"] [ext_resource type="Texture2D" uid="uid://bxgw2u7j4b634" path="res://images/laser_turret.png" id="6_qxhyw"] -[ext_resource type="Texture2D" uid="uid://buirp1h6onqai" path="res://images/AsteroidBrown.png" id="7_0tjls"] [ext_resource type="Script" path="res://hardpoint.gd" id="7_6cr6a"] +[ext_resource type="Script" path="res://spawn_asteroid_button.gd" id="9_21dg0"] [sub_resource type="CapsuleShape2D" id="CapsuleShape2D_3vtwu"] radius = 48.0 @@ -18,9 +17,6 @@ height = 102.0 offsets = PackedFloat32Array(0.961735, 1) colors = PackedColorArray(1, 1, 0, 1, 1, 1, 1, 0.137255) -[sub_resource type="CircleShape2D" id="CircleShape2D_w58nc"] -radius = 88.0057 - [node name="Main" type="Node2D"] script = ExtResource("1_eedai") @@ -30,7 +26,7 @@ scale = Vector2(2, 2) texture = ExtResource("1_rpyi5") [node name="spaceship" type="CharacterBody2D" parent="."] -position = Vector2(908, 835) +position = Vector2(956, 623) collision_layer = 2 motion_mode = 1 script = ExtResource("3_ttkgl") @@ -75,45 +71,10 @@ offset_bottom = -20.0 position = Vector2(0, -46) script = ExtResource("7_6cr6a") -[node name="asteroid" type="StaticBody2D" parent="."] -position = Vector2(564, 144) -collision_mask = 2 -script = ExtResource("6_n4dsl") - -[node name="Sprite2D" type="Sprite2D" parent="asteroid"] -position = Vector2(1.00006, -3.99998) -scale = Vector2(1.2, 1.181) -texture = ExtResource("7_0tjls") - -[node name="AsteroidCollisionPolygon2D" type="CollisionPolygon2D" parent="asteroid"] -position = Vector2(-519, -164) -polygon = PackedVector2Array(548, 101, 613, 169, 597, 210, 548, 240, 462, 221, 431, 184, 434, 133, 497, 90) - -[node name="AsteroidHealthLabel" type="Label" parent="asteroid"] -offset_left = 105.0 -offset_top = 38.0 -offset_right = 181.0 -offset_bottom = 80.0 - -[node name="CollisionShape2D" type="CollisionShape2D" parent="asteroid"] -position = Vector2(-2, 1) -shape = SubResource("CircleShape2D_w58nc") - -[node name="asteroid2" type="StaticBody2D" parent="."] -position = Vector2(1405, 413) -script = ExtResource("6_n4dsl") - -[node name="Sprite2D" type="Sprite2D" parent="asteroid2"] -position = Vector2(1.00006, -3.99998) -scale = Vector2(1.2, 1.181) -texture = ExtResource("7_0tjls") - -[node name="AsteroidCollisionPolygon2D" type="CollisionPolygon2D" parent="asteroid2"] -position = Vector2(-519, -164) -polygon = PackedVector2Array(548, 101, 613, 169, 597, 210, 548, 240, 462, 221, 431, 184, 434, 133, 497, 90) - -[node name="AsteroidHealthLabel" type="Label" parent="asteroid2"] -offset_left = 105.0 -offset_top = 38.0 -offset_right = 181.0 -offset_bottom = 80.0 +[node name="SpawnAsteroidButton" type="Button" parent="."] +offset_left = 72.0 +offset_top = 993.0 +offset_right = 249.0 +offset_bottom = 1049.0 +text = "SPAWN ASTEROID" +script = ExtResource("9_21dg0") diff --git a/project.godot b/project.godot index bcda1c8..bbc0fb8 100644 --- a/project.godot +++ b/project.godot @@ -24,7 +24,7 @@ window/size/viewport_height=1080 ui_fire={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } diff --git a/reward_spawner.gd b/reward_spawner.gd new file mode 100644 index 0000000..57c3e3c --- /dev/null +++ b/reward_spawner.gd @@ -0,0 +1,20 @@ +class_name RewardSpawner +extends Node + +var event_bus: EventBus + +func _ready(): + event_bus = get_node("/root/Main/MainEventBus") + event_bus.subscribe_to(get_node("/root/Main/DestroyedEventScope"), "DestroyedEvent", Callable(self, "on_destroyed")) + +func on_destroyed(event: DestroyedEvent): + if event.object_type == "asteroid": + spawn_cheese(event.position) + +func spawn_cheese(position: Vector2): + var cheese_scene = load("res://cheese.tscn") + var cheese_instance = cheese_scene.instantiate() + + cheese_instance.global_position = position + Vector2(randf() * 50 - 25, randf() * 50 - 25) + + get_parent().add_child(cheese_instance) diff --git a/spawn_asteroid_button.gd b/spawn_asteroid_button.gd new file mode 100644 index 0000000..5a489df --- /dev/null +++ b/spawn_asteroid_button.gd @@ -0,0 +1,29 @@ +extends Button + +@onready var main_script = get_node("/root/Main") + +func _ready(): + # Connect the "pressed" signal to a custom function in this script + self.pressed.connect(self.on_button_pressed) + +# Handle what happens when the button is pressed +func on_button_pressed(): + # Call the main script's spawn_asteroid function + main_script.spawn_asteroid() + + # Disable the button temporarily to prevent immediate re-trigger + self.disabled = true + + self.release_focus() + + # Start a timer to re-enable the button after 0.2 seconds + var timer = Timer.new() + timer.wait_time = 0.2 + timer.one_shot = true + timer.timeout.connect(self.on_timeout) + add_child(timer) + timer.start() + +# Re-enable the button when the timer times out +func on_timeout(): + self.disabled = false