Compare commits

..

20 commits

Author SHA1 Message Date
Henry
b5d97c0ffb Fixed shield issue by removing old experiments and ensuring the right
values were being used!
2025-12-27 16:25:06 +00:00
Henry
c8d578af04 Enemy spawning code now reference COLS and ROWS constants; removed
extraneous enemy_count removal.
2025-12-27 10:08:30 +00:00
Henry
dac1601f4a Troubleshooting enemy count. 2025-12-24 16:48:40 +00:00
Henry
25a4897697 Tracking down the spawning of extra enemies; removed extraneous enemy
counting and queue_free of enemies.
2025-12-24 15:59:15 +00:00
Henry
be3919acd7 Commented main game's functionality to better track what's happening. 2025-12-24 13:29:59 +00:00
Henry
aa7cdc90d6 Trying to sort shield issues. 2025-12-23 18:48:49 +00:00
Henry
a007b08b83 Removed Player from the Main scene in favor of instantiatiating Player
during the start of a new game.
2025-12-23 16:27:48 +00:00
Henry
a20e496c2e Enemies now stay on screen after player dies, until start of new game. 2025-12-23 14:28:35 +00:00
Henry
ec7a84c252 Added shoot-to-start game code, re-ordered starting sequence using
"playing" variable.
2025-12-23 10:38:27 +00:00
Henry
099440d27f Player now comes up from the bottom of the screen on a new game. 2025-12-20 19:37:32 +00:00
Henry
dec3cbe595 Set up new signals in EventBus; preparing to restructure game start
code.
2025-12-20 09:15:59 +00:00
Henry
7ef6076eda Removed extraneous enemy_died signal from spawning; used
get_nodes_in_group for enemy_count
2025-12-17 19:17:46 +00:00
Henry
485f03d702 Fixed signals; removed most extra debug output. Still issues with
shieldbar showing accurate damage, but functionality of main branch
restored.
2025-12-17 09:19:01 +00:00
Henry
a73fb28552 Troubleshooting player_died signal. 2025-12-16 23:19:03 +00:00
Henry
afc5c68569 Fixed _on_shield_changed logic to smoothly tween shield bar. Added a
function call to trigger shader to flash shield bar.
2025-12-16 13:09:52 +00:00
Henry
9f2569a73c Identified @export variables as int, float and the game started again! 2025-12-16 09:25:40 +00:00
Henry
65a887e9db Fixed an issue with a signal for cool down; still having an issue with
wait_time and vector2 controlling movement.
2025-12-16 00:05:26 +00:00
Henry
d739beb6f2 Cleaned up @export and @onready ordering; commented out unfinished
features.
2025-12-15 12:03:13 +00:00
Henry
1ebba28e5d Updated event_bus to have shield change single; attempted to update
player's set shield but running into problems at runtime.
2025-12-15 10:20:23 +00:00
Henry
d64504189a Branch for signal refactoring, singleton bus. 2025-12-14 20:32:23 +00:00
16 changed files with 304 additions and 96 deletions

View file

@ -1,13 +1,14 @@
extends Area2D
signal died
var bullet_scene = preload("res://enemy_bullet.tscn")
var start_pos = Vector2.ZERO
var speed = 0
var exploding = false
@onready var screensize = get_viewport_rect().size
func start(pos):
speed = 0
position = Vector2(pos.x, -pos.y)
@ -21,6 +22,7 @@ func start(pos):
$ShootTimer.wait_time = randf_range(4, 20)
$ShootTimer.start()
func _on_timer_timeout() -> void:
speed = randf_range(75, 100)
@ -38,9 +40,13 @@ func _process(delta):
func explode():
if exploding: return
exploding = true
print_debug("Enemy explode!")
EventBus.enemy_hit.emit(5)
speed = 0
$AnimationPlayer.play("explode")
set_deferred("monitoring", false)
died.emit(5)
await $AnimationPlayer.animation_finished
queue_free()
EventBus.enemy_died.emit()

12
event_bus.gd Normal file
View file

@ -0,0 +1,12 @@
extends Node
@warning_ignore_start("unused_signal") # since otherwise Godot will throw a warning that the signal is unused in current scope
signal shield_changed(max_value: int, old_value: int, new_value: int)
signal player_died()
signal enemy_died()
signal enemy_hit(value: int)
signal initialize_shieldbar()
signal start_game()
@warning_ignore_restore("unused_signal") # put any future signals you add between the two ignore annotations

1
event_bus.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://jibpipn2p1c7

View file

@ -2,6 +2,21 @@
[ext_resource type="Texture2D" uid="uid://h04wm5a27u0" path="res://Mini Pixel Pack 3/Effects/Explosion (16 x 16).png" id="1_q7epf"]
[sub_resource type="Animation" id="Animation_j4sxf"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:frame")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [0]
}
[sub_resource type="Animation" id="Animation_vxas0"]
resource_name = "explosion-one-shot"
length = 0.5
@ -19,21 +34,6 @@ tracks/0/keys = {
"values": [0, 1, 3, 4, 5]
}
[sub_resource type="Animation" id="Animation_j4sxf"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath(".:frame")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_m5xho"]
_data = {
&"RESET": SubResource("Animation_j4sxf"),
@ -48,4 +48,4 @@ hframes = 6
libraries = {
&"": SubResource("AnimationLibrary_m5xho")
}
autoplay = "explosion-one-shot"
autoplay = "RESET"

6
global.gd Normal file
View file

@ -0,0 +1,6 @@
extends Node
# Global Game variables
var score: int = 0
var new_game = true
var playing = false

1
global.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://dhfukspc2nyu0

108
main.gd
View file

@ -1,42 +1,116 @@
extends Node2D
var enemy = preload("res://enemy.tscn")
var player = preload("res://player.tscn")
var instance = null
var playing = false
var enemy_count: int = 0:
set(value):
if value < 0:
print_debug("Enemy value set to below zero: ", get_stack())
if value > 27:
print_debug("Enemy value set to above 27!: ", get_stack())
enemy_count = value
const COLS: int = 9
const ROWS: int = 3
@onready var start_button = $CanvasLayer/CenterContainer/Start
@onready var game_over = $CanvasLayer/CenterContainer/GameOver
var enemy = preload("res://enemy.tscn")
var score = 0
func _ready():
start_button.show()
game_over.hide()
# spawn_enemies()
start_button.show()
EventBus.player_died.connect(_on_player_died)
EventBus.enemy_died.connect(_on_enemy_died)
EventBus.enemy_hit.connect(_on_enemy_hit)
func new_game():
score = 0
$CanvasLayer/UI.update_score(score)
$Player.start()
spawn_enemies()
func spawn_enemies():
for x in range(9):
for y in range(3):
# print("Remaining enemies: ", enemy_count)
# await get_tree().process_frame
for x in range(COLS):
for y in range(ROWS):
var e = enemy.instantiate()
var pos = Vector2(x * (16 + 8) + 24, 16 * 4 + y * 16)
add_child(e)
e.start(pos)
e.died.connect(_on_enemy_died)
enemy_count = ROWS * COLS
await get_tree().process_frame
print_debug("Remaining enemies: ", enemy_count, ", ", get_tree().get_nodes_in_group("enemies").size())
func _on_enemy_died(value):
score += value
$CanvasLayer/UI.update_score(score)
func _on_enemy_died():
enemy_count -= 1
print_debug(enemy_count)
if enemy_count == 0:
print_debug("Remaining enemies: ", enemy_count, ", ", get_tree().get_nodes_in_group("enemies").size())
win_game()
func _on_enemy_hit(value: int):
Global.score += value
$CanvasLayer/UI.update_score(Global.score)
func _on_player_died():
get_tree().call_group("enemies", "queue_free")
# get_tree().call_group("enemies", "queue_free")
# $Player.set_process(false)
# get_tree().call_group("enemies", "set_process", false)
enemy_win()
instance.queue_free()
game_over.show()
await get_tree().create_timer(2).timeout
game_over.hide()
start_button.show()
playing = false
func new_game():
# Ensure enemies are cleared.
get_tree().call_group("enemies", "queue_free")
get_tree().call_group("enemy_bullets", "queue_free")
# print("Number of enemies at new_game: ",enemy_count)
enemy_count = 0
await get_tree().process_frame
# Reset score.
Global.score = 0
$CanvasLayer/UI.update_score(Global.score)
# Tell the shield to recharge.
# EventBus.initialize_shieldbar.emit()
# await EventBus.initialize_shieldbar
# instantiate the Player
# await get_tree().create_timer(1).timeout
instance = player.instantiate()
add_child(instance)
$Player.start()
# Tell the enemies to spawn!
#await get_tree().create_timer(.5).timeout
spawn_enemies()
# Tell the game we're playing.
playing = true
print("New game started!")
func _input(EventInput):
if EventInput.is_action_pressed("shoot") and playing == false:
print("Input detected!")
start_button.hide()
new_game()
func _on_start_pressed():
start_button.hide()
new_game()
func win_game():
playing = false
game_over.show()
$Player._on_player_victory()
await get_tree().create_timer(2).timeout
game_over.hide()
start_button.show()
func enemy_win() -> void:
print("Enemy win!")

View file

@ -1,8 +1,7 @@
[gd_scene load_steps=11 format=3 uid="uid://cc2dnhuv4qx7m"]
[gd_scene load_steps=10 format=3 uid="uid://cc2dnhuv4qx7m"]
[ext_resource type="Script" uid="uid://c51huloycn5as" path="res://main.gd" id="1_h2yge"]
[ext_resource type="Texture2D" uid="uid://jj8b7vqj3ihx" path="res://Mini Pixel Pack 3/Space_BG (2 frames) (64 x 64).png" id="1_ig7tw"]
[ext_resource type="PackedScene" uid="uid://pyuorpwb7lpe" path="res://player.tscn" id="2_0xm2m"]
[ext_resource type="PackedScene" uid="uid://s6wf3egdqtmh" path="res://ui.tscn" id="4_1bvp3"]
[ext_resource type="Texture2D" uid="uid://bonoqs5pisflo" path="res://Mini Pixel Pack 3/UI objects/START (48 x 8).png" id="5_lquwl"]
[ext_resource type="Texture2D" uid="uid://bubqwoum50gf8" path="res://Mini Pixel Pack 3/UI objects/GAME_OVER (72 x 8).png" id="6_7mycd"]
@ -59,9 +58,6 @@ centered = false
region_enabled = true
region_rect = Rect2(0, 0, 240, 320)
[node name="Player" parent="." instance=ExtResource("2_0xm2m")]
position = Vector2(123, 270)
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
&"": SubResource("AnimationLibrary_lquwl")
@ -71,6 +67,8 @@ autoplay = "scroll"
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="UI" parent="CanvasLayer" instance=ExtResource("4_1bvp3")]
offset_right = 196.0
offset_bottom = 36.0
[node name="CenterContainer" type="CenterContainer" parent="CanvasLayer"]
anchors_preset = 15
@ -87,6 +85,4 @@ texture_normal = ExtResource("5_lquwl")
layout_mode = 2
texture = ExtResource("6_7mycd")
[connection signal="died" from="Player" to="." method="_on_player_died"]
[connection signal="shield_changed" from="Player" to="CanvasLayer/UI" method="update_shield"]
[connection signal="pressed" from="CanvasLayer/CenterContainer/Start" to="." method="_on_start_pressed"]

142
player.gd
View file

@ -1,49 +1,56 @@
extends Area2D
signal died
signal shield_changed
signal damage_taken
var shader_active = false
signal damage_taken
# signal shield_damage
# signal shield_ui
@export var speed: int = 150
@export var cooldown: float = 0.25
@export var bullet_scene : PackedScene
@export var max_shield: int = 10
var shield: int = 0:
set = set_shield
var can_shoot = false
var shader_active: bool = false:
set(value):
if value == true:
print_debug("Shader active!", get_stack())
else:
print_debug("Shader inactive!", get_stack())
var clamp_shield = clamp(shield, 0, max_shield)
@onready var screensize = get_viewport_rect().size
@export var max_shield = 10
var shield = max_shield:
set = set_shield
@export var speed = 150
@export var cooldown = 0.25
@export var bullet_scene : PackedScene
var can_shoot = true
@onready var explosion = $Explosion
@onready var wait_time = $GunCooldown
@onready var ship = $Ship
func _ready():
start()
set_process(false)
print(shield)
# start()
func start():
set_process(true)
print(shield)
shader_active = false
$Ship.frame = 1
$Ship/Boosters.hide()
$Ship.show()
shield = max_shield
position = Vector2(screensize.x / 2, screensize.y - 64)
position = Vector2(screensize.x / 2, screensize.y)
var tween = create_tween()
tween.tween_property(self, "position:y", 48 * -1, .75).as_relative()
await tween.finished
$GunCooldown.wait_time = cooldown
func set_shield(value):
shield = min(max_shield, value)
shield_changed.emit(max_shield, shield)
if shield <= 0:
set_process(false)
$Ship.hide()
$Explosion.show()
$Explosion/AnimationPlayer.play("explosion-one-shot")
await $Explosion/AnimationPlayer.animation_finished
died.emit()
func shoot():
if not can_shoot:
return
can_shoot = false
$GunCooldown.start()
var b = bullet_scene.instantiate()
get_tree().root.add_child(b)
b.start(position + Vector2(0, -8))
set_shield(max_shield)
print(shield)
await get_tree().create_timer(1).timeout
set_process(true)
$Ship/Boosters.show()
can_shoot = true
# EventBus.shield_changed.emit(max_shield, old_value, shield)
func _process(delta):
var input = Input.get_vector("left", "right", "up", "down")
@ -61,24 +68,65 @@ func _process(delta):
if Input.is_action_pressed("shoot"):
shoot()
func _on_gun_cooldown_timeout():
can_shoot = true
func shoot():
if not can_shoot:
return
can_shoot = false
$GunCooldown.start()
var b = bullet_scene.instantiate()
get_tree().root.add_child(b)
b.start(position + ship.position + Vector2(0, -1))
var tween = create_tween().set_parallel(false)
tween.tween_property(ship, "position:y", 1, 0.1)
tween.tween_property(ship, "position:y", 0, 0.05)
func _on_gun_cool_down_timeout() -> void:
can_shoot = true
func set_shield(value: int):
var old_value = shield
# shield = clamp(value, 0, max_shield)
shield = min(max_shield, value)
EventBus.shield_changed.emit(max_shield, old_value, shield)
print("Shield set to:", shield)
if shield <= 0:
set_process(false)
$Ship.hide()
shader_active = false
$Explosion.show()
$Explosion/AnimationPlayer.play("explosion-one-shot")
await $Explosion/AnimationPlayer.animation_finished
EventBus.player_died.emit()
func _on_gun_cooldown_timeout() -> void:
can_shoot = true
func _on_area_entered(area):
if area.is_in_group("enemies"):
shield -= int(max_shield / 2)
# damage_taken.emit()
area.explode()
shield -= max_shield / 2
damage_taken.emit()
if area.is_in_group("enemy_bullets"):
if area.is_in_group("enemy_bullets") and self.monitoring == true:
damage_taken.emit()
func _on_damage_taken() -> void:
shader_active = true
$Ship.material.set_shader_parameter("toggle", 1.0)
func _on_damage_taken():
if shield == 0:
shader_active = false
return
else:
shader_active = true
$Ship.material.set_shader_parameter("toggle", 1.0)
await get_tree().create_timer(1).timeout
$Ship.material.set_shader_parameter("toggle", 0.0)
shader_active = false
func _on_player_victory() -> void:
print("Victory!")
set_process(false)
$Ship.frame = 1
await get_tree().create_timer(1).timeout
shader_active = false
$Ship.material.set_shader_parameter("toggle", 0.0)
var tween = create_tween()
tween.tween_property(self, "position:y", 60 * -1, .25).set_ease(tween.EASE_IN)
await tween.finished
queue_free()

View file

@ -104,4 +104,4 @@ visible = false
[connection signal="area_entered" from="." to="." method="_on_area_entered"]
[connection signal="damage_taken" from="." to="." method="_on_damage_taken"]
[connection signal="timeout" from="GunCooldown" to="." method="_on_gun_cool_down_timeout"]
[connection signal="timeout" from="GunCooldown" to="." method="_on_gun_cooldown_timeout"]

6
progress_bar.gd Normal file
View file

@ -0,0 +1,6 @@
extends TextureProgressBar
func _ready():
self.value = 0
var shield_tween = get_tree().create_tween()
shield_tween.tween_property(self, "value", 100, 3).set_trans(Tween.TRANS_LINEAR)

1
progress_bar.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://b85ktxeoj4b2n

19
progress_bar.tscn Normal file
View file

@ -0,0 +1,19 @@
[gd_scene load_steps=4 format=3 uid="uid://c8s7htpdg4v4i"]
[ext_resource type="Texture2D" uid="uid://d11molrkdjjh5" path="res://bar_background.png" id="1_q0tf5"]
[ext_resource type="Texture2D" uid="uid://bsl3pxvxiuoqg" path="res://bar_foreground.png" id="2_5xu4y"]
[ext_resource type="Script" uid="uid://b85ktxeoj4b2n" path="res://progress_bar.gd" id="3_5xu4y"]
[node name="ProgressBar" type="TextureProgressBar"]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 20.0
grow_horizontal = 2
nine_patch_stretch = true
stretch_margin_left = 8
stretch_margin_top = 8
stretch_margin_right = 8
stretch_margin_bottom = 8
texture_under = ExtResource("1_q0tf5")
texture_progress = ExtResource("2_5xu4y")
script = ExtResource("3_5xu4y")

View file

@ -14,6 +14,11 @@ config/name="shmup01b"
config/features=PackedStringArray("4.5", "Forward Plus")
config/icon="res://icon.svg"
[autoload]
EventBus="*res://event_bus.gd"
Global="*res://global.gd"
[display]
window/size/viewport_width=240

32
ui.gd
View file

@ -3,12 +3,36 @@ extends MarginContainer
@onready var shield_bar = $HBoxContainer/ShieldBar
@onready var score_counter = $HBoxContainer/ScoreCounter
var shader_active = false
func _ready():
# get_node("Player.Ship").node_ready.connect("shield_ui", self, "_on_shield_ui")
EventBus.shield_changed.connect(_on_shield_changed)
EventBus.initialize_shieldbar.connect(_on_initialize_shieldbar)
func update_score(value):
score_counter.display_digits(value)
func update_shield(max_value, value):
var shield_tween = get_tree().create_tween()
func _on_shield_changed(max_value: int, old_value: int, new_value: int) -> void:
shield_bar.max_value = max_value
shield_bar.value = value
shield_tween.tween_property(shield_bar, "value", "max_value", 3,).set_trans(Tween.TRANS_LINEAR)
shield_bar.value = old_value
var tween = create_tween()
print_debug("Tweening shield bar")
tween.tween_property(shield_bar, "value", new_value, .25).set_trans(Tween.TRANS_LINEAR)
_on_fx_shield_ui()
func _on_fx_shield_ui():
shader_active = true
shield_bar.material.set_shader_parameter("toggle", 1.0)
await get_tree().create_timer(1).timeout
shader_active = false
shield_bar.material.set_shader_parameter("toggle", 0.0)
func _on_initialize_shieldbar():
print("Shieldbar Initializing!")
var tween = create_tween()
tween.tween_property(shield_bar, "value", 100, .25).set_trans(Tween.TRANS_LINEAR)
await tween.finished
print_debug("Tweens played!")

11
ui.tscn
View file

@ -1,10 +1,15 @@
[gd_scene load_steps=5 format=3 uid="uid://s6wf3egdqtmh"]
[gd_scene load_steps=7 format=3 uid="uid://s6wf3egdqtmh"]
[ext_resource type="Texture2D" uid="uid://d11molrkdjjh5" path="res://bar_background.png" id="1_m6e0p"]
[ext_resource type="Script" uid="uid://b544c65halgk4" path="res://ui.gd" id="1_nltto"]
[ext_resource type="Texture2D" uid="uid://bsl3pxvxiuoqg" path="res://bar_foreground.png" id="2_27fn8"]
[ext_resource type="Shader" uid="uid://dfywtah53il1m" path="res://player_hit.gdshader" id="2_ibotj"]
[ext_resource type="PackedScene" uid="uid://5qkcf1cpre32" path="res://score_counter.tscn" id="4_ibotj"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_n5ude"]
shader = ExtResource("2_ibotj")
shader_parameter/toggle = 0.0
[node name="UI" type="MarginContainer"]
anchors_preset = 10
anchor_right = 1.0
@ -20,8 +25,10 @@ script = ExtResource("1_nltto")
layout_mode = 2
[node name="ShieldBar" type="TextureProgressBar" parent="HBoxContainer"]
material = SubResource("ShaderMaterial_n5ude")
custom_minimum_size = Vector2(80, 16)
layout_mode = 2
step = 0.0
nine_patch_stretch = true
stretch_margin_left = 3
stretch_margin_top = 3
@ -32,3 +39,5 @@ texture_progress = ExtResource("2_27fn8")
[node name="ScoreCounter" parent="HBoxContainer" instance=ExtResource("4_ibotj")]
layout_mode = 2
[connection signal="value_changed" from="HBoxContainer/ShieldBar" to="." method="_on_shield_bar_value_changed"]