forked from kanium/starcheese
Merge pull request 'event_bus' (#4) from Trugath/starcheese:event_bus into master
Reviewed-on: kanium/starcheese#4
This commit is contained in:
commit
44e0c54c6f
58
asteroid.gd
58
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)
|
||||
|
||||
31
asteroid.tscn
Normal file
31
asteroid.tscn
Normal file
@ -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")
|
||||
@ -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!")
|
||||
|
||||
10
damage_event.gd
Normal file
10
damage_event.gd
Normal file
@ -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"
|
||||
22
destroyed_event.gd
Normal file
22
destroyed_event.gd
Normal file
@ -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
|
||||
}
|
||||
43
eventbus/defaulteventbus.gd
Normal file
43
eventbus/defaulteventbus.gd
Normal file
@ -0,0 +1,43 @@
|
||||
class_name DefaultEventBus
|
||||
extends EventBus
|
||||
|
||||
var subscribers: Dictionary = {}
|
||||
|
||||
func _init():
|
||||
subscribers = {}
|
||||
|
||||
func subscribers_of(event_scope: EventScope, event_type: String) -> Array[Subscription]:
|
||||
var key = [event_scope, event_type]
|
||||
return subscribers.get(key, [])
|
||||
|
||||
func subscribe_to(event_scope: EventScope, event_type: String, fn: Callable) -> Subscription:
|
||||
var key = [event_scope, event_type]
|
||||
var subscriber_set: Array[EventBusSubscription] = subscribers.get(key, [] as Array[EventBusSubscription])
|
||||
var subscription = EventBusSubscription.new(key, fn, self)
|
||||
subscriber_set.append(subscription)
|
||||
subscribers[key] = subscriber_set
|
||||
return subscription
|
||||
|
||||
func publish(event_scope: EventScope, event: Event) -> void:
|
||||
var key = [event_scope, event.get_type()]
|
||||
var subscriber_set: Array[EventBusSubscription] = subscribers.get(key, [] as Array[EventBusSubscription]).duplicate(true)
|
||||
for subscriber in subscriber_set:
|
||||
var result = subscriber.callback.call(event)
|
||||
if result == EventResult.ResultType.DISPOSE_SUBSCRIPTION:
|
||||
subscriber.dispose()
|
||||
|
||||
func cancel_scope(event_scope: EventScope) -> void:
|
||||
var keys_to_cancel: Array = []
|
||||
for key in subscribers.keys():
|
||||
if key[0] == event_scope:
|
||||
keys_to_cancel.append(key)
|
||||
for key in keys_to_cancel:
|
||||
var subscriber_set: Array[EventBusSubscription] = subscribers[key]
|
||||
for subscriber in subscriber_set:
|
||||
subscriber.dispose()
|
||||
|
||||
func dispose() -> void:
|
||||
for subscriber_set in subscribers.values():
|
||||
for subscriber in subscriber_set:
|
||||
subscriber.dispose()
|
||||
subscribers.clear()
|
||||
2
eventbus/defaultscope.gd
Normal file
2
eventbus/defaultscope.gd
Normal file
@ -0,0 +1,2 @@
|
||||
class_name DefaultScope
|
||||
extends EventScope
|
||||
12
eventbus/event.gd
Normal file
12
eventbus/event.gd
Normal file
@ -0,0 +1,12 @@
|
||||
class_name Event
|
||||
extends RefCounted
|
||||
|
||||
var type: String
|
||||
var source: Variant
|
||||
|
||||
func _init(_source: Variant = null):
|
||||
source = _source
|
||||
type = self.get_class()
|
||||
|
||||
func get_type() -> String:
|
||||
return type
|
||||
17
eventbus/eventbus.gd
Normal file
17
eventbus/eventbus.gd
Normal file
@ -0,0 +1,17 @@
|
||||
class_name EventBus
|
||||
extends Node
|
||||
|
||||
func subscribers_of(_event_scope: EventScope, _event_type: String) -> Array[Subscription]:
|
||||
return Array()
|
||||
|
||||
func subscribe_to(_event_scope: EventScope, _event_type: String, _fn: Callable) -> Subscription:
|
||||
return Subscription.new()
|
||||
|
||||
func publish(_event_scope: EventScope, _event: Event) -> void:
|
||||
pass
|
||||
|
||||
func cancel_scope(_event_scope: EventScope) -> void:
|
||||
pass
|
||||
|
||||
func dispose() -> void:
|
||||
pass
|
||||
19
eventbus/eventbussubscription.gd
Normal file
19
eventbus/eventbussubscription.gd
Normal file
@ -0,0 +1,19 @@
|
||||
class_name EventBusSubscription
|
||||
extends Subscription
|
||||
|
||||
var key: Array
|
||||
var callback: Callable
|
||||
var bus: DefaultEventBus
|
||||
|
||||
func _init(_key: Array, _callback: Callable, _bus: DefaultEventBus):
|
||||
key = _key
|
||||
callback = _callback
|
||||
bus = _bus
|
||||
|
||||
func dispose() -> void:
|
||||
var subscriber_set: Array[EventBusSubscription] = bus.subscribers.get(key, [])
|
||||
subscriber_set.erase(self)
|
||||
if subscriber_set.is_empty():
|
||||
bus.subscribers.erase(key)
|
||||
else:
|
||||
bus.subscribers[key] = subscriber_set
|
||||
7
eventbus/eventresult.gd
Normal file
7
eventbus/eventresult.gd
Normal file
@ -0,0 +1,7 @@
|
||||
class_name EventResult
|
||||
extends RefCounted
|
||||
|
||||
enum ResultType {
|
||||
KEEP_SUBSCRIPTION,
|
||||
DISPOSE_SUBSCRIPTION
|
||||
}
|
||||
2
eventbus/eventscope.gd
Normal file
2
eventbus/eventscope.gd
Normal file
@ -0,0 +1,2 @@
|
||||
class_name EventScope
|
||||
extends Node
|
||||
5
eventbus/subscription.gd
Normal file
5
eventbus/subscription.gd
Normal file
@ -0,0 +1,5 @@
|
||||
class_name Subscription
|
||||
extends RefCounted
|
||||
|
||||
func dispose() -> void:
|
||||
pass
|
||||
10
input_event.gd
Normal file
10
input_event.gd
Normal file
@ -0,0 +1,10 @@
|
||||
class_name KeyboardInputEvent
|
||||
extends Event
|
||||
|
||||
var action: String
|
||||
var pressed: bool
|
||||
|
||||
func _init(_action: String, _pressed: bool):
|
||||
action = _action
|
||||
pressed = _pressed
|
||||
type = "KeyboardInputEvent"
|
||||
32
laser.gd
32
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)
|
||||
|
||||
80
main.gd
Normal file
80
main.gd
Normal file
@ -0,0 +1,80 @@
|
||||
extends Node
|
||||
|
||||
func _init() -> void:
|
||||
var node = WeaponsSystem.new()
|
||||
node.set_name("WeaponsSystem")
|
||||
add_child(node)
|
||||
|
||||
node = DefaultEventBus.new()
|
||||
node.set_name("MainEventBus")
|
||||
add_child(node)
|
||||
|
||||
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 = [
|
||||
"ui_fire",
|
||||
"ui_up",
|
||||
"ui_down",
|
||||
"ui_left",
|
||||
"ui_right",
|
||||
]
|
||||
for action in actions:
|
||||
if Input.is_action_pressed(action):
|
||||
get_node("/root/Main/MainEventBus").publish(get_node("/root/Main/InputEventScope"), KeyboardInputEvent.new(action, true))
|
||||
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
|
||||
65
main.tscn
65
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://weapons_system.gd" id="5_gf6oh"]
|
||||
[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,10 +17,8 @@ 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")
|
||||
|
||||
[node name="background" type="Sprite2D" parent="."]
|
||||
position = Vector2(955, 537)
|
||||
@ -29,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")
|
||||
@ -70,52 +67,14 @@ offset_top = -71.0
|
||||
offset_right = 104.0
|
||||
offset_bottom = -20.0
|
||||
|
||||
[node name="WeaponsSystem" type="Node" parent="spaceship"]
|
||||
script = ExtResource("5_gf6oh")
|
||||
|
||||
[node name="HardPoint1" type="Node2D" parent="spaceship"]
|
||||
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")
|
||||
|
||||
@ -12,7 +12,7 @@ config_version=5
|
||||
|
||||
config/name="Star Cheese - The Final Fromage"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.2", "Forward Plus")
|
||||
config/features=PackedStringArray("4.3", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[display]
|
||||
@ -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,"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)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
20
reward_spawner.gd
Normal file
20
reward_spawner.gd
Normal file
@ -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)
|
||||
25
spaceship.gd
25
spaceship.gd
@ -8,10 +8,12 @@ extends CharacterBody2D
|
||||
signal fire # Signal to start firing
|
||||
signal stop_fire # Signal to stop firing
|
||||
|
||||
var weapons_system
|
||||
|
||||
var weapons_system: WeaponsSystem
|
||||
var event_bus: EventBus
|
||||
func _ready():
|
||||
weapons_system = $WeaponsSystem
|
||||
weapons_system = get_node("/root/Main/WeaponsSystem")
|
||||
event_bus = get_node("/root/Main/MainEventBus")
|
||||
event_bus.subscribe_to(get_node("/root/Main/InputEventScope"), "KeyboardInputEvent", Callable(self, "handle_keyboard_input"))
|
||||
|
||||
func get_spaceship_orientation_vector() -> Vector2:
|
||||
return -global_transform.y
|
||||
@ -45,13 +47,14 @@ func handle_movement(delta: float) -> void:
|
||||
var collision_normal = collision.get_normal()
|
||||
velocity = velocity.slide(collision_normal)
|
||||
|
||||
func handle_weapons_input() -> void:
|
||||
if Input.is_action_pressed("ui_fire"):
|
||||
weapons_system.fire_all()
|
||||
|
||||
if Input.is_action_just_released("ui_fire"):
|
||||
weapons_system.cease_fire_all()
|
||||
|
||||
func handle_keyboard_input(event: KeyboardInputEvent):
|
||||
if( event.action == "ui_fire" ):
|
||||
if( event.pressed ):
|
||||
weapons_system.fire_all()
|
||||
else:
|
||||
weapons_system.cease_fire_all()
|
||||
|
||||
pass
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
handle_movement(delta)
|
||||
handle_weapons_input()
|
||||
|
||||
29
spawn_asteroid_button.gd
Normal file
29
spawn_asteroid_button.gd
Normal file
@ -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
|
||||
6
tests.tscn
Normal file
6
tests.tscn
Normal file
@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dxxijo7vef7or"]
|
||||
|
||||
[ext_resource type="Script" path="res://tests/tests.gd" id="1_dngg8"]
|
||||
|
||||
[node name="tests" type="Node"]
|
||||
script = ExtResource("1_dngg8")
|
||||
105
tests/test_eventbus.gd
Normal file
105
tests/test_eventbus.gd
Normal file
@ -0,0 +1,105 @@
|
||||
# res://tests/test_eventbus.gd
|
||||
class_name EventBusTests
|
||||
extends Node
|
||||
|
||||
func _ready():
|
||||
run_tests()
|
||||
|
||||
func run_tests():
|
||||
test_subscribe_and_publish()
|
||||
test_dispose_subscription()
|
||||
test_cancel_scope()
|
||||
test_multiple_subscribers()
|
||||
|
||||
# Test function: Test subscribing and publishing events
|
||||
func test_subscribe_and_publish() -> void:
|
||||
var bus: DefaultEventBus = DefaultEventBus.new()
|
||||
var scope: DefaultScope = DefaultScope.new()
|
||||
var event_received: Flag = Flag.new()
|
||||
|
||||
var event_handler = func(_event: Event) -> int:
|
||||
event_received.value = true
|
||||
return EventResult.ResultType.KEEP_SUBSCRIPTION
|
||||
|
||||
bus.subscribe_to(scope, "TestEvent", event_handler)
|
||||
var event: TestEvent = TestEvent.new(self)
|
||||
bus.publish(scope, event)
|
||||
|
||||
# Assert that the event was received
|
||||
assert(event_received.value == true, "Event was not received by subscriber")
|
||||
bus.dispose()
|
||||
|
||||
# Test function: Test disposing of a subscription after handling an event
|
||||
func test_dispose_subscription() -> void:
|
||||
var bus: DefaultEventBus = DefaultEventBus.new()
|
||||
var scope: DefaultScope = DefaultScope.new()
|
||||
var event_received_times: Counter = Counter.new()
|
||||
|
||||
var event_handler = func(_event: Event) -> int:
|
||||
event_received_times.value += 1
|
||||
return EventResult.ResultType.DISPOSE_SUBSCRIPTION
|
||||
|
||||
bus.subscribe_to(scope, "TestEvent", event_handler)
|
||||
var event: TestEvent = TestEvent.new(self)
|
||||
bus.publish(scope, event)
|
||||
bus.publish(scope, event) # Publish a second time
|
||||
|
||||
# Assert that the event handler was called only once
|
||||
assert(event_received_times.value == 1, "Event handler should have been called only once due to disposal")
|
||||
bus.dispose()
|
||||
|
||||
# Test function: Test canceling an event scope
|
||||
func test_cancel_scope() -> void:
|
||||
var bus: DefaultEventBus = DefaultEventBus.new()
|
||||
var scope: DefaultScope = DefaultScope.new()
|
||||
var event_received: Flag = Flag.new()
|
||||
|
||||
var event_handler = func(_event: Event) -> int:
|
||||
event_received.value = true
|
||||
return EventResult.ResultType.KEEP_SUBSCRIPTION
|
||||
|
||||
bus.subscribe_to(scope, "TestEvent", event_handler)
|
||||
bus.cancel_scope(scope)
|
||||
var event: TestEvent = TestEvent.new(self)
|
||||
bus.publish(scope, event)
|
||||
|
||||
# Assert that the event was not received after scope cancellation
|
||||
assert(event_received.value == false, "Event should not have been received after scope cancellation")
|
||||
bus.dispose()
|
||||
|
||||
|
||||
# Test function: Test multiple subscribers receiving the same event
|
||||
func test_multiple_subscribers() -> void:
|
||||
var bus: DefaultEventBus = DefaultEventBus.new()
|
||||
var scope: DefaultScope = DefaultScope.new()
|
||||
var event_received_by_handler1: Flag = Flag.new()
|
||||
var event_received_by_handler2: Flag = Flag.new()
|
||||
|
||||
var event_handler1 = func(_event: Event) -> int:
|
||||
event_received_by_handler1.value = true
|
||||
return EventResult.ResultType.KEEP_SUBSCRIPTION
|
||||
|
||||
var event_handler2 = func(_event: Event) -> int:
|
||||
event_received_by_handler2.value = true
|
||||
return EventResult.ResultType.KEEP_SUBSCRIPTION
|
||||
|
||||
bus.subscribe_to(scope, "TestEvent", event_handler1)
|
||||
bus.subscribe_to(scope, "TestEvent", event_handler2)
|
||||
var event: TestEvent = TestEvent.new(self)
|
||||
bus.publish(scope, event)
|
||||
|
||||
# Assert that both handlers received the event
|
||||
assert(event_received_by_handler1.value == true, "First handler did not receive event")
|
||||
assert(event_received_by_handler2.value == true, "Second handler did not receive event")
|
||||
bus.dispose()
|
||||
|
||||
class Flag:
|
||||
var value = false
|
||||
|
||||
class Counter:
|
||||
var value = 0
|
||||
|
||||
class TestEvent extends Event:
|
||||
func _init(_source: Variant = null) -> void:
|
||||
super(_source)
|
||||
type = "TestEvent"
|
||||
8
tests/tests.gd
Normal file
8
tests/tests.gd
Normal file
@ -0,0 +1,8 @@
|
||||
extends Node
|
||||
|
||||
func _ready() -> void:
|
||||
EventBusTests.run_tests()
|
||||
get_tree().quit()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
pass
|
||||
@ -1,3 +1,4 @@
|
||||
class_name WeaponsSystem
|
||||
extends Node
|
||||
|
||||
var weapons = []
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user