summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.gitignore3
-rw-r--r--Readme.md5
-rw-r--r--SoundManager.tscn20
-rw-r--r--character/assets/boss_ko_2.wavbin0 -> 200050 bytes
-rw-r--r--character/assets/boss_ko_2.wav.import24
-rw-r--r--character/assets/boss_ko_2_speed_up.wavbin0 -> 55986 bytes
-rw-r--r--character/assets/boss_ko_2_speed_up.wav.import24
-rw-r--r--character/assets/character_spritesheet.pngbin0 -> 4629 bytes
-rw-r--r--character/assets/character_spritesheet.png.import34
-rw-r--r--character/assets/character_spritesheet.png~bin0 -> 4764 bytes
-rw-r--r--character/character.gd223
-rw-r--r--character/character.tscn52
-rw-r--r--character/character_sprite_frames.tres265
-rw-r--r--icon.svg1
-rw-r--r--icon.svg.import37
-rw-r--r--item/assets/hurt.oggbin0 -> 5747 bytes
-rw-r--r--item/assets/hurt.ogg.import19
-rw-r--r--item/assets/item-crown.pngbin0 -> 305 bytes
-rw-r--r--item/assets/item-crown.png.import34
-rw-r--r--item/assets/item-shoe.pngbin0 -> 247 bytes
-rw-r--r--item/assets/item-shoe.png.import34
-rw-r--r--item/assets/item_pickup.flacbin0 -> 19284 bytes
-rw-r--r--item/assets/item_pickup.oggbin0 -> 7968 bytes
-rw-r--r--item/assets/item_pickup.ogg.import19
-rw-r--r--item/assets/sfx_-_success.oggbin0 -> 58364 bytes
-rw-r--r--item/assets/sfx_-_success.ogg.import19
-rw-r--r--item/crown.gd7
-rw-r--r--item/crown.tscn11
-rw-r--r--item/item-crown.krabin0 -> 31568 bytes
-rw-r--r--item/item-shoe.krabin0 -> 31219 bytes
-rw-r--r--item/item.gd6
-rw-r--r--item/item.tscn22
-rw-r--r--item/item_pickup.flacbin0 -> 19284 bytes
-rw-r--r--item/shoe.gd7
-rw-r--r--item/shoe.tscn11
-rw-r--r--player/opponent.gd57
-rw-r--r--player/opponent.tscn27
-rw-r--r--player/player.gd148
-rw-r--r--player/player.tscn25
-rw-r--r--project.godot50
-rw-r--r--stage/assets/tileset-01.pngbin0 -> 635 bytes
-rw-r--r--stage/assets/tileset-01.png.import34
-rw-r--r--stage/stage.gd15
-rw-r--r--stage/stage.tscn28
-rw-r--r--stage/stage_01.gd103
-rw-r--r--stage/stage_01.tscn29
-rw-r--r--stage/tile_map_layer.tscn44
-rw-r--r--stage/tileset-01.krabin0 -> 41461 bytes
-rw-r--r--ui/assets/Minimal3x5.ttfbin0 -> 10612 bytes
-rw-r--r--ui/assets/Minimal3x5.ttf.import34
-rw-r--r--ui/assets/Minimal5x5Monospaced.ttfbin0 -> 10036 bytes
-rw-r--r--ui/assets/Minimal5x5Monospaced.ttf.import34
-rw-r--r--ui/assets/Minimal5x7.ttfbin0 -> 14584 bytes
-rw-r--r--ui/assets/Minimal5x7.ttf.import34
-rw-r--r--ui/hud.gd13
-rw-r--r--ui/hud.tscn34
-rw-r--r--ui/start_screen.gd13
-rw-r--r--ui/start_screen.tscn51
-rw-r--r--ui/theme.tres8
60 files changed, 1660 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8ad74f7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Normalize EOL for all files that Git considers text files.
+* text=auto eol=lf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0af181c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+# Godot 4+ specific ignores
+.godot/
+/android/
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..b84b01d
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,5 @@
+## TODO
+
+- Type change items
+- Melon
+- Berries
diff --git a/SoundManager.tscn b/SoundManager.tscn
new file mode 100644
index 0000000..8ccfe6f
--- /dev/null
+++ b/SoundManager.tscn
@@ -0,0 +1,20 @@
+[gd_scene load_steps=5 format=3 uid="uid://bn8cjxpontcbf"]
+
+[ext_resource type="AudioStream" uid="uid://c3pvnjmmcmyor" path="res://item/assets/item_pickup.ogg" id="1_kgewx"]
+[ext_resource type="AudioStream" uid="uid://b7ijltkkhtl0" path="res://item/assets/sfx_-_success.ogg" id="2_silpf"]
+[ext_resource type="AudioStream" uid="uid://dt7j663brwu3k" path="res://item/assets/hurt.ogg" id="3_ihrpf"]
+[ext_resource type="AudioStream" uid="uid://1tatxmb1yho1" path="res://character/assets/boss_ko_2_speed_up.wav" id="4_fu3vr"]
+
+[node name="SoundManager" type="Node"]
+
+[node name="ItemPickUpShoe" type="AudioStreamPlayer" parent="."]
+stream = ExtResource("1_kgewx")
+
+[node name="ItemPickUpCrown" type="AudioStreamPlayer" parent="."]
+stream = ExtResource("2_silpf")
+
+[node name="OpponentHit" type="AudioStreamPlayer" parent="."]
+stream = ExtResource("3_ihrpf")
+
+[node name="PlayerKO" type="AudioStreamPlayer" parent="."]
+stream = ExtResource("4_fu3vr")
diff --git a/character/assets/boss_ko_2.wav b/character/assets/boss_ko_2.wav
new file mode 100644
index 0000000..0eed22b
--- /dev/null
+++ b/character/assets/boss_ko_2.wav
Binary files differ
diff --git a/character/assets/boss_ko_2.wav.import b/character/assets/boss_ko_2.wav.import
new file mode 100644
index 0000000..d462c6a
--- /dev/null
+++ b/character/assets/boss_ko_2.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://c5fphxg1torik"
+path="res://.godot/imported/boss_ko_2.wav-82c65adb3b984cb2964503f8b8f2e1a5.sample"
+
+[deps]
+
+source_file="res://character/assets/boss_ko_2.wav"
+dest_files=["res://.godot/imported/boss_ko_2.wav-82c65adb3b984cb2964503f8b8f2e1a5.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/character/assets/boss_ko_2_speed_up.wav b/character/assets/boss_ko_2_speed_up.wav
new file mode 100644
index 0000000..b1d9139
--- /dev/null
+++ b/character/assets/boss_ko_2_speed_up.wav
Binary files differ
diff --git a/character/assets/boss_ko_2_speed_up.wav.import b/character/assets/boss_ko_2_speed_up.wav.import
new file mode 100644
index 0000000..cc5b88a
--- /dev/null
+++ b/character/assets/boss_ko_2_speed_up.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://1tatxmb1yho1"
+path="res://.godot/imported/boss_ko_2_speed_up.wav-755e37e7a7926935cf77cd90f2568d2d.sample"
+
+[deps]
+
+source_file="res://character/assets/boss_ko_2_speed_up.wav"
+dest_files=["res://.godot/imported/boss_ko_2_speed_up.wav-755e37e7a7926935cf77cd90f2568d2d.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/character/assets/character_spritesheet.png b/character/assets/character_spritesheet.png
new file mode 100644
index 0000000..9c1b844
--- /dev/null
+++ b/character/assets/character_spritesheet.png
Binary files differ
diff --git a/character/assets/character_spritesheet.png.import b/character/assets/character_spritesheet.png.import
new file mode 100644
index 0000000..3009953
--- /dev/null
+++ b/character/assets/character_spritesheet.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d3cp58o1j55au"
+path="res://.godot/imported/character_spritesheet.png-2d80c8875136c51fbbec17d53bbcb841.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://character/assets/character_spritesheet.png"
+dest_files=["res://.godot/imported/character_spritesheet.png-2d80c8875136c51fbbec17d53bbcb841.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
diff --git a/character/assets/character_spritesheet.png~ b/character/assets/character_spritesheet.png~
new file mode 100644
index 0000000..2136c69
--- /dev/null
+++ b/character/assets/character_spritesheet.png~
Binary files differ
diff --git a/character/character.gd b/character/character.gd
new file mode 100644
index 0000000..ef18bbc
--- /dev/null
+++ b/character/character.gd
@@ -0,0 +1,223 @@
+class_name Character
+extends Node2D
+
+
+const BASE_SPEED := 50.0
+const VERTICAL_DISTANCE := 24
+
+signal speed_changed
+var speed_modifier := 1.0:
+ set(value):
+ speed_modifier = value
+ speed_changed.emit()
+
+enum Type {
+ Rock,
+ Paper,
+ Scissors,
+}
+
+signal type_change_finished
+signal type_changed
+@export var current_type: Type = Type.Rock:
+ set(value):
+ current_type = value
+ type_changed.emit()
+
+enum Direction {
+ None,
+ Left,
+ Right,
+}
+
+enum State {
+ Idle,
+ Walk,
+ Jump,
+ Fall,
+ Transform,
+}
+
+var current_state: State = State.Idle
+
+var vertical_tween: Tween
+
+@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
+
+
+func _ready() -> void:
+ speed_changed.connect(func():
+ $AnimatedSprite2D.speed_scale = speed_modifier
+ )
+
+ type_changed.connect(func():
+ if current_state == State.Jump:
+ $AnimatedSprite2D.play("%s_jump" % get_type_name())
+ elif current_state == State.Fall:
+ $AnimatedSprite2D.play("%s_fall" % get_type_name())
+ )
+
+
+func get_type_name(type: Type = current_type):
+ match type:
+ Type.Rock:
+ return "rock"
+ Type.Paper:
+ return "paper"
+ Type.Scissors:
+ return "scissors"
+
+
+func idle():
+ current_state = State.Idle
+
+ $AnimatedSprite2D.play("%s_idle" % get_type_name())
+
+
+func walk(direction: Direction):
+ current_state = State.Walk
+
+ $AnimatedSprite2D.flip_h = direction == Direction.Left
+ $AnimatedSprite2D.play("%s_walk" % get_type_name())
+
+ if is_on_wall(direction):
+ return
+
+ var direction_vector: Vector2
+ match direction:
+ Direction.Left:
+ direction_vector = Vector2.LEFT
+
+ Direction.Right:
+ direction_vector = Vector2.RIGHT
+
+ position.x = lerp(
+ position.x,
+ position.x + (BASE_SPEED * speed_modifier * direction_vector.x),
+ get_process_delta_time()
+ )
+
+
+func jump():
+ if is_below_ceiling():
+ return
+
+ current_state = State.Jump
+
+ $AnimatedSprite2D.play("%s_jump" % get_type_name())
+
+ vertical_tween = get_tree().create_tween()
+ vertical_tween.tween_property(
+ self,
+ "position",
+ position - Vector2(0, VERTICAL_DISTANCE),
+ min(1.0 / speed_modifier, 1.0)
+ )
+
+ await vertical_tween.finished
+
+ if not is_on_floor():
+ fall()
+ else:
+ current_state = State.Idle
+
+
+func fall():
+ current_state = State.Fall
+
+ $AnimatedSprite2D.play("%s_fall" % get_type_name())
+
+ vertical_tween = get_tree().create_tween()
+ vertical_tween.tween_property(
+ self,
+ "position",
+ position + Vector2(0, VERTICAL_DISTANCE),
+ min(1.0 / speed_modifier, 1.0)
+ )
+
+ await vertical_tween.finished
+
+ if not is_on_floor():
+ fall()
+ else:
+ current_state = State.Idle
+
+
+func is_on_floor() -> bool:
+ $RayDownLeft.force_raycast_update()
+ $RayDownRight.force_raycast_update()
+
+ return $RayDownLeft.is_colliding() or $RayDownRight.is_colliding()
+
+
+func is_on_ledge() -> bool:
+ return true
+ pass
+ # TODO: add two more down Rays
+ # and up rays for is_below wall and is_below_ledge
+ # to fix falling through wall
+ # funktion im base-game aber auch gar nicht vorhanden:)
+
+
+func is_on_bottom_floor() -> bool:
+ var stage: Stage = get_tree().current_scene
+ var map: TileMapLayer = get_tree().get_first_node_in_group("tilemap")
+ var bottom = position.y + (get_sprite_size().y / 2) + map.tile_set.tile_size.y
+
+ return bottom >= stage.get_world_boundaries()[Vector2.DOWN]
+
+
+func is_below_ceiling() -> bool:
+ return $RayUpLeft.is_colliding() or $RayUpRight.is_colliding()
+
+
+func is_on_wall(direction: Direction) -> bool:
+ var stage: Stage = get_tree().current_scene
+
+ match direction:
+ Direction.None:
+ return $RayLeft.is_colliding() or $RayRight.is_colliding()
+
+ Direction.Left:
+ var left = position.x - (get_sprite_size().x / 2)
+ return $RayLeft.is_colliding() or left <= stage.get_world_boundaries()[Vector2.LEFT]
+
+ Direction.Right:
+ var right = position.x + (get_sprite_size().x / 2)
+ return $RayRight.is_colliding() or right >= stage.get_world_boundaries()[Vector2.RIGHT]
+
+ return false
+
+
+func change_type_random():
+ var types = Type.values()
+ types.erase(current_type)
+
+ current_type = types.pick_random()
+
+
+func animate_type_change():
+ var previous_state := current_state
+ current_state = State.Transform
+
+ var tween_was_running := false
+ if vertical_tween and vertical_tween.is_running():
+ vertical_tween.pause()
+ tween_was_running = true
+
+ $AnimatedSprite2D.play("transform")
+ await $AnimatedSprite2D.animation_finished
+
+ current_state = previous_state
+
+ type_change_finished.emit()
+
+ if tween_was_running:
+ vertical_tween.play()
+
+
+func get_sprite_size() -> Vector2:
+ var sprite_frames: SpriteFrames = $AnimatedSprite2D.sprite_frames
+ var texture := sprite_frames.get_frame_texture($AnimatedSprite2D.animation, $AnimatedSprite2D.frame)
+
+ return texture.get_size() - Vector2(4, 0)
diff --git a/character/character.tscn b/character/character.tscn
new file mode 100644
index 0000000..3a1b0e8
--- /dev/null
+++ b/character/character.tscn
@@ -0,0 +1,52 @@
+[gd_scene load_steps=4 format=3 uid="uid://d21spw8y5yiuu"]
+
+[ext_resource type="Script" path="res://character/character.gd" id="1_wqxem"]
+[ext_resource type="SpriteFrames" uid="uid://cvbw222po7psr" path="res://character/character_sprite_frames.tres" id="2_xbkcg"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_wfm33"]
+size = Vector2(12, 12)
+
+[node name="Character" type="Node2D"]
+script = ExtResource("1_wqxem")
+
+[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
+texture_filter = 1
+position = Vector2(-10, -10)
+sprite_frames = ExtResource("2_xbkcg")
+animation = &"scissors_idle"
+centered = false
+
+[node name="Collision" type="Area2D" parent="."]
+collision_layer = 0
+collision_mask = 256
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Collision"]
+shape = SubResource("RectangleShape2D_wfm33")
+
+[node name="RayLeft" type="RayCast2D" parent="."]
+target_position = Vector2(-8, 0)
+collision_mask = 256
+
+[node name="RayRight" type="RayCast2D" parent="."]
+target_position = Vector2(8, 0)
+collision_mask = 256
+
+[node name="RayUpLeft" type="RayCast2D" parent="."]
+position = Vector2(-6, 0)
+target_position = Vector2(0, -10)
+collision_mask = 256
+
+[node name="RayUpRight" type="RayCast2D" parent="."]
+position = Vector2(6, 0)
+target_position = Vector2(0, -10)
+collision_mask = 256
+
+[node name="RayDownLeft" type="RayCast2D" parent="."]
+position = Vector2(-6, 0)
+target_position = Vector2(0, 9)
+collision_mask = 768
+
+[node name="RayDownRight" type="RayCast2D" parent="."]
+position = Vector2(6, 0)
+target_position = Vector2(0, 9)
+collision_mask = 768
diff --git a/character/character_sprite_frames.tres b/character/character_sprite_frames.tres
new file mode 100644
index 0000000..6aa4352
--- /dev/null
+++ b/character/character_sprite_frames.tres
@@ -0,0 +1,265 @@
+[gd_resource type="SpriteFrames" load_steps=29 format=3 uid="uid://cvbw222po7psr"]
+
+[ext_resource type="Texture2D" uid="uid://d3cp58o1j55au" path="res://character/assets/character_spritesheet.png" id="1_0ukqc"]
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_q8pdk"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(0, 60, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_k21bg"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(20, 60, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_a33vs"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(40, 60, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_ad1cw"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(100, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_khl7x"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(0, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_yqka7"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(20, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_6o2jd"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(80, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_fi3xw"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(40, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_8aswo"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(60, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_0x2b7"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(100, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_luqcw"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(0, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_er4mc"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(20, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_h68fd"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(80, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_2uumw"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(40, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_isrrp"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(60, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_1xa27"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(100, 60, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_qhn6i"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(0, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_wsjy3"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(20, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_g2iar"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(80, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_btwgo"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(40, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_g5iao"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(60, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_i0gr8"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(120, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_uf1gj"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(140, 0, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_06q0h"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(120, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_k4wtj"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(140, 20, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_064a1"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(120, 40, 20, 20)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_komno"]
+atlas = ExtResource("1_0ukqc")
+region = Rect2(140, 40, 20, 20)
+
+[resource]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_q8pdk")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_k21bg")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_a33vs")
+}],
+"loop": false,
+"name": &"ko",
+"speed": 6.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_ad1cw")
+}],
+"loop": true,
+"name": &"paper_fall",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_khl7x")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_yqka7")
+}],
+"loop": true,
+"name": &"paper_idle",
+"speed": 4.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_6o2jd")
+}],
+"loop": true,
+"name": &"paper_jump",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_fi3xw")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_8aswo")
+}],
+"loop": true,
+"name": &"paper_walk",
+"speed": 4.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_0x2b7")
+}],
+"loop": false,
+"name": &"rock_fall",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_luqcw")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_er4mc")
+}],
+"loop": true,
+"name": &"rock_idle",
+"speed": 4.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_h68fd")
+}],
+"loop": false,
+"name": &"rock_jump",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_2uumw")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_isrrp")
+}],
+"loop": true,
+"name": &"rock_walk",
+"speed": 4.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_1xa27")
+}],
+"loop": false,
+"name": &"scissors_fall",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_qhn6i")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_wsjy3")
+}],
+"loop": true,
+"name": &"scissors_idle",
+"speed": 4.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_g2iar")
+}],
+"loop": false,
+"name": &"scissors_jump",
+"speed": 5.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_btwgo")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_g5iao")
+}],
+"loop": true,
+"name": &"scissors_walk",
+"speed": 4.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_i0gr8")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_uf1gj")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_06q0h")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_k4wtj")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_064a1")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_komno")
+}],
+"loop": false,
+"name": &"transform",
+"speed": 4.0
+}]
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..9d8b7fa
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> \ No newline at end of file
diff --git a/icon.svg.import b/icon.svg.import
new file mode 100644
index 0000000..287fee7
--- /dev/null
+++ b/icon.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dwt6h37ll70f"
+path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.svg"
+dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
diff --git a/item/assets/hurt.ogg b/item/assets/hurt.ogg
new file mode 100644
index 0000000..f824056
--- /dev/null
+++ b/item/assets/hurt.ogg
Binary files differ
diff --git a/item/assets/hurt.ogg.import b/item/assets/hurt.ogg.import
new file mode 100644
index 0000000..e9875fc
--- /dev/null
+++ b/item/assets/hurt.ogg.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOggVorbis"
+uid="uid://dt7j663brwu3k"
+path="res://.godot/imported/hurt.ogg-70ee6cc8b521e110664ed33e18f38ac7.oggvorbisstr"
+
+[deps]
+
+source_file="res://item/assets/hurt.ogg"
+dest_files=["res://.godot/imported/hurt.ogg-70ee6cc8b521e110664ed33e18f38ac7.oggvorbisstr"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/item/assets/item-crown.png b/item/assets/item-crown.png
new file mode 100644
index 0000000..56efa7a
--- /dev/null
+++ b/item/assets/item-crown.png
Binary files differ
diff --git a/item/assets/item-crown.png.import b/item/assets/item-crown.png.import
new file mode 100644
index 0000000..6f3c73c
--- /dev/null
+++ b/item/assets/item-crown.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://wp7r2fnlaty5"
+path="res://.godot/imported/item-crown.png-ec868573b1dc0cd10108d94b8a454b1b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/assets/item-crown.png"
+dest_files=["res://.godot/imported/item-crown.png-ec868573b1dc0cd10108d94b8a454b1b.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
diff --git a/item/assets/item-shoe.png b/item/assets/item-shoe.png
new file mode 100644
index 0000000..fa2a6ae
--- /dev/null
+++ b/item/assets/item-shoe.png
Binary files differ
diff --git a/item/assets/item-shoe.png.import b/item/assets/item-shoe.png.import
new file mode 100644
index 0000000..8f43447
--- /dev/null
+++ b/item/assets/item-shoe.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d12cln2og1pon"
+path="res://.godot/imported/item-shoe.png-e12e4c5ea27054908dc8103fd004bc0e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://item/assets/item-shoe.png"
+dest_files=["res://.godot/imported/item-shoe.png-e12e4c5ea27054908dc8103fd004bc0e.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
diff --git a/item/assets/item_pickup.flac b/item/assets/item_pickup.flac
new file mode 100644
index 0000000..7af81d8
--- /dev/null
+++ b/item/assets/item_pickup.flac
Binary files differ
diff --git a/item/assets/item_pickup.ogg b/item/assets/item_pickup.ogg
new file mode 100644
index 0000000..a3b7efa
--- /dev/null
+++ b/item/assets/item_pickup.ogg
Binary files differ
diff --git a/item/assets/item_pickup.ogg.import b/item/assets/item_pickup.ogg.import
new file mode 100644
index 0000000..248be74
--- /dev/null
+++ b/item/assets/item_pickup.ogg.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOggVorbis"
+uid="uid://c3pvnjmmcmyor"
+path="res://.godot/imported/item_pickup.ogg-bbbc329c8dfb09e723abd2fbea1c1417.oggvorbisstr"
+
+[deps]
+
+source_file="res://item/assets/item_pickup.ogg"
+dest_files=["res://.godot/imported/item_pickup.ogg-bbbc329c8dfb09e723abd2fbea1c1417.oggvorbisstr"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/item/assets/sfx_-_success.ogg b/item/assets/sfx_-_success.ogg
new file mode 100644
index 0000000..761468a
--- /dev/null
+++ b/item/assets/sfx_-_success.ogg
Binary files differ
diff --git a/item/assets/sfx_-_success.ogg.import b/item/assets/sfx_-_success.ogg.import
new file mode 100644
index 0000000..aade728
--- /dev/null
+++ b/item/assets/sfx_-_success.ogg.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOggVorbis"
+uid="uid://b7ijltkkhtl0"
+path="res://.godot/imported/sfx_-_success.ogg-83f02af82e030026e9833067c3de9acd.oggvorbisstr"
+
+[deps]
+
+source_file="res://item/assets/sfx_-_success.ogg"
+dest_files=["res://.godot/imported/sfx_-_success.ogg-83f02af82e030026e9833067c3de9acd.oggvorbisstr"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/item/crown.gd b/item/crown.gd
new file mode 100644
index 0000000..3ff1c84
--- /dev/null
+++ b/item/crown.gd
@@ -0,0 +1,7 @@
+extends Item
+
+
+func apply(player: Player):
+ SoundManager.get_node("ItemPickUpCrown").play()
+ player.change_type_random()
+ queue_free()
diff --git a/item/crown.tscn b/item/crown.tscn
new file mode 100644
index 0000000..0d38cb9
--- /dev/null
+++ b/item/crown.tscn
@@ -0,0 +1,11 @@
+[gd_scene load_steps=4 format=3 uid="uid://05jcjn7fw7iu"]
+
+[ext_resource type="PackedScene" uid="uid://36cam5oaj8p5" path="res://item/item.tscn" id="1_4htir"]
+[ext_resource type="Script" path="res://item/crown.gd" id="2_74yne"]
+[ext_resource type="Texture2D" uid="uid://wp7r2fnlaty5" path="res://item/assets/item-crown.png" id="3_ejtdy"]
+
+[node name="Crown" instance=ExtResource("1_4htir")]
+script = ExtResource("2_74yne")
+
+[node name="Sprite2D" parent="." index="0"]
+texture = ExtResource("3_ejtdy")
diff --git a/item/item-crown.kra b/item/item-crown.kra
new file mode 100644
index 0000000..d558a50
--- /dev/null
+++ b/item/item-crown.kra
Binary files differ
diff --git a/item/item-shoe.kra b/item/item-shoe.kra
new file mode 100644
index 0000000..ad5d1a5
--- /dev/null
+++ b/item/item-shoe.kra
Binary files differ
diff --git a/item/item.gd b/item/item.gd
new file mode 100644
index 0000000..4f99999
--- /dev/null
+++ b/item/item.gd
@@ -0,0 +1,6 @@
+class_name Item
+extends Node2D
+
+
+func apply(_player: Player):
+ pass
diff --git a/item/item.tscn b/item/item.tscn
new file mode 100644
index 0000000..ee13cda
--- /dev/null
+++ b/item/item.tscn
@@ -0,0 +1,22 @@
+[gd_scene load_steps=3 format=3 uid="uid://36cam5oaj8p5"]
+
+[ext_resource type="Script" path="res://item/item.gd" id="1_xhv56"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_23apt"]
+size = Vector2(16, 16)
+
+[node name="Item" type="Node2D"]
+script = ExtResource("1_xhv56")
+
+[node name="Sprite2D" type="Sprite2D" parent="."]
+texture_filter = 1
+position = Vector2(-8, -8)
+centered = false
+
+[node name="Area2D" type="Area2D" parent="." groups=["item"]]
+visible = false
+collision_layer = 16
+collision_mask = 0
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
+shape = SubResource("RectangleShape2D_23apt")
diff --git a/item/item_pickup.flac b/item/item_pickup.flac
new file mode 100644
index 0000000..7af81d8
--- /dev/null
+++ b/item/item_pickup.flac
Binary files differ
diff --git a/item/shoe.gd b/item/shoe.gd
new file mode 100644
index 0000000..821af95
--- /dev/null
+++ b/item/shoe.gd
@@ -0,0 +1,7 @@
+extends Item
+
+
+func apply(player: Player):
+ SoundManager.get_node("ItemPickUpShoe").play()
+ player.speed_modifier = min(player.speed_modifier + 0.5, 2.0)
+ queue_free()
diff --git a/item/shoe.tscn b/item/shoe.tscn
new file mode 100644
index 0000000..c35facd
--- /dev/null
+++ b/item/shoe.tscn
@@ -0,0 +1,11 @@
+[gd_scene load_steps=4 format=3 uid="uid://bpl6aiic6muas"]
+
+[ext_resource type="PackedScene" uid="uid://36cam5oaj8p5" path="res://item/item.tscn" id="1_1i4gm"]
+[ext_resource type="Script" path="res://item/shoe.gd" id="2_byls7"]
+[ext_resource type="Texture2D" uid="uid://d12cln2og1pon" path="res://item/assets/item-shoe.png" id="3_n8grx"]
+
+[node name="Shoe" instance=ExtResource("1_1i4gm")]
+script = ExtResource("2_byls7")
+
+[node name="Sprite2D" parent="." index="0"]
+texture = ExtResource("3_n8grx")
diff --git a/player/opponent.gd b/player/opponent.gd
new file mode 100644
index 0000000..ec20cd1
--- /dev/null
+++ b/player/opponent.gd
@@ -0,0 +1,57 @@
+extends Character
+
+
+var current_direction := Direction.Left
+
+@export var random_start_type := false
+
+
+func _ready() -> void:
+ super._ready()
+
+ var rng = RandomNumberGenerator.new()
+ rng.seed = ((get_tree().current_scene as Stage).scene_file_path as String).md5_buffer().decode_u64(0) + Time.get_ticks_msec()
+
+ $AnimatedSprite2D.modulate = Color(max(0.1, rng.randf()), max(0.1, rng.randf()), max(0.1, rng.randf()))
+
+ speed_modifier = 0.5
+
+ if random_start_type:
+ current_type = Type.values().pick_random()
+
+ idle()
+
+
+func _process(_delta: float) -> void:
+ if current_state == State.Idle or current_state == State.Walk:
+ walk(current_direction)
+
+ if is_on_wall(current_direction):
+ change_direction()
+
+ if not is_on_floor():
+ fall()
+
+
+func is_below_ledge() -> bool:
+ return $RayUpLeft2.is_colliding() or $RayUpRight2.is_colliding()
+
+
+func change_direction():
+ if current_direction == Direction.Left:
+ current_direction = Direction.Right
+ else:
+ current_direction = Direction.Left
+
+
+func _on_vertical_timer_timeout() -> void:
+ if current_state == State.Idle or current_state == State.Walk:
+ if randi_range(0, 100) > 75:
+ change_direction()
+
+ if randi_range(0, 100) > 75 and is_below_ledge():
+ await jump()
+ elif randi_range(0, 100) > 75 and not is_on_bottom_floor():
+ await fall()
+
+ $VerticalTimer.start()
diff --git a/player/opponent.tscn b/player/opponent.tscn
new file mode 100644
index 0000000..92d0af6
--- /dev/null
+++ b/player/opponent.tscn
@@ -0,0 +1,27 @@
+[gd_scene load_steps=3 format=3 uid="uid://d1h8psjxqge0a"]
+
+[ext_resource type="PackedScene" uid="uid://d21spw8y5yiuu" path="res://character/character.tscn" id="1_ykya6"]
+[ext_resource type="Script" path="res://player/opponent.gd" id="2_pkqiw"]
+
+[node name="Opponent" instance=ExtResource("1_ykya6")]
+script = ExtResource("2_pkqiw")
+random_start_type = false
+
+[node name="Collision" parent="." index="1" groups=["opponent"]]
+collision_layer = 2
+
+[node name="RayUpLeft2" type="RayCast2D" parent="." index="6"]
+position = Vector2(-6, 0)
+target_position = Vector2(0, -10)
+collision_mask = 512
+
+[node name="RayUpRight2" type="RayCast2D" parent="." index="7"]
+position = Vector2(6, 0)
+target_position = Vector2(0, -10)
+collision_mask = 512
+
+[node name="VerticalTimer" type="Timer" parent="." index="10"]
+one_shot = true
+autostart = true
+
+[connection signal="timeout" from="VerticalTimer" to="." method="_on_vertical_timer_timeout"]
diff --git a/player/player.gd b/player/player.gd
new file mode 100644
index 0000000..4257f2a
--- /dev/null
+++ b/player/player.gd
@@ -0,0 +1,148 @@
+class_name Player
+extends Character
+
+
+var is_invincible := false
+
+@onready var camera := $Camera2D
+
+
+func _ready() -> void:
+ super._ready()
+
+ $AnimatedSprite2D.modulate = Color(max(0.1, randf()), max(0.1, randf()), max(0.1, randf()))
+
+
+func _process(_delta: float) -> void:
+ if current_state == State.Idle:
+ if Input.is_action_pressed("ui_left"):
+ walk(Direction.Left)
+ elif Input.is_action_pressed("ui_right"):
+ walk(Direction.Right)
+ else:
+ idle()
+
+ if Input.is_action_pressed("ui_up"):
+ jump()
+ if Input.is_action_pressed("ui_down"):
+ if not is_on_bottom_floor():
+ fall()
+
+ if not is_on_floor():
+ fall()
+
+
+ elif current_state == State.Walk:
+ if Input.is_action_pressed("ui_left"):
+ walk(Direction.Left)
+ elif Input.is_action_pressed("ui_right"):
+ walk(Direction.Right)
+ else:
+ idle()
+
+ if Input.is_action_pressed("ui_up"):
+ jump()
+ if Input.is_action_pressed("ui_down"):
+ if not is_on_bottom_floor():
+ fall()
+
+ if not is_on_floor():
+ fall()
+
+
+ if Input.is_action_just_pressed("ui_accept"):
+ change_type_random()
+
+
+func invincible(duration: float):
+ is_invincible = true
+
+ var tween := get_tree().create_tween().set_loops(int(duration / 0.5))
+ tween.tween_property($AnimatedSprite2D, "self_modulate", Color(1.0, 1.0, 1.0, 0.25), 0.25)
+ tween.tween_property($AnimatedSprite2D, "self_modulate", Color(1.0, 1.0, 1.0, 1.0), 0.25)
+
+ await tween.finished
+ is_invincible = false
+
+
+enum Result {
+ Draw,
+ Win,
+ Lose,
+}
+
+static func is_rock_paper_scissors_win(player: Character, opponent: Character) -> Result:
+ if player.current_type == Type.Rock and opponent.current_type == Type.Scissors:
+ return Result.Win
+ elif player.current_type == Type.Paper and opponent.current_type == Type.Rock:
+ return Result.Win
+ elif player.current_type == Type.Scissors and opponent.current_type == Type.Paper:
+ return Result.Win
+ elif player.current_type == Type.Rock and opponent.current_type == Type.Paper:
+ return Result.Lose
+ elif player.current_type == Type.Paper and opponent.current_type == Type.Scissors:
+ return Result.Lose
+ elif player.current_type == Type.Rock and opponent.current_type == Type.Paper:
+ return Result.Lose
+ elif player.current_type == Type.Scissors and opponent.current_type == Type.Rock:
+ return Result.Lose
+ else:
+ return Result.Draw
+
+
+func _on_collision_area_entered(area: Area2D) -> void:
+ if area.is_in_group("item"):
+ var item: Item = area.get_parent()
+ item.apply(self)
+
+ elif area.is_in_group("opponent"):
+ if is_invincible or current_state == State.Transform:
+ return
+
+ var opponent: Character = area.get_parent()
+ var result := Player.is_rock_paper_scissors_win(self, opponent)
+ if result == Result.Draw:
+ type_change_finished.connect(func():
+ change_type_random()
+ )
+ animate_type_change()
+
+ elif result == Result.Win:
+ (get_tree().get_first_node_in_group("hud") as HUD).score += 1
+
+ SoundManager.get_node("OpponentHit").play()
+
+ type_change_finished.connect(func():
+ change_type_random()
+ invincible(1.0)
+ )
+ animate_type_change()
+
+ opponent.process_mode = Node.PROCESS_MODE_DISABLED
+ var tween = get_tree().create_tween()
+ tween.tween_property(
+ opponent,
+ "position",
+ position + (opponent.position - position) * 10,
+ 0.5
+ )
+ await tween.finished
+
+ opponent.queue_free()
+
+ await get_tree().process_frame
+ if (get_tree().current_scene as Stage).has_win_condition():
+ await get_tree().create_timer(2.0).timeout
+ get_tree().change_scene_to_file("res://stage/stage_01.tscn")
+
+ elif result == Result.Lose:
+ (func(): $Collision.process_mode = Node.PROCESS_MODE_DISABLED).call_deferred()
+ set_process(false)
+ if vertical_tween: vertical_tween.stop()
+
+ SoundManager.get_node("PlayerKO").play()
+ $AnimatedSprite2D.play("ko")
+ await $AnimatedSprite2D.animation_finished
+ SoundManager.get_node("PlayerKO").stop()
+ visible = false
+ get_tree().change_scene_to_file("res://stage/stage_01.tscn")
diff --git a/player/player.tscn b/player/player.tscn
new file mode 100644
index 0000000..b213030
--- /dev/null
+++ b/player/player.tscn
@@ -0,0 +1,25 @@
+[gd_scene load_steps=5 format=4 uid="uid://b4t3ipnq8vq2p"]
+
+[ext_resource type="PackedScene" uid="uid://d21spw8y5yiuu" path="res://character/character.tscn" id="1_eixx6"]
+[ext_resource type="Script" path="res://player/player.gd" id="1_wqxem"]
+[ext_resource type="AudioStream" uid="uid://c3pvnjmmcmyor" path="res://item/assets/item_pickup.ogg" id="3_o0r1j"]
+
+[sub_resource type="AudioStreamMP3" id="AudioStreamMP3_sy3f5"]
+data = PackedByteArray("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")
+
+[node name="Player" instance=ExtResource("1_eixx6")]
+script = ExtResource("1_wqxem")
+
+[node name="Collision" parent="." index="1"]
+collision_layer = 1
+collision_mask = 18
+
+[node name="Camera2D" type="Camera2D" parent="." index="2"]
+
+[node name="ShoeItemPickUp" type="AudioStreamPlayer" parent="." index="9"]
+stream = ExtResource("3_o0r1j")
+
+[node name="CrownItemPickUp" type="AudioStreamPlayer" parent="." index="10"]
+stream = SubResource("AudioStreamMP3_sy3f5")
+
+[connection signal="area_entered" from="Collision" to="." method="_on_collision_area_entered"]
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..3001e57
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,50 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Magical Tower"
+run/main_scene="res://ui/start_screen.tscn"
+config/features=PackedStringArray("4.3", "GL Compatibility")
+config/icon="res://icon.svg"
+
+[autoload]
+
+SoundManager="*res://SoundManager.tscn"
+
+[debug]
+
+gdscript/warnings/integer_division=0
+
+[display]
+
+window/size/viewport_width=160
+window/size/viewport_height=144
+window/stretch/mode="viewport"
+
+[global_group]
+
+item=""
+tilemap=""
+opponent=""
+hud=""
+
+[layer_names]
+
+2d_physics/layer_1="Player"
+2d_physics/layer_2="Opponent"
+2d_physics/layer_5="Item"
+2d_physics/layer_9="Wall"
+2d_physics/layer_10="Ledge"
+
+[rendering]
+
+renderer/rendering_method="gl_compatibility"
+renderer/rendering_method.mobile="gl_compatibility"
diff --git a/stage/assets/tileset-01.png b/stage/assets/tileset-01.png
new file mode 100644
index 0000000..f2006f8
--- /dev/null
+++ b/stage/assets/tileset-01.png
Binary files differ
diff --git a/stage/assets/tileset-01.png.import b/stage/assets/tileset-01.png.import
new file mode 100644
index 0000000..8429b38
--- /dev/null
+++ b/stage/assets/tileset-01.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://4sbg8fnguw48"
+path="res://.godot/imported/tileset-01.png-85eb1066afb12100d0b0c110ba758473.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://stage/assets/tileset-01.png"
+dest_files=["res://.godot/imported/tileset-01.png-85eb1066afb12100d0b0c110ba758473.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
diff --git a/stage/stage.gd b/stage/stage.gd
new file mode 100644
index 0000000..8d72ee1
--- /dev/null
+++ b/stage/stage.gd
@@ -0,0 +1,15 @@
+class_name Stage
+extends Node2D
+
+
+func get_world_boundaries() -> Dictionary: #Dictionary[Vector2, float]
+ return {
+ Vector2.LEFT: 0.0,
+ Vector2.RIGHT: 0.0,
+ Vector2.UP: 0.0,
+ Vector2.DOWN: 0.0,
+ }
+
+
+func has_win_condition() -> bool:
+ return false
diff --git a/stage/stage.tscn b/stage/stage.tscn
new file mode 100644
index 0000000..9c8e256
--- /dev/null
+++ b/stage/stage.tscn
@@ -0,0 +1,28 @@
+[gd_scene load_steps=3 format=3 uid="uid://ivf0v2snsls5"]
+
+[ext_resource type="Script" path="res://stage/stage.gd" id="1_8ax4l"]
+[ext_resource type="PackedScene" uid="uid://ciyxysx3rwjhf" path="res://ui/hud.tscn" id="5_gnx55"]
+
+[node name="Stage" type="Node2D"]
+script = ExtResource("1_8ax4l")
+
+[node name="ColorRect" type="ColorRect" parent="."]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_right = 256.0
+offset_bottom = 144.0
+grow_horizontal = 2
+grow_vertical = 2
+color = Color(0.419608, 0.65098, 0.290196, 1)
+
+[node name="Opponents" type="Node2D" parent="."]
+unique_name_in_owner = true
+
+[node name="HUD" parent="." instance=ExtResource("5_gnx55")]
+
+[node name="TickTimer" type="Timer" parent="."]
+wait_time = 2.0
+autostart = true
+
+[connection signal="timeout" from="TickTimer" to="." method="_on_tick_timer_timeout"]
diff --git a/stage/stage_01.gd b/stage/stage_01.gd
new file mode 100644
index 0000000..01cc558
--- /dev/null
+++ b/stage/stage_01.gd
@@ -0,0 +1,103 @@
+extends Stage
+
+
+var item_pool: Array = []
+var reserved_item_positions: Array = []
+
+
+func _ready() -> void:
+ $Player.camera.limit_left = get_world_boundaries()[Vector2.LEFT]
+ $Player.camera.limit_right = get_world_boundaries()[Vector2.RIGHT]
+ $Player.camera.limit_top = get_world_boundaries()[Vector2.UP]
+ $Player.camera.limit_bottom = get_world_boundaries()[Vector2.DOWN]
+
+ $TileMapLayer.modulate = Color(max(0.1, randf()), max(0.1, randf()), max(0.1, randf()))
+
+
+func get_world_boundaries() -> Dictionary:
+ return {
+ Vector2.LEFT: $TileMapLayer.get_used_rect().position.x * $TileMapLayer.tile_set.tile_size.x,
+ Vector2.RIGHT: $TileMapLayer.get_used_rect().end.x * $TileMapLayer.tile_set.tile_size.x,
+ Vector2.UP: $TileMapLayer.get_used_rect().position.y * $TileMapLayer.tile_set.tile_size.y - $HUD.size.y,
+ Vector2.DOWN: $TileMapLayer.get_used_rect().end.y * $TileMapLayer.tile_set.tile_size.y,
+ }
+
+
+func has_win_condition() -> bool:
+ return %Opponents.get_child_count() == 0
+
+
+func _on_tick_timer_timeout() -> void:
+ if randf() > 0.8 and item_pool.size() < 3:
+ var item_scene: PackedScene = [
+ preload("res://item/shoe.tscn"),
+ preload("res://item/crown.tscn"),
+ ].pick_random()
+
+ var item: Item = item_scene.instantiate()
+ var map: TileMapLayer = get_tree().get_first_node_in_group("tilemap")
+
+ var size_x := map.get_used_rect().position.x + map.get_used_rect().size.x
+ var size_y := map.get_used_rect().position.y + map.get_used_rect().size.y
+
+ var start_x: int = max(map.get_used_rect().position.x, range(size_x / 2).pick_random())
+ var start_y: int = max(map.get_used_rect().position.y, range(size_y / 2).pick_random())
+
+ var get_map_position = func() -> Vector2i:
+ for x in range(start_x, size_x):
+ for y in range(start_y, size_y):
+ var data = map.get_cell_tile_data(Vector2(x, y))
+ if not data:
+ return Vector2i(x, y)
+ return Vector2i.ZERO
+
+ var map_position = get_map_position.call()
+
+ #print(map_position)
+ if reserved_item_positions.has(map_position):
+ return
+
+ var local_position = map.map_to_local(map_position)
+
+ var _was_shifted := false
+ var collide_top = map.get_cell_tile_data(map.get_neighbor_cell(map_position, TileSet.CELL_NEIGHBOR_TOP_SIDE))
+ var collide_bottom = map.get_cell_tile_data(map.get_neighbor_cell(map_position, TileSet.CELL_NEIGHBOR_BOTTOM_SIDE))
+ var collide_right = map.get_cell_tile_data(map.get_neighbor_cell(map_position, TileSet.CELL_NEIGHBOR_RIGHT_SIDE))
+ if collide_top:
+ local_position += Vector2(0, map.tile_set.tile_size.y / 2)
+ _was_shifted = true
+ if collide_bottom:
+ local_position += Vector2(0, -map.tile_set.tile_size.y / 2)
+ _was_shifted = true
+ if collide_right:
+ local_position += Vector2(-map.tile_set.tile_size.x, 0)
+ _was_shifted = true
+ if not collide_top and not collide_right:
+ if map.get_cell_tile_data(map.get_neighbor_cell(map_position, TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER)):
+ local_position += Vector2(-map.tile_set.tile_size.x, map.tile_set.tile_size.y / 2)
+ _was_shifted = true
+
+ #if not was_shifted:
+ local_position += Vector2(map.tile_set.tile_size.x / 2, 0)
+
+ item.position = local_position
+ add_child(item)
+
+ var get_reserved_positions = func() -> Array[Vector2i]:
+ var rp := [] as Array[Vector2i]
+ for x in range(0, 3):
+ for y in range(0, 3):
+ rp.append(Vector2i(x, y))
+ rp.append(Vector2i(-x, y))
+ rp.append(Vector2i(x, -y))
+ rp.append(Vector2i(-x, -y))
+ return rp
+
+ item.tree_exiting.connect(func():
+ item_pool.erase(item)
+ for v in get_reserved_positions.call():
+ reserved_item_positions.erase(map_position + v)
+ )
+ item_pool.append(item)
+ for v in get_reserved_positions.call():
+ reserved_item_positions.append(map_position + v)
diff --git a/stage/stage_01.tscn b/stage/stage_01.tscn
new file mode 100644
index 0000000..6b0d67c
--- /dev/null
+++ b/stage/stage_01.tscn
@@ -0,0 +1,29 @@
+[gd_scene load_steps=6 format=4 uid="uid://yb0no7vyekil"]
+
+[ext_resource type="Script" path="res://stage/stage_01.gd" id="1_2ycoy"]
+[ext_resource type="PackedScene" uid="uid://dfioemvleakyt" path="res://stage/tile_map_layer.tscn" id="1_4iotk"]
+[ext_resource type="PackedScene" uid="uid://ivf0v2snsls5" path="res://stage/stage.tscn" id="1_uanw1"]
+[ext_resource type="PackedScene" uid="uid://b4t3ipnq8vq2p" path="res://player/player.tscn" id="2_34lp1"]
+[ext_resource type="PackedScene" uid="uid://d1h8psjxqge0a" path="res://player/opponent.tscn" id="4_h35rr"]
+
+[node name="Stage01" instance=ExtResource("1_uanw1")]
+script = ExtResource("1_2ycoy")
+
+[node name="TileMapLayer" parent="." index="1" groups=["tilemap"] instance=ExtResource("1_4iotk")]
+tile_map_data = PackedByteArray("AAAIAAIAAAADAAAAAAAIAAMAAAAAAAAAAAAJAAIAAAAEAAAAAAAJAAMAAAACAAAAAAAKAAsAAAAAAAAAAAAKAAwAAAAAAAEAAAALAAsAAAACAAAAAAALAAwAAAACAAEAAAASAAgAAAAAAAAAAAASAAkAAAAAAAEAAAASAAoAAAAAAAEAAAASAAsAAAAAAAEAAAASAAwAAAAAAAEAAAATAAgAAAACAAAAAAATAAkAAAACAAEAAAATAAoAAAACAAEAAAATAAsAAAACAAEAAAATAAwAAAACAAEAAAAAAAIAAAADAAAAAAAAAAUAAAADAAEAAAAAAAgAAAADAAEAAAAAAAsAAAADAAEAAAAAAA4AAAADAAEAAAAAABEAAAADAAAAAAABAAIAAAAEAAAAAAABAAUAAAADAAEAAAABAAgAAAADAAEAAAABAAsAAAADAAEAAAABAA4AAAADAAEAAAABABEAAAAEAAAAAAACAAIAAAADAAAAAAACAAUAAAADAAEAAAACAAgAAAADAAEAAAACAAsAAAADAAEAAAACAA4AAAADAAEAAAACABEAAAADAAAAAAADAAIAAAAEAAAAAAADAAUAAAADAAEAAAADAAgAAAADAAEAAAADAAsAAAADAAEAAAADAA4AAAADAAEAAAADABEAAAAEAAAAAAAEAAIAAAADAAAAAAAEAAUAAAADAAEAAAAEAAgAAAADAAEAAAAEAAsAAAADAAEAAAAEABEAAAADAAAAAAAFAAIAAAAEAAAAAAAFAAUAAAADAAEAAAAFAAgAAAADAAEAAAAFAAsAAAADAAEAAAAFABEAAAAEAAAAAAAGAAIAAAADAAAAAAAGAAgAAAADAAEAAAAGAAsAAAADAAEAAAAGAA4AAAADAAEAAAAGABEAAAADAAAAAAAHAAIAAAAEAAAAAAAHAAgAAAADAAEAAAAHAAsAAAADAAEAAAAHAA4AAAADAAEAAAAHABEAAAAEAAAAAAAIAAQAAAAAAAEAAAAIAAUAAAAAAAIAAAAIAAsAAAADAAEAAAAIAA4AAAADAAEAAAAIABEAAAADAAAAAAAJAAQAAAACAAEAAAAJAAUAAAACAAIAAAAJAAsAAAADAAEAAAAJAA4AAAADAAEAAAAJABEAAAAEAAAAAAAKAAIAAAADAAAAAAAKAAgAAAADAAEAAAAKAA0AAAAAAAEAAAAKAA4AAAAAAAIAAAAKABEAAAADAAAAAAALAAIAAAAEAAAAAAALAAgAAAADAAEAAAALAA0AAAACAAEAAAALAA4AAAACAAIAAAALABEAAAAEAAAAAAAMAAIAAAADAAAAAAAMAAUAAAADAAEAAAAMAAgAAAADAAEAAAAMAA4AAAADAAEAAAAMABEAAAADAAAAAAANAAIAAAAEAAAAAAANAAUAAAADAAEAAAANAAgAAAADAAEAAAANAA4AAAADAAEAAAANABEAAAAEAAAAAAAOAAIAAAADAAAAAAAOAAUAAAADAAEAAAAOAAgAAAADAAEAAAAOAAsAAAADAAEAAAAOAA4AAAADAAEAAAAOABEAAAADAAAAAAAPAAIAAAAEAAAAAAAPAAUAAAADAAEAAAAPAAgAAAADAAEAAAAPAAsAAAADAAEAAAAPAA4AAAADAAEAAAAPABEAAAAEAAAAAAAQAAIAAAADAAAAAAAQAAUAAAADAAEAAAAQAAgAAAADAAEAAAAQAAsAAAADAAEAAAAQABEAAAADAAAAAAARAAIAAAAEAAAAAAARAAUAAAADAAEAAAARAAgAAAADAAEAAAARAAsAAAADAAEAAAARABEAAAAEAAAAAAASAAIAAAADAAAAAAASAAUAAAADAAEAAAASAA0AAAAAAAEAAAASAA4AAAAAAAIAAAASABEAAAADAAAAAAATAAIAAAAEAAAAAAATAAUAAAADAAEAAAATAA0AAAACAAEAAAATAA4AAAACAAIAAAATABEAAAAEAAAAAAAUAAIAAAADAAAAAAAUAAUAAAADAAEAAAAUAAgAAAADAAEAAAAUABEAAAADAAAAAAAVAAIAAAAEAAAAAAAVAAUAAAADAAEAAAAVAAgAAAADAAEAAAAVABEAAAAEAAAAAAAWAAIAAAADAAAAAAAWAAUAAAADAAEAAAAWAAgAAAADAAEAAAAWABEAAAADAAAAAAAXAAIAAAAEAAAAAAAXAAUAAAADAAEAAAAXAAgAAAADAAEAAAAXABEAAAAEAAAAAAAYAAIAAAADAAAAAAAYABEAAAADAAAAAAAZAAIAAAAEAAAAAAAZABEAAAAEAAAAAAAaAAIAAAADAAAAAAAaABEAAAADAAAAAAAbAAIAAAAEAAAAAAAbABEAAAAEAAAAAAAcAAIAAAADAAAAAAAcABEAAAADAAAAAAAdAAIAAAAEAAAAAAAdABEAAAAEAAAAAAAeAAIAAAADAAAAAAAeABEAAAADAAAAAAAfAAIAAAAEAAAAAAAfABEAAAAEAAAAAAAWAA4AAAADAAEAAAAXAA4AAAADAAEAAAAYAA4AAAADAAEAAAAZAA4AAAADAAEAAAAaAA4AAAADAAEAAAAUAAsAAAADAAEAAAAVAAsAAAADAAEAAAAYAAsAAAADAAEAAAAZAAsAAAADAAEAAAAaAAsAAAADAAEAAAAaAAgAAAADAAEAAAAbAAgAAAADAAEAAAAcAAgAAAADAAEAAAAdAAgAAAADAAEAAAAeAAgAAAADAAEAAAAfAAgAAAADAAEAAAAYAAUAAAADAAEAAAAZAAUAAAADAAEAAAAcAAUAAAADAAEAAAAdAAUAAAADAAEAAAAfAAUAAAADAAEAAAAeAAUAAAADAAEAAAAcAAsAAAAAAAAAAAAcAAwAAAAAAAEAAAAcAA0AAAAAAAEAAAAcAA4AAAAAAAIAAAAdAAsAAAACAAAAAAAdAAwAAAACAAEAAAAdAA0AAAACAAEAAAAdAA4AAAACAAIAAAAbAAsAAAADAAEAAAAbAA4AAAADAAEAAAAeAAsAAAADAAEAAAAfAAsAAAADAAEAAAAeAA4AAAADAAEAAAAfAA4AAAADAAEAAAA=")
+
+[node name="Opponent" parent="Opponents" index="0" instance=ExtResource("4_h35rr")]
+position = Vector2(105, 128)
+current_type = null
+
+[node name="Opponent2" parent="Opponents" index="1" instance=ExtResource("4_h35rr")]
+position = Vector2(52, 80)
+current_type = 1
+
+[node name="Opponent3" parent="Opponents" index="2" instance=ExtResource("4_h35rr")]
+position = Vector2(120, 80)
+current_type = 2
+
+[node name="Player" parent="." index="3" instance=ExtResource("2_34lp1")]
+position = Vector2(16, 128)
+current_type = 2
diff --git a/stage/tile_map_layer.tscn b/stage/tile_map_layer.tscn
new file mode 100644
index 0000000..6fd9df1
--- /dev/null
+++ b/stage/tile_map_layer.tscn
@@ -0,0 +1,44 @@
+[gd_scene load_steps=4 format=3 uid="uid://dfioemvleakyt"]
+
+[ext_resource type="Texture2D" uid="uid://4sbg8fnguw48" path="res://stage/assets/tileset-01.png" id="1_kgkhx"]
+
+[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_kmxxx"]
+texture = ExtResource("1_kgkhx")
+separation = Vector2i(1, 1)
+texture_region_size = Vector2i(8, 8)
+0:0/0 = 0
+0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+1:0/0 = 0
+1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+2:0/0 = 0
+2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+0:1/0 = 0
+0:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+1:1/0 = 0
+1:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+2:1/0 = 0
+2:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+0:2/0 = 0
+0:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+1:2/0 = 0
+1:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+2:2/0 = 0
+2:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+3:0/0 = 0
+3:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
+4:0/0 = 0
+4:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
+3:1/0 = 0
+3:1/0/physics_layer_1/polygon_0/points = PackedVector2Array(-4, -4, -4, 4, 4, 4, 4, -4)
+
+[sub_resource type="TileSet" id="TileSet_277cy"]
+tile_size = Vector2i(8, 8)
+physics_layer_0/collision_layer = 256
+physics_layer_0/collision_mask = 256
+physics_layer_1/collision_layer = 512
+physics_layer_1/collision_mask = 0
+sources/0 = SubResource("TileSetAtlasSource_kmxxx")
+
+[node name="TileMapLayer" type="TileMapLayer"]
+texture_filter = 1
+tile_set = SubResource("TileSet_277cy")
diff --git a/stage/tileset-01.kra b/stage/tileset-01.kra
new file mode 100644
index 0000000..68a3bf4
--- /dev/null
+++ b/stage/tileset-01.kra
Binary files differ
diff --git a/ui/assets/Minimal3x5.ttf b/ui/assets/Minimal3x5.ttf
new file mode 100644
index 0000000..3024b74
--- /dev/null
+++ b/ui/assets/Minimal3x5.ttf
Binary files differ
diff --git a/ui/assets/Minimal3x5.ttf.import b/ui/assets/Minimal3x5.ttf.import
new file mode 100644
index 0000000..17c2eab
--- /dev/null
+++ b/ui/assets/Minimal3x5.ttf.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://16usq1tjtauh"
+path="res://.godot/imported/Minimal3x5.ttf-68b9a4ba08b6cadb0cd3e189612c985e.fontdata"
+
+[deps]
+
+source_file="res://ui/assets/Minimal3x5.ttf"
+dest_files=["res://.godot/imported/Minimal3x5.ttf-68b9a4ba08b6cadb0cd3e189612c985e.fontdata"]
+
+[params]
+
+Rendering=null
+antialiasing=1
+generate_mipmaps=false
+disable_embedded_bitmaps=true
+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={}
diff --git a/ui/assets/Minimal5x5Monospaced.ttf b/ui/assets/Minimal5x5Monospaced.ttf
new file mode 100644
index 0000000..8ef9fa1
--- /dev/null
+++ b/ui/assets/Minimal5x5Monospaced.ttf
Binary files differ
diff --git a/ui/assets/Minimal5x5Monospaced.ttf.import b/ui/assets/Minimal5x5Monospaced.ttf.import
new file mode 100644
index 0000000..294e8fd
--- /dev/null
+++ b/ui/assets/Minimal5x5Monospaced.ttf.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://2hbnsvgx1y4u"
+path="res://.godot/imported/Minimal5x5Monospaced.ttf-fd9125b575442d5a0ab82dd016487ac3.fontdata"
+
+[deps]
+
+source_file="res://ui/assets/Minimal5x5Monospaced.ttf"
+dest_files=["res://.godot/imported/Minimal5x5Monospaced.ttf-fd9125b575442d5a0ab82dd016487ac3.fontdata"]
+
+[params]
+
+Rendering=null
+antialiasing=1
+generate_mipmaps=false
+disable_embedded_bitmaps=true
+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={}
diff --git a/ui/assets/Minimal5x7.ttf b/ui/assets/Minimal5x7.ttf
new file mode 100644
index 0000000..7372987
--- /dev/null
+++ b/ui/assets/Minimal5x7.ttf
Binary files differ
diff --git a/ui/assets/Minimal5x7.ttf.import b/ui/assets/Minimal5x7.ttf.import
new file mode 100644
index 0000000..dad8bcf
--- /dev/null
+++ b/ui/assets/Minimal5x7.ttf.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://c5se3wxtkeley"
+path="res://.godot/imported/Minimal5x7.ttf-a34c0ec56184d93c2e894a2cb938e1c0.fontdata"
+
+[deps]
+
+source_file="res://ui/assets/Minimal5x7.ttf"
+dest_files=["res://.godot/imported/Minimal5x7.ttf-a34c0ec56184d93c2e894a2cb938e1c0.fontdata"]
+
+[params]
+
+Rendering=null
+antialiasing=1
+generate_mipmaps=false
+disable_embedded_bitmaps=true
+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={}
diff --git a/ui/hud.gd b/ui/hud.gd
new file mode 100644
index 0000000..49c5d34
--- /dev/null
+++ b/ui/hud.gd
@@ -0,0 +1,13 @@
+class_name HUD
+extends CanvasLayer
+
+
+var size: Vector2:
+ get():
+ return get_child(0).size
+
+
+var score: int:
+ set(value):
+ score = value
+ %Score.text = str(score)
diff --git a/ui/hud.tscn b/ui/hud.tscn
new file mode 100644
index 0000000..340d7a2
--- /dev/null
+++ b/ui/hud.tscn
@@ -0,0 +1,34 @@
+[gd_scene load_steps=3 format=3 uid="uid://ciyxysx3rwjhf"]
+
+[ext_resource type="Script" path="res://ui/hud.gd" id="1_c8cqk"]
+[ext_resource type="Theme" uid="uid://b067xhqktnmhr" path="res://ui/theme.tres" id="1_it884"]
+
+[node name="HUD" type="CanvasLayer" groups=["hud"]]
+script = ExtResource("1_c8cqk")
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+custom_minimum_size = Vector2(0, 16)
+offset_right = 43.0
+offset_bottom = 10.0
+theme_override_constants/margin_left = 2
+theme_override_constants/margin_top = 2
+theme_override_constants/margin_right = 2
+theme_override_constants/margin_bottom = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
+layout_mode = 2
+size_flags_horizontal = 0
+size_flags_vertical = 0
+
+[node name="Label" type="Label" parent="MarginContainer/HBoxContainer"]
+texture_filter = 1
+layout_mode = 2
+theme = ExtResource("1_it884")
+text = "Score:"
+
+[node name="Score" type="Label" parent="MarginContainer/HBoxContainer"]
+unique_name_in_owner = true
+texture_filter = 1
+layout_mode = 2
+theme = ExtResource("1_it884")
+text = "0"
diff --git a/ui/start_screen.gd b/ui/start_screen.gd
new file mode 100644
index 0000000..418e407
--- /dev/null
+++ b/ui/start_screen.gd
@@ -0,0 +1,13 @@
+extends Control
+
+
+func _ready() -> void:
+ %CountdownTimer.start()
+
+
+func _process(delta: float) -> void:
+ %CountdownLabel.text = "%.1f" % %CountdownTimer.time_left
+
+
+func _on_countdown_timer_timeout() -> void:
+ (func(): get_tree().change_scene_to_file("res://stage/stage_01.tscn")).call_deferred()
diff --git a/ui/start_screen.tscn b/ui/start_screen.tscn
new file mode 100644
index 0000000..6d40d01
--- /dev/null
+++ b/ui/start_screen.tscn
@@ -0,0 +1,51 @@
+[gd_scene load_steps=3 format=3 uid="uid://brfnvqsla72pn"]
+
+[ext_resource type="Script" path="res://ui/start_screen.gd" id="1_bpjye"]
+[ext_resource type="Theme" uid="uid://b067xhqktnmhr" path="res://ui/theme.tres" id="2_qfrkp"]
+
+[node name="StartScreen" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_bpjye")
+
+[node name="ColorRect" type="ColorRect" parent="."]
+layout_mode = 0
+offset_right = 160.0
+offset_bottom = 144.0
+color = Color(0.419608, 0.65098, 0.290196, 1)
+
+[node name="CenterContainer" type="CenterContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer"]
+layout_mode = 2
+theme_override_constants/separation = 2
+
+[node name="Label" type="Label" parent="CenterContainer/HBoxContainer"]
+texture_filter = 1
+layout_mode = 2
+theme = ExtResource("2_qfrkp")
+text = "Starting in"
+
+[node name="CountdownLabel" type="Label" parent="CenterContainer/HBoxContainer"]
+unique_name_in_owner = true
+texture_filter = 1
+layout_mode = 2
+theme = ExtResource("2_qfrkp")
+text = "0"
+
+[node name="CountdownTimer" type="Timer" parent="."]
+unique_name_in_owner = true
+wait_time = 3.0
+one_shot = true
+
+[connection signal="timeout" from="CountdownTimer" to="." method="_on_countdown_timer_timeout"]
diff --git a/ui/theme.tres b/ui/theme.tres
new file mode 100644
index 0000000..eb181eb
--- /dev/null
+++ b/ui/theme.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Theme" load_steps=2 format=3 uid="uid://b067xhqktnmhr"]
+
+[ext_resource type="FontFile" uid="uid://16usq1tjtauh" path="res://ui/assets/Minimal3x5.ttf" id="1_qtw8w"]
+
+[resource]
+Label/colors/font_color = Color(0.12549, 0.345098, 0.313726, 1)
+Label/font_sizes/font_size = 8
+Label/fonts/font = ExtResource("1_qtw8w")