✨ Ebb and flow
							
								
								
									
										
											BIN
										
									
								
								assets/fonts/ibm-plex-sans-regular.otf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										33
									
								
								assets/fonts/ibm-plex-sans-regular.otf.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,33 @@
 | 
			
		||||
[remap]
 | 
			
		||||
 | 
			
		||||
importer="font_data_dynamic"
 | 
			
		||||
type="FontFile"
 | 
			
		||||
uid="uid://cjga4eijrww18"
 | 
			
		||||
path="res://.godot/imported/ibm-plex-sans-regular.otf-03ba595ab5fa8897c955d71d581c61dd.fontdata"
 | 
			
		||||
 | 
			
		||||
[deps]
 | 
			
		||||
 | 
			
		||||
source_file="res://assets/fonts/ibm-plex-sans-regular.otf"
 | 
			
		||||
dest_files=["res://.godot/imported/ibm-plex-sans-regular.otf-03ba595ab5fa8897c955d71d581c61dd.fontdata"]
 | 
			
		||||
 | 
			
		||||
[params]
 | 
			
		||||
 | 
			
		||||
Rendering=null
 | 
			
		||||
antialiasing=1
 | 
			
		||||
generate_mipmaps=false
 | 
			
		||||
multichannel_signed_distance_field=false
 | 
			
		||||
msdf_pixel_range=8
 | 
			
		||||
msdf_size=48
 | 
			
		||||
allow_system_fallback=true
 | 
			
		||||
force_autohinter=false
 | 
			
		||||
hinting=1
 | 
			
		||||
subpixel_positioning=1
 | 
			
		||||
oversampling=0.0
 | 
			
		||||
Fallbacks=null
 | 
			
		||||
fallbacks=[]
 | 
			
		||||
Compress=null
 | 
			
		||||
compress=true
 | 
			
		||||
preload=[]
 | 
			
		||||
language_support={}
 | 
			
		||||
script_support={}
 | 
			
		||||
opentype_features={}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 249 B After Width: | Height: | Size: 249 B  | 
@@ -3,15 +3,15 @@
 | 
			
		||||
importer="texture"
 | 
			
		||||
type="CompressedTexture2D"
 | 
			
		||||
uid="uid://p3urintydjlo"
 | 
			
		||||
path="res://.godot/imported/attacker.svg-150f6909959cc42ad50b11689a4301db.ctex"
 | 
			
		||||
path="res://.godot/imported/attacker.svg-2be6a89ac945048dfab7b97c46f99d5f.ctex"
 | 
			
		||||
metadata={
 | 
			
		||||
"vram_texture": false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[deps]
 | 
			
		||||
 | 
			
		||||
source_file="res://assets/attacker.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/attacker.svg-150f6909959cc42ad50b11689a4301db.ctex"]
 | 
			
		||||
source_file="res://assets/images/attacker.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/attacker.svg-2be6a89ac945048dfab7b97c46f99d5f.ctex"]
 | 
			
		||||
 | 
			
		||||
[params]
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 226 B  | 
@@ -3,15 +3,15 @@
 | 
			
		||||
importer="texture"
 | 
			
		||||
type="CompressedTexture2D"
 | 
			
		||||
uid="uid://voltvmrkr73s"
 | 
			
		||||
path="res://.godot/imported/bullet.svg-63ca26e6536cc1d6a6067a48f66d9b99.ctex"
 | 
			
		||||
path="res://.godot/imported/bullet.svg-3164417db6ddc18184d97c37d20e19f8.ctex"
 | 
			
		||||
metadata={
 | 
			
		||||
"vram_texture": false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[deps]
 | 
			
		||||
 | 
			
		||||
source_file="res://assets/bullet.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/bullet.svg-63ca26e6536cc1d6a6067a48f66d9b99.ctex"]
 | 
			
		||||
source_file="res://assets/images/bullet.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/bullet.svg-3164417db6ddc18184d97c37d20e19f8.ctex"]
 | 
			
		||||
 | 
			
		||||
[params]
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B  | 
@@ -3,15 +3,15 @@
 | 
			
		||||
importer="texture"
 | 
			
		||||
type="CompressedTexture2D"
 | 
			
		||||
uid="uid://b4daomndc1ag"
 | 
			
		||||
path="res://.godot/imported/player.svg-e72d10ccf9c1b331af0b406534563f6c.ctex"
 | 
			
		||||
path="res://.godot/imported/player.svg-351bec044cd47e73eb6ecd3eb5a3b51d.ctex"
 | 
			
		||||
metadata={
 | 
			
		||||
"vram_texture": false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[deps]
 | 
			
		||||
 | 
			
		||||
source_file="res://assets/player.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/player.svg-e72d10ccf9c1b331af0b406534563f6c.ctex"]
 | 
			
		||||
source_file="res://assets/images/player.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/player.svg-351bec044cd47e73eb6ecd3eb5a3b51d.ctex"]
 | 
			
		||||
 | 
			
		||||
[params]
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B  | 
@@ -3,15 +3,15 @@
 | 
			
		||||
importer="texture"
 | 
			
		||||
type="CompressedTexture2D"
 | 
			
		||||
uid="uid://jxub8lma4oud"
 | 
			
		||||
path="res://.godot/imported/tower_background.svg-e77d209753f33c422eeb2695c1195112.ctex"
 | 
			
		||||
path="res://.godot/imported/tower.svg-0a634f4f37eb4a65b03541f661999487.ctex"
 | 
			
		||||
metadata={
 | 
			
		||||
"vram_texture": false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[deps]
 | 
			
		||||
 | 
			
		||||
source_file="res://assets/tower_background.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/tower_background.svg-e77d209753f33c422eeb2695c1195112.ctex"]
 | 
			
		||||
source_file="res://assets/images/tower.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/tower.svg-0a634f4f37eb4a65b03541f661999487.ctex"]
 | 
			
		||||
 | 
			
		||||
[params]
 | 
			
		||||
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1024" height="1024">
 | 
			
		||||
	<title>Tower</title>
 | 
			
		||||
	<style>
 | 
			
		||||
		.s0 { fill: none;stroke: #4750a3;stroke-miterlimit:100;stroke-width: 64 } 
 | 
			
		||||
	</style>
 | 
			
		||||
	<path id="Background" class="s0" d="m512 992c-265.4 0-480-214.6-480-480 0-265.4 214.6-480 480-480 265.4 0 480 214.6 480 480 0 265.4-214.6 480-480 480z"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 385 B  | 
@@ -1,37 +0,0 @@
 | 
			
		||||
[remap]
 | 
			
		||||
 | 
			
		||||
importer="texture"
 | 
			
		||||
type="CompressedTexture2D"
 | 
			
		||||
uid="uid://b4a5wo7y6orr0"
 | 
			
		||||
path="res://.godot/imported/tower_forceground.svg-9f6d44720ea623d40c26c9524e3dd5b1.ctex"
 | 
			
		||||
metadata={
 | 
			
		||||
"vram_texture": false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[deps]
 | 
			
		||||
 | 
			
		||||
source_file="res://assets/tower_forceground.svg"
 | 
			
		||||
dest_files=["res://.godot/imported/tower_forceground.svg-9f6d44720ea623d40c26c9524e3dd5b1.ctex"]
 | 
			
		||||
 | 
			
		||||
[params]
 | 
			
		||||
 | 
			
		||||
compress/mode=0
 | 
			
		||||
compress/high_quality=false
 | 
			
		||||
compress/lossy_quality=0.7
 | 
			
		||||
compress/hdr_compression=1
 | 
			
		||||
compress/normal_map=0
 | 
			
		||||
compress/channel_pack=0
 | 
			
		||||
mipmaps/generate=false
 | 
			
		||||
mipmaps/limit=-1
 | 
			
		||||
roughness/mode=0
 | 
			
		||||
roughness/src_normal=""
 | 
			
		||||
process/fix_alpha_border=true
 | 
			
		||||
process/premult_alpha=false
 | 
			
		||||
process/normal_map_invert_y=false
 | 
			
		||||
process/hdr_as_srgb=false
 | 
			
		||||
process/hdr_clamp_exposure=false
 | 
			
		||||
process/size_limit=0
 | 
			
		||||
detect_3d/compress_to=1
 | 
			
		||||
svg/scale=1.0
 | 
			
		||||
editor/scale_with_editor_scale=false
 | 
			
		||||
editor/convert_colors_with_editor_theme=false
 | 
			
		||||
							
								
								
									
										6
									
								
								codingland.tres
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,6 @@
 | 
			
		||||
[gd_resource type="Theme" load_steps=2 format=3 uid="uid://gh5a3no0ojkl"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="FontFile" uid="uid://cjga4eijrww18" path="res://assets/fonts/ibm-plex-sans-regular.otf" id="1_5jc7o"]
 | 
			
		||||
 | 
			
		||||
[resource]
 | 
			
		||||
default_font = ExtResource("1_5jc7o")
 | 
			
		||||
@@ -51,7 +51,8 @@ skill_dash={
 | 
			
		||||
}
 | 
			
		||||
weapon_fire={
 | 
			
		||||
"deadzone": 0.5,
 | 
			
		||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(163, 27),"global_position":Vector2(171, 107),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
 | 
			
		||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":256,"position":Vector2(234, 24),"global_position":Vector2(242, 104),"factor":1.0,"button_index":9,"canceled":false,"pressed":true,"double_click":false,"script":null)
 | 
			
		||||
, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(185, 16),"global_position":Vector2(193, 96),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
 | 
			
		||||
]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,10 @@
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/enemy_farm.gd" id="1_66qev"]
 | 
			
		||||
 | 
			
		||||
[node name="EnemyFarm" type="Node2D" node_paths=PackedStringArray("common_parent")]
 | 
			
		||||
[node name="EnemyFarm" type="Node2D" node_paths=PackedStringArray("common_parent", "respawn_timer")]
 | 
			
		||||
script = ExtResource("1_66qev")
 | 
			
		||||
common_parent = NodePath(".")
 | 
			
		||||
respawn_timer = NodePath("RespawnTimer")
 | 
			
		||||
 | 
			
		||||
[node name="RespawnTimer" type="Timer" parent="."]
 | 
			
		||||
autostart = true
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
[gd_scene load_steps=6 format=3 uid="uid://l4mybb2dw107"]
 | 
			
		||||
[gd_scene load_steps=9 format=3 uid="uid://l4mybb2dw107"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://cwkcf8h5rspoh" path="res://scenes/objects/player.tscn" id="1_nq1ke"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://cxlgt8h33u7os" path="res://scenes/objects/tower.tscn" id="2_betjv"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://cppmks4ln28yd" path="res://scenes/objects/attacker.tscn" id="3_jg22m"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://cy2xpilh8v7vx" path="res://scenes/farms/enemy_farm.tscn" id="3_ogjsq"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://2tqfm73cc4id" path="res://scenes/manager/statistics.tscn" id="5_qd3ww"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://cjam63kp5sg2o" path="res://scenes/ui/stats_overlay.tscn" id="5_rymed"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://dy51uqtr2ng32" path="res://scenes/ui/finish_screen.tscn" id="6_b264x"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="Curve2D" id="Curve2D_gwd20"]
 | 
			
		||||
_data = {
 | 
			
		||||
@@ -20,8 +23,9 @@ common_target = NodePath("../Player")
 | 
			
		||||
 | 
			
		||||
[node name="BulletFarm" type="Node2D" parent="."]
 | 
			
		||||
 | 
			
		||||
[node name="Player" parent="." node_paths=PackedStringArray("weapon_bullet_parent") instance=ExtResource("1_nq1ke")]
 | 
			
		||||
[node name="Player" parent="." node_paths=PackedStringArray("weapon_bullet_parent", "statistics") instance=ExtResource("1_nq1ke")]
 | 
			
		||||
weapon_bullet_parent = NodePath("../BulletFarm")
 | 
			
		||||
statistics = NodePath("../Statistics")
 | 
			
		||||
 | 
			
		||||
[node name="Tower" parent="." instance=ExtResource("2_betjv")]
 | 
			
		||||
 | 
			
		||||
@@ -31,3 +35,17 @@ curve = SubResource("Curve2D_gwd20")
 | 
			
		||||
[node name="EnemySpawnPoint" type="PathFollow2D" parent="EnemySpawnPath"]
 | 
			
		||||
position = Vector2(-309, -271)
 | 
			
		||||
rotation = 1.5708
 | 
			
		||||
 | 
			
		||||
[node name="StatsOverlay" parent="." node_paths=PackedStringArray("stats") instance=ExtResource("5_rymed")]
 | 
			
		||||
stats = NodePath("../Statistics")
 | 
			
		||||
 | 
			
		||||
[node name="FinishScreen" parent="." node_paths=PackedStringArray("stats") instance=ExtResource("6_b264x")]
 | 
			
		||||
visible = false
 | 
			
		||||
stats = NodePath("../Statistics")
 | 
			
		||||
 | 
			
		||||
[node name="Statistics" parent="." instance=ExtResource("5_qd3ww")]
 | 
			
		||||
 | 
			
		||||
[connection signal="enemy_defeat" from="EnemyFarm" to="Statistics" method="_on_enemy_defeated"]
 | 
			
		||||
[connection signal="tower_broken" from="Tower" to="FinishScreen" method="_show"]
 | 
			
		||||
[connection signal="wave_finished" from="Statistics" to="EnemyFarm" method="_on_wave_finished"]
 | 
			
		||||
[connection signal="wave_started" from="Statistics" to="EnemyFarm" method="_on_wave_started"]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								scenes/manager/statistics.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,18 @@
 | 
			
		||||
[gd_scene load_steps=2 format=3 uid="uid://2tqfm73cc4id"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/statistics.gd" id="1_4fj6w"]
 | 
			
		||||
 | 
			
		||||
[node name="Statistics" type="Node" node_paths=PackedStringArray("wave_timer", "wave_gap_timer")]
 | 
			
		||||
script = ExtResource("1_4fj6w")
 | 
			
		||||
wave_timer = NodePath("WaveTimer")
 | 
			
		||||
wave_gap_timer = NodePath("WaveGapTimer")
 | 
			
		||||
 | 
			
		||||
[node name="WaveTimer" type="Timer" parent="."]
 | 
			
		||||
wait_time = 10.0
 | 
			
		||||
one_shot = true
 | 
			
		||||
 | 
			
		||||
[node name="WaveGapTimer" type="Timer" parent="."]
 | 
			
		||||
one_shot = true
 | 
			
		||||
 | 
			
		||||
[connection signal="timeout" from="WaveTimer" to="." method="_on_wave_passed"]
 | 
			
		||||
[connection signal="timeout" from="WaveGapTimer" to="." method="_on_wave_gap_passed"]
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
[gd_scene load_steps=3 format=3 uid="uid://cppmks4ln28yd"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://p3urintydjlo" path="res://assets/attacker.svg" id="1_56wxx"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://p3urintydjlo" path="res://assets/images/attacker.svg" id="1_56wxx"]
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/attacker.gd" id="1_d7hg4"]
 | 
			
		||||
 | 
			
		||||
[node name="Attacker" type="CharacterBody2D"]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
[gd_scene load_steps=4 format=3 uid="uid://h4fxpxqc6bpt"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/bullet.gd" id="1_7ic61"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://voltvmrkr73s" path="res://assets/bullet.svg" id="1_tytsj"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://voltvmrkr73s" path="res://assets/images/bullet.svg" id="1_tytsj"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_r7dy5"]
 | 
			
		||||
size = Vector2(8, 24)
 | 
			
		||||
@@ -22,6 +22,7 @@ rotation = 1.5708
 | 
			
		||||
shape = SubResource("RectangleShape2D_r7dy5")
 | 
			
		||||
 | 
			
		||||
[node name="DisposeTimer" type="Timer" parent="."]
 | 
			
		||||
one_shot = true
 | 
			
		||||
autostart = true
 | 
			
		||||
 | 
			
		||||
[connection signal="timeout" from="DisposeTimer" to="." method="_on_timed_out"]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
[gd_scene load_steps=5 format=3 uid="uid://cwkcf8h5rspoh"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/player.gd" id="1_sa7t7"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://b4daomndc1ag" path="res://assets/player.svg" id="2_3pad2"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://b4daomndc1ag" path="res://assets/images/player.svg" id="2_3pad2"]
 | 
			
		||||
[ext_resource type="PackedScene" uid="uid://h4fxpxqc6bpt" path="res://scenes/objects/bullet.tscn" id="2_v83ov"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="CircleShape2D" id="CircleShape2D_k56cq"]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
[gd_scene load_steps=5 format=3 uid="uid://cxlgt8h33u7os"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/tower.gd" id="1_d5o8q"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://jxub8lma4oud" path="res://assets/tower_background.svg" id="2_ynj1l"]
 | 
			
		||||
[ext_resource type="Texture2D" uid="uid://jxub8lma4oud" path="res://assets/images/tower.svg" id="2_ynj1l"]
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/tower_health_display.gd" id="3_ijb8h"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="CircleShape2D" id="CircleShape2D_7mogk"]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								scenes/ui/finish_screen.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,28 @@
 | 
			
		||||
[gd_scene load_steps=3 format=3 uid="uid://dy51uqtr2ng32"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/ui/finish_screen.gd" id="1_c1emt"]
 | 
			
		||||
[ext_resource type="Theme" uid="uid://gh5a3no0ojkl" path="res://codingland.tres" id="1_l6ven"]
 | 
			
		||||
 | 
			
		||||
[node name="FinishScreen" type="Control"]
 | 
			
		||||
layout_mode = 3
 | 
			
		||||
anchors_preset = 15
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
grow_horizontal = 2
 | 
			
		||||
grow_vertical = 2
 | 
			
		||||
theme = ExtResource("1_l6ven")
 | 
			
		||||
script = ExtResource("1_c1emt")
 | 
			
		||||
 | 
			
		||||
[node name="Panel" type="Panel" parent="."]
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 648.0
 | 
			
		||||
 | 
			
		||||
[node name="Title" type="Label" parent="Panel"]
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_top = 280.0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 364.0
 | 
			
		||||
theme_override_font_sizes/font_size = 64
 | 
			
		||||
text = "Game Over"
 | 
			
		||||
horizontal_alignment = 1
 | 
			
		||||
							
								
								
									
										78
									
								
								scenes/ui/stats_overlay.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,78 @@
 | 
			
		||||
[gd_scene load_steps=5 format=3 uid="uid://cjam63kp5sg2o"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" path="res://scripts/ui/stats_overlay.gd" id="1_iejg3"]
 | 
			
		||||
[ext_resource type="Theme" uid="uid://gh5a3no0ojkl" path="res://codingland.tres" id="1_ne3m3"]
 | 
			
		||||
 | 
			
		||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bs475"]
 | 
			
		||||
bg_color = Color(0.996078, 0.996078, 0.996078, 0.588235)
 | 
			
		||||
 | 
			
		||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rfnxc"]
 | 
			
		||||
bg_color = Color(0.517647, 0.729412, 0.478431, 1)
 | 
			
		||||
 | 
			
		||||
[node name="StatsOverlay" type="Control" node_paths=PackedStringArray("survived_indicator", "wave_indicator", "wave_progress")]
 | 
			
		||||
layout_mode = 3
 | 
			
		||||
anchors_preset = 15
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
grow_horizontal = 2
 | 
			
		||||
grow_vertical = 2
 | 
			
		||||
theme = ExtResource("1_ne3m3")
 | 
			
		||||
script = ExtResource("1_iejg3")
 | 
			
		||||
survived_indicator = NodePath("SurvivedControl/SurvivedTime")
 | 
			
		||||
wave_indicator = NodePath("WaveControl/WaveCount")
 | 
			
		||||
wave_progress = NodePath("WaveControl/WaveProgress")
 | 
			
		||||
 | 
			
		||||
[node name="SurvivedControl" type="Control" parent="."]
 | 
			
		||||
anchors_preset = 0
 | 
			
		||||
offset_top = 570.0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 648.0
 | 
			
		||||
 | 
			
		||||
[node name="SurvivedCaption" type="Label" parent="SurvivedControl"]
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 26.0
 | 
			
		||||
theme_override_font_sizes/font_size = 18
 | 
			
		||||
text = "You survived"
 | 
			
		||||
horizontal_alignment = 1
 | 
			
		||||
 | 
			
		||||
[node name="SurvivedTime" type="Label" parent="SurvivedControl"]
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_top = 20.0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 65.0
 | 
			
		||||
theme_override_font_sizes/font_size = 32
 | 
			
		||||
text = "0.0s"
 | 
			
		||||
horizontal_alignment = 1
 | 
			
		||||
 | 
			
		||||
[node name="WaveControl" type="Control" parent="."]
 | 
			
		||||
anchors_preset = 0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 648.0
 | 
			
		||||
 | 
			
		||||
[node name="WaveCaption" type="Label" parent="WaveControl"]
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_top = 14.0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 40.0
 | 
			
		||||
theme_override_font_sizes/font_size = 18
 | 
			
		||||
text = "Wave"
 | 
			
		||||
horizontal_alignment = 1
 | 
			
		||||
 | 
			
		||||
[node name="WaveCount" type="Label" parent="WaveControl"]
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_top = 34.0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 79.0
 | 
			
		||||
theme_override_font_sizes/font_size = 32
 | 
			
		||||
text = "1"
 | 
			
		||||
horizontal_alignment = 1
 | 
			
		||||
 | 
			
		||||
[node name="WaveProgress" type="ProgressBar" parent="WaveControl"]
 | 
			
		||||
custom_minimum_size = Vector2(2.08165e-12, 10)
 | 
			
		||||
layout_mode = 0
 | 
			
		||||
offset_right = 1152.0
 | 
			
		||||
offset_bottom = 8.0
 | 
			
		||||
theme_override_styles/background = SubResource("StyleBoxFlat_bs475")
 | 
			
		||||
theme_override_styles/fill = SubResource("StyleBoxFlat_rfnxc")
 | 
			
		||||
show_percentage = false
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
extends CharacterBody2D
 | 
			
		||||
 | 
			
		||||
@export var damage = 12.0
 | 
			
		||||
@export var knockback = 4
 | 
			
		||||
 | 
			
		||||
func _physics_process(delta):
 | 
			
		||||
	var collision = move_and_collide(velocity * delta)
 | 
			
		||||
@@ -8,6 +9,8 @@ func _physics_process(delta):
 | 
			
		||||
	if collision:
 | 
			
		||||
		var collider = collision.get_collider()
 | 
			
		||||
		if collider is Enemy:
 | 
			
		||||
			var normal = collision.get_normal()
 | 
			
		||||
			collider.velocity = collider.velocity.bounce(normal) * knockback
 | 
			
		||||
			collider.take_damage(damage)
 | 
			
		||||
			queue_free()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@ class_name Enemy
 | 
			
		||||
 | 
			
		||||
extends CharacterBody2D
 | 
			
		||||
 | 
			
		||||
signal enemy_defeat
 | 
			
		||||
 | 
			
		||||
@export var damage = 8.0
 | 
			
		||||
@export var max_health = 20
 | 
			
		||||
 | 
			
		||||
@@ -13,4 +15,5 @@ func _ready():
 | 
			
		||||
func take_damage(amount: float):
 | 
			
		||||
	health -= amount
 | 
			
		||||
	if health <= 0:
 | 
			
		||||
		enemy_defeat.emit()
 | 
			
		||||
		queue_free()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,15 @@
 | 
			
		||||
extends Node2D
 | 
			
		||||
 | 
			
		||||
signal enemy_defeat
 | 
			
		||||
 | 
			
		||||
@export var common_parent: Node2D
 | 
			
		||||
@export var path_follow: PathFollow2D
 | 
			
		||||
 | 
			
		||||
@export var target: PackedScene
 | 
			
		||||
@export var common_target: Node2D
 | 
			
		||||
 | 
			
		||||
@export var respawn_timer: Timer
 | 
			
		||||
 | 
			
		||||
func spawn():
 | 
			
		||||
	var instance = target.instantiate()
 | 
			
		||||
	
 | 
			
		||||
@@ -18,6 +22,16 @@ func spawn():
 | 
			
		||||
	instance.speed = randi_range(800, 1400)
 | 
			
		||||
	
 | 
			
		||||
	instance.target = common_target
 | 
			
		||||
	instance.connect("enemy_defeat", _on_enemy_defeat)
 | 
			
		||||
 | 
			
		||||
	# Add into common parent
 | 
			
		||||
	common_parent.add_child(instance)
 | 
			
		||||
 | 
			
		||||
func _on_wave_finished():
 | 
			
		||||
	respawn_timer.stop()
 | 
			
		||||
 | 
			
		||||
func _on_wave_started():
 | 
			
		||||
	respawn_timer.start()
 | 
			
		||||
 | 
			
		||||
func _on_enemy_defeat():
 | 
			
		||||
	enemy_defeat.emit()
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ extends CharacterBody2D
 | 
			
		||||
@export var fire_cooldown_duration = 0.2
 | 
			
		||||
@export var fire_cooldown_timer: Timer
 | 
			
		||||
 | 
			
		||||
@export var statistics: Statistics
 | 
			
		||||
 | 
			
		||||
func deal_move(delta):
 | 
			
		||||
	var input_direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
 | 
			
		||||
	velocity = velocity.move_toward(input_direction * speed, speed * delta)
 | 
			
		||||
@@ -36,6 +38,7 @@ func deal_weapon_shoot():
 | 
			
		||||
		bullet.global_position = global_position
 | 
			
		||||
		bullet.velocity = direction * weapon_bullet_speed
 | 
			
		||||
		
 | 
			
		||||
		statistics.bullet_shoot += 1
 | 
			
		||||
		fire_cooldown_timer.start(fire_cooldown_duration)
 | 
			
		||||
 | 
			
		||||
func _on_dash_cooled_down():
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										71
									
								
								scripts/statistics.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,71 @@
 | 
			
		||||
class_name Statistics
 | 
			
		||||
 | 
			
		||||
extends Node
 | 
			
		||||
 | 
			
		||||
signal wave_finished
 | 
			
		||||
signal wave_started
 | 
			
		||||
 | 
			
		||||
var time_started
 | 
			
		||||
var time_survived
 | 
			
		||||
 | 
			
		||||
var wave_passed: int
 | 
			
		||||
var in_wave_gap: bool
 | 
			
		||||
 | 
			
		||||
var enemies_defeated: int
 | 
			
		||||
var bullet_shoot: int
 | 
			
		||||
 | 
			
		||||
@export var wave_gap_duration = 10
 | 
			
		||||
@export var wave_duration = 10
 | 
			
		||||
@export var wave_multiplier = 1.5
 | 
			
		||||
 | 
			
		||||
@export var wave_timer: Timer
 | 
			
		||||
@export var wave_gap_timer: Timer
 | 
			
		||||
 | 
			
		||||
func _ready():
 | 
			
		||||
	time_started = Time.get_ticks_msec()
 | 
			
		||||
	time_survived = null
 | 
			
		||||
	
 | 
			
		||||
	wave_passed = 0
 | 
			
		||||
	enemies_defeated = 0
 | 
			
		||||
	bullet_shoot = 0
 | 
			
		||||
	
 | 
			
		||||
	_on_wave_gap_passed()
 | 
			
		||||
 | 
			
		||||
func _on_game_over():
 | 
			
		||||
	time_survived = get_time_survived()
 | 
			
		||||
 | 
			
		||||
func get_current_wave():
 | 
			
		||||
	return wave_passed + 1
 | 
			
		||||
 | 
			
		||||
func get_current_wave_time():
 | 
			
		||||
	if in_wave_gap:
 | 
			
		||||
		return get_current_wave_duration() - $WaveGapTimer.time_left
 | 
			
		||||
	else:
 | 
			
		||||
		return get_current_wave_duration() - $WaveTimer.time_left
 | 
			
		||||
 | 
			
		||||
func get_current_wave_duration():
 | 
			
		||||
	if in_wave_gap:
 | 
			
		||||
		return wave_gap_duration
 | 
			
		||||
	else:
 | 
			
		||||
		return wave_duration + wave_multiplier * wave_passed
 | 
			
		||||
 | 
			
		||||
func get_time_survived():
 | 
			
		||||
	if time_survived == null:
 | 
			
		||||
		return Time.get_ticks_msec() - time_started
 | 
			
		||||
	else:
 | 
			
		||||
		return time_survived
 | 
			
		||||
 | 
			
		||||
func _on_enemy_defeated():
 | 
			
		||||
	enemies_defeated += 1
 | 
			
		||||
 | 
			
		||||
func _on_wave_passed():
 | 
			
		||||
	wave_passed += 1
 | 
			
		||||
	in_wave_gap = true
 | 
			
		||||
	wave_finished.emit()
 | 
			
		||||
	wave_gap_timer.start(wave_gap_duration)
 | 
			
		||||
 | 
			
		||||
func _on_wave_gap_passed():
 | 
			
		||||
	in_wave_gap = false
 | 
			
		||||
	wave_started.emit()
 | 
			
		||||
	wave_timer.wait_time = get_current_wave_duration()
 | 
			
		||||
	wave_timer.start()
 | 
			
		||||
@@ -2,6 +2,6 @@ extends Sprite2D
 | 
			
		||||
 | 
			
		||||
@export var regeneration_progress = 0.5
 | 
			
		||||
 | 
			
		||||
func _process(delta):
 | 
			
		||||
func _process(_wdelta):
 | 
			
		||||
	set_modulate(Color(1, 1, 1, regeneration_progress))
 | 
			
		||||
	rotation_degrees += 1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								scripts/ui/finish_screen.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,6 @@
 | 
			
		||||
extends Control
 | 
			
		||||
 | 
			
		||||
@export var stats: Statistics
 | 
			
		||||
 | 
			
		||||
func _show():
 | 
			
		||||
	visible = true
 | 
			
		||||
							
								
								
									
										25
									
								
								scripts/ui/stats_overlay.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
			
		||||
extends Control
 | 
			
		||||
 | 
			
		||||
@export var stats: Statistics
 | 
			
		||||
 | 
			
		||||
@export var survived_indicator: Label
 | 
			
		||||
 | 
			
		||||
@export var wave_indicator: Label
 | 
			
		||||
@export var wave_progress: ProgressBar
 | 
			
		||||
 | 
			
		||||
var wave_stylebox = StyleBoxFlat.new()
 | 
			
		||||
var wave_gap_stylebox = StyleBoxFlat.new()
 | 
			
		||||
 | 
			
		||||
func _ready():
 | 
			
		||||
	wave_stylebox.bg_color = Color("84ba7a")
 | 
			
		||||
	wave_gap_stylebox.bg_color = Color("89a1e5")
 | 
			
		||||
 | 
			
		||||
func _process(_delta):
 | 
			
		||||
	survived_indicator.text = "%.2fs" % (stats.get_time_survived() / 1000.0)
 | 
			
		||||
	wave_indicator.text = "%d" % stats.get_current_wave()
 | 
			
		||||
	
 | 
			
		||||
	if stats.in_wave_gap:
 | 
			
		||||
		wave_progress.add_theme_stylebox_override("fill", wave_gap_stylebox)
 | 
			
		||||
	else:
 | 
			
		||||
		wave_progress.add_theme_stylebox_override("fill", wave_stylebox)
 | 
			
		||||
	wave_progress.value = stats.get_current_wave_time() / stats.get_current_wave_duration() * 100
 | 
			
		||||