summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig4
-rw-r--r--.gitattributes2
-rw-r--r--.gitignore3
-rw-r--r--Minimal3x5.ttfbin0 -> 10612 bytes
-rw-r--r--Minimal3x5.ttf.import36
-rw-r--r--TetrominoBar.pngbin0 -> 2146 bytes
-rw-r--r--TetrominoBar.png.import40
-rw-r--r--TetrominoCube.pngbin0 -> 5685 bytes
-rw-r--r--TetrominoCube.png.import40
-rw-r--r--TetrominoJ.pngbin0 -> 3425 bytes
-rw-r--r--TetrominoJ.png.import40
-rw-r--r--TetrominoL.pngbin0 -> 3502 bytes
-rw-r--r--TetrominoL.png.import40
-rw-r--r--TetrominoS.pngbin0 -> 3291 bytes
-rw-r--r--TetrominoS.png.import40
-rw-r--r--TetrominoT.pngbin0 -> 2642 bytes
-rw-r--r--TetrominoT.png.import40
-rw-r--r--TetrominoZ.pngbin0 -> 3343 bytes
-rw-r--r--TetrominoZ.png.import40
-rw-r--r--icon.svg1
-rw-r--r--icon.svg.import43
-rw-r--r--main.gd260
-rw-r--r--main.gd.uid1
-rw-r--r--main.tscn104
-rw-r--r--preview-segment-6x6.krabin0 -> 26543 bytes
-rw-r--r--preview-segment-6x6.pngbin0 -> 119 bytes
-rw-r--r--preview-segment-6x6.png.import40
-rw-r--r--preview-segment-8x8.krabin0 -> 21623 bytes
-rw-r--r--preview-segment-8x8.pngbin0 -> 120 bytes
-rw-r--r--preview-segment-8x8.png.import40
-rw-r--r--project.godot33
-rw-r--r--segment-5x5.krabin0 -> 32956 bytes
-rw-r--r--segment-5x5.pngbin0 -> 117 bytes
-rw-r--r--segment-5x5.png.import40
-rw-r--r--segment-6x6.krabin0 -> 31673 bytes
-rw-r--r--segment-6x6.pngbin0 -> 124 bytes
-rw-r--r--segment-6x6.png.import40
-rw-r--r--segment-8x8.krabin0 -> 21184 bytes
-rw-r--r--segment-8x8.pngbin0 -> 133 bytes
-rw-r--r--segment-8x8.png.import40
-rw-r--r--segment.krabin0 -> 21564 bytes
-rw-r--r--segment.pngbin0 -> 155 bytes
-rw-r--r--segment.png.import40
-rw-r--r--tetromino.gd101
-rw-r--r--tetromino.gd.uid1
-rw-r--r--tetromino.tscn17
-rw-r--r--tetromino_bar.gd8
-rw-r--r--tetromino_bar.gd.uid1
-rw-r--r--tetromino_bar.tscn17
-rw-r--r--tetromino_cube.gd12
-rw-r--r--tetromino_cube.gd.uid1
-rw-r--r--tetromino_cube.tscn17
-rw-r--r--tetromino_j.gd8
-rw-r--r--tetromino_j.gd.uid1
-rw-r--r--tetromino_j.tscn17
-rw-r--r--tetromino_l.gd8
-rw-r--r--tetromino_l.gd.uid1
-rw-r--r--tetromino_l.tscn17
-rw-r--r--tetromino_s.gd8
-rw-r--r--tetromino_s.gd.uid1
-rw-r--r--tetromino_s.tscn17
-rw-r--r--tetromino_segment.gd2
-rw-r--r--tetromino_segment.gd.uid1
-rw-r--r--tetromino_segment.tscn11
-rw-r--r--tetromino_t.gd8
-rw-r--r--tetromino_t.gd.uid1
-rw-r--r--tetromino_t.tscn17
-rw-r--r--tetromino_z.gd8
-rw-r--r--tetromino_z.gd.uid1
-rw-r--r--tetromino_z.tscn17
-rw-r--r--theme.tres8
-rw-r--r--ui.krabin0 -> 28779 bytes
-rw-r--r--ui.pngbin0 -> 1083 bytes
-rw-r--r--ui.png.import40
74 files changed, 1374 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..f28239b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+root = true
+
+[*]
+charset = utf-8
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/Minimal3x5.ttf b/Minimal3x5.ttf
new file mode 100644
index 0000000..3024b74
--- /dev/null
+++ b/Minimal3x5.ttf
Binary files differ
diff --git a/Minimal3x5.ttf.import b/Minimal3x5.ttf.import
new file mode 100644
index 0000000..6237f64
--- /dev/null
+++ b/Minimal3x5.ttf.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="font_data_dynamic"
+type="FontFile"
+uid="uid://nkinuhroocu"
+path="res://.godot/imported/Minimal3x5.ttf-9d8e4aac2c963dd9da3e7d9ca1cb107f.fontdata"
+
+[deps]
+
+source_file="res://Minimal3x5.ttf"
+dest_files=["res://.godot/imported/Minimal3x5.ttf-9d8e4aac2c963dd9da3e7d9ca1cb107f.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
+modulate_color_glyphs=false
+hinting=1
+subpixel_positioning=4
+keep_rounding_remainders=true
+oversampling=0.0
+Fallbacks=null
+fallbacks=[]
+Compress=null
+compress=true
+preload=[]
+language_support={}
+script_support={}
+opentype_features={}
diff --git a/TetrominoBar.png b/TetrominoBar.png
new file mode 100644
index 0000000..2537d63
--- /dev/null
+++ b/TetrominoBar.png
Binary files differ
diff --git a/TetrominoBar.png.import b/TetrominoBar.png.import
new file mode 100644
index 0000000..601f24d
--- /dev/null
+++ b/TetrominoBar.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dklmkjfgsf62r"
+path="res://.godot/imported/TetrominoBar.png-a6206e0b0ff9ba5a1764431edd180a0b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoBar.png"
+dest_files=["res://.godot/imported/TetrominoBar.png-a6206e0b0ff9ba5a1764431edd180a0b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/TetrominoCube.png b/TetrominoCube.png
new file mode 100644
index 0000000..b64ea6a
--- /dev/null
+++ b/TetrominoCube.png
Binary files differ
diff --git a/TetrominoCube.png.import b/TetrominoCube.png.import
new file mode 100644
index 0000000..58de499
--- /dev/null
+++ b/TetrominoCube.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cli0jgwfg4144"
+path="res://.godot/imported/TetrominoCube.png-eef91e66f1ec0233433dc816c4109520.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoCube.png"
+dest_files=["res://.godot/imported/TetrominoCube.png-eef91e66f1ec0233433dc816c4109520.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/TetrominoJ.png b/TetrominoJ.png
new file mode 100644
index 0000000..9742925
--- /dev/null
+++ b/TetrominoJ.png
Binary files differ
diff --git a/TetrominoJ.png.import b/TetrominoJ.png.import
new file mode 100644
index 0000000..b809b81
--- /dev/null
+++ b/TetrominoJ.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://psvkpjm8dqda"
+path="res://.godot/imported/TetrominoJ.png-7b804352d12a2da1698f4c4180b03e3b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoJ.png"
+dest_files=["res://.godot/imported/TetrominoJ.png-7b804352d12a2da1698f4c4180b03e3b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/TetrominoL.png b/TetrominoL.png
new file mode 100644
index 0000000..76c3948
--- /dev/null
+++ b/TetrominoL.png
Binary files differ
diff --git a/TetrominoL.png.import b/TetrominoL.png.import
new file mode 100644
index 0000000..0713487
--- /dev/null
+++ b/TetrominoL.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://r1k16gr6fg7o"
+path="res://.godot/imported/TetrominoL.png-06ddd7713314f0cdf634b7f34d969793.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoL.png"
+dest_files=["res://.godot/imported/TetrominoL.png-06ddd7713314f0cdf634b7f34d969793.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/TetrominoS.png b/TetrominoS.png
new file mode 100644
index 0000000..b9122ab
--- /dev/null
+++ b/TetrominoS.png
Binary files differ
diff --git a/TetrominoS.png.import b/TetrominoS.png.import
new file mode 100644
index 0000000..f3743c9
--- /dev/null
+++ b/TetrominoS.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://h3ptxwm3l2gl"
+path="res://.godot/imported/TetrominoS.png-d871904d5b135242667dd23df7cba7a2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoS.png"
+dest_files=["res://.godot/imported/TetrominoS.png-d871904d5b135242667dd23df7cba7a2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/TetrominoT.png b/TetrominoT.png
new file mode 100644
index 0000000..48c96d8
--- /dev/null
+++ b/TetrominoT.png
Binary files differ
diff --git a/TetrominoT.png.import b/TetrominoT.png.import
new file mode 100644
index 0000000..a337591
--- /dev/null
+++ b/TetrominoT.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dk7wynbjbour"
+path="res://.godot/imported/TetrominoT.png-83e99385723cc262b340dfd85094286d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoT.png"
+dest_files=["res://.godot/imported/TetrominoT.png-83e99385723cc262b340dfd85094286d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/TetrominoZ.png b/TetrominoZ.png
new file mode 100644
index 0000000..d33b8c1
--- /dev/null
+++ b/TetrominoZ.png
Binary files differ
diff --git a/TetrominoZ.png.import b/TetrominoZ.png.import
new file mode 100644
index 0000000..a905284
--- /dev/null
+++ b/TetrominoZ.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bnb4jb2v6oxqd"
+path="res://.godot/imported/TetrominoZ.png-be8faaef0f8e649327d41227e21b2e9a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://TetrominoZ.png"
+dest_files=["res://.godot/imported/TetrominoZ.png-be8faaef0f8e649327d41227e21b2e9a.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/icon.svg b/icon.svg
new file mode 100644
index 0000000..c6bbb7d
--- /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>
diff --git a/icon.svg.import b/icon.svg.import
new file mode 100644
index 0000000..4b49dda
--- /dev/null
+++ b/icon.svg.import
@@ -0,0 +1,43 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bochw3lqqvg3r"
+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/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/main.gd b/main.gd
new file mode 100644
index 0000000..aef207c
--- /dev/null
+++ b/main.gd
@@ -0,0 +1,260 @@
+extends Node2D
+
+
+const TETROMINO_POOL = [
+ preload("res://tetromino_bar.tscn"),
+ preload("res://tetromino_cube.tscn"),
+ preload("res://tetromino_t.tscn"),
+ preload("res://tetromino_s.tscn"),
+ preload("res://tetromino_z.tscn"),
+ preload("res://tetromino_j.tscn"),
+ preload("res://tetromino_l.tscn"),
+]
+
+const INPUT_BUFFER_TRHESHOLD := 0.1
+var INPUT_BUFFER_MAP: Dictionary[String, float] = {
+ #"ui_up": INPUT_BUFFER_TRHESHOLD,
+ "ui_left": INPUT_BUFFER_TRHESHOLD,
+ "ui_right": INPUT_BUFFER_TRHESHOLD,
+ "ui_down": INPUT_BUFFER_TRHESHOLD,
+}
+
+
+signal tetromino_reached_bottom
+signal game_over
+
+
+@export var score_threshold: int
+
+
+var grid: Dictionary[Vector2i, TetrominoSegment]
+var grid_bounds: Rect2i
+
+var current_tetromino: Tetromino
+var next_tetromino: Tetromino: set = set_next_tetromino
+
+var score: int
+
+
+func _ready() -> void:
+ grid_bounds = get_grid_bounds()
+
+ next_tetromino = TETROMINO_POOL.pick_random().instantiate()
+ _on_tick_timer_timeout()
+
+ game_over.connect(_on_game_over)
+
+
+func _input(event: InputEvent) -> void:
+ if event.is_action_pressed("ui_up"):
+ rotate_current_tetromino(1.0)
+
+
+func _process(delta: float) -> void:
+ if Input.is_action_pressed("ui_left") and INPUT_BUFFER_MAP["ui_left"] > INPUT_BUFFER_TRHESHOLD:
+ move_current_tetromino(Vector2i.LEFT)
+ INPUT_BUFFER_MAP["ui_left"] = 0.0
+
+ if Input.is_action_pressed("ui_right") and INPUT_BUFFER_MAP["ui_right"] > INPUT_BUFFER_TRHESHOLD:
+ move_current_tetromino(Vector2i.RIGHT)
+ INPUT_BUFFER_MAP["ui_right"] = 0.0
+
+ if Input.is_action_pressed("ui_down") and INPUT_BUFFER_MAP["ui_down"] > INPUT_BUFFER_TRHESHOLD:
+ move_current_tetromino(Vector2i.DOWN)
+ INPUT_BUFFER_MAP["ui_down"] = 0.0
+
+ for key in INPUT_BUFFER_MAP.keys():
+ INPUT_BUFFER_MAP[key] += delta
+
+ if OS.is_debug_build():
+ if current_tetromino:
+ %Debug.text = "P: %s" % current_tetromino.current_grid_position
+ %Debug.text += "\nPS: %s" % " ".join(current_tetromino.get_grid_occupations())
+ else:
+ %Debug.text = ""
+
+
+func set_next_tetromino(value: Tetromino) -> void:
+ next_tetromino = value
+ %NextTetromino.texture = load("%s.png" % next_tetromino.name)
+
+
+func spawn_tetromino() -> Tetromino:
+ var tetromino: Tetromino = next_tetromino
+ tetromino.init($Grid, $Grid.local_to_map($SpawnPosition.global_position))
+
+ return tetromino
+
+
+func set_current_tetromino_to_grid() -> void:
+ var grid_segments := current_tetromino.get_grid_segments()
+
+ var mapped: Dictionary[int, Variant]
+ for grid_position: Vector2i in grid_segments.keys():
+ if grid.get(grid_position, null) != null:
+ game_over.emit()
+ break
+
+ grid.set(grid_position, grid_segments.get(grid_position))
+ mapped.set(grid_position.y, true)
+
+ $ProjectionSegments.visible = false
+ clear_rows(mapped.keys())
+
+ current_tetromino = null
+
+
+func clear_rows(rows_to_check: Array[int] = []) -> void:
+ if rows_to_check.is_empty():
+ rows_to_check.assign(range(grid_bounds.size.y))
+
+ var filled_rows: Array[int]
+
+ for y in rows_to_check:
+ var row_is_filled := true
+ for x in range(grid_bounds.size.x):
+ row_is_filled = row_is_filled and grid.get(Vector2i(x, y), null)
+ if not row_is_filled:
+ break
+
+ if row_is_filled:
+ filled_rows.append(y)
+
+ # no rows filled? return
+ if filled_rows.size() == 0:
+ return
+
+ # sort rows
+ filled_rows.sort()
+
+ $TickTimer.paused = true
+
+ # animate
+ var tween = create_tween().set_parallel()
+ for y in filled_rows:
+ for x in range(grid_bounds.size.x):
+ var segment: TetrominoSegment = grid.get(Vector2i(x, y))
+ var previous_modulate := segment.modulate
+ tween.tween_property(segment, "modulate", Color(10, 10, 10, 1), 0.3)
+ tween.tween_property(segment, "modulate", previous_modulate, 0.3).set_delay(0.3)
+ tween.tween_property(segment, "modulate", Color(10, 10, 10, 1), 0.3).set_delay(0.6)
+ tween.tween_property(segment, "modulate", previous_modulate, 0.3).set_delay(0.9)
+ await tween.finished
+
+ # remove segments
+ for y in filled_rows:
+ for x in range(grid_bounds.size.x):
+ grid.get(Vector2i(x, y)).queue_free()
+ grid.set(Vector2i(x, y), null)
+
+ # shift rows down
+ for y in filled_rows:
+ for n in range(y - 1, 0, -1):
+ for x in range(grid_bounds.size.x):
+ var segment: TetrominoSegment = grid.get(Vector2i(x, n), null)
+ grid.set(Vector2i(x, n + 1), segment)
+ grid.set(Vector2i(x, n), null)
+ if is_instance_valid(segment):
+ segment.global_position.y += $Grid.tile_set.tile_size.y
+
+ # increase score and game speed
+ score += int(100 * pow(filled_rows.size(), 2))
+ %Score.text = str(score)
+ $TickTimer.wait_time = 1.0 - (score / float(score_threshold))
+
+ $TickTimer.paused = false
+
+
+func rotate_current_tetromino(direction: float) -> void:
+ if not current_tetromino:
+ return
+
+ for grid_position in current_tetromino.get_grid_occupations(Vector2.ZERO, direction):
+ if grid.get(grid_position, null) or not grid_bounds.has_point(grid_position):
+ return
+
+ current_tetromino.do_rotation(direction)
+ update_projection()
+
+
+func move_current_tetromino(direction: Vector2i) -> void:
+ if not current_tetromino:
+ return
+
+ for grid_position in current_tetromino.get_grid_occupations(direction):
+ if direction == Vector2i.DOWN:
+ if grid.get(grid_position, null) or grid_position.y >= grid_bounds.size.y:
+ set_current_tetromino_to_grid()
+ tetromino_reached_bottom.emit()
+ return
+
+ elif grid.get(grid_position, null) or not grid_bounds.has_point(grid_position):
+ return
+
+ current_tetromino.current_grid_position += direction
+ update_projection()
+
+
+func advance_current_tetromino() -> void:
+ move_current_tetromino(Vector2i.DOWN)
+
+
+func update_projection() -> void:
+ var current_segments := current_tetromino.get_grid_occupations()
+ current_segments.sort_custom(func (a: Vector2i, b: Vector2i):
+ return a.y < b.y
+ )
+
+ var highest_segment: int = current_segments[0].y
+ var lowest_segment: int = current_segments[3].y
+
+ var colliding_segment: int = lowest_segment
+ var colliding_row := grid_bounds.size.y
+ var is_colliding := false
+
+ for y in range(grid_bounds.size.y - highest_segment):
+ for segment in current_segments:
+ if grid.get(Vector2i(segment.x, segment.y + y), null):
+ colliding_row = segment.y + y
+ colliding_segment = segment.y
+ is_colliding = true
+ break
+ elif segment.y + y >= grid_bounds.size.y:
+ is_colliding = true
+ break
+ if is_colliding:
+ break
+
+ var projection_segments := $ProjectionSegments.get_children()
+ for index in current_segments.size():
+ var segment := current_segments[index]
+ var difference := colliding_segment - segment.y
+ projection_segments[index].global_position = Vector2(
+ segment.x,
+ colliding_row - 1 - difference
+ ) * Vector2($Grid.tile_set.tile_size) + $Grid.position
+
+ $ProjectionSegments.visible = true
+
+
+func get_grid_bounds() -> Rect2i:
+ return Rect2i(
+ #Vector2i($Area.global_position - ($Area.shape.size / 2.0)) / $Grid.tile_set.tile_size,
+ Vector2.ZERO,
+ Vector2i($Area.shape.size) / $Grid.tile_set.tile_size
+ )
+
+
+func _on_tick_timer_timeout() -> void:
+ if current_tetromino:
+ advance_current_tetromino()
+ else:
+ current_tetromino = spawn_tetromino()
+ add_child(current_tetromino)
+ update_projection()
+
+ next_tetromino = TETROMINO_POOL.pick_random().instantiate()
+
+
+func _on_game_over() -> void:
+ get_tree().quit()
diff --git a/main.gd.uid b/main.gd.uid
new file mode 100644
index 0000000..5704810
--- /dev/null
+++ b/main.gd.uid
@@ -0,0 +1 @@
+uid://bk0pedc84ybq4
diff --git a/main.tscn b/main.tscn
new file mode 100644
index 0000000..6746914
--- /dev/null
+++ b/main.tscn
@@ -0,0 +1,104 @@
+[gd_scene format=3 uid="uid://7we6j188njrf"]
+
+[ext_resource type="Script" uid="uid://bk0pedc84ybq4" path="res://main.gd" id="1_ig7tw"]
+[ext_resource type="Theme" uid="uid://qlaurqwpvca4" path="res://theme.tres" id="2_0xm2m"]
+[ext_resource type="Texture2D" uid="uid://ck2vq6wfki52d" path="res://ui.png" id="2_h2yge"]
+[ext_resource type="Texture2D" uid="uid://b2xdvg8kpuenh" path="res://preview-segment-6x6.png" id="4_1bvp3"]
+
+[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_1bvp3"]
+texture = ExtResource("2_h2yge")
+
+[sub_resource type="TileSet" id="TileSet_ig7tw"]
+tile_size = Vector2i(6, 6)
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_h2yge"]
+size = Vector2(108, 132)
+
+[node name="Main" type="Node2D" unique_id=1578992227]
+script = ExtResource("1_ig7tw")
+score_threshold = 10000
+
+[node name="CanvasLayer" type="CanvasLayer" parent="." unique_id=2121828730]
+layer = -1
+
+[node name="PanelContainer" type="PanelContainer" parent="CanvasLayer" unique_id=708690395]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+theme = ExtResource("2_0xm2m")
+theme_override_styles/panel = SubResource("StyleBoxTexture_1bvp3")
+
+[node name="Control" type="Control" parent="CanvasLayer/PanelContainer" unique_id=1247878242]
+layout_mode = 2
+
+[node name="NextTetromino" type="TextureRect" parent="CanvasLayer/PanelContainer/Control" unique_id=1522928335]
+unique_name_in_owner = true
+layout_mode = 0
+offset_left = 119.0
+offset_top = 6.0
+offset_right = 154.0
+offset_bottom = 33.0
+theme = ExtResource("2_0xm2m")
+expand_mode = 2
+stretch_mode = 5
+
+[node name="Score" type="Label" parent="CanvasLayer/PanelContainer/Control" unique_id=399456442]
+unique_name_in_owner = true
+layout_mode = 0
+offset_left = 117.0
+offset_top = 38.0
+offset_right = 156.0
+offset_bottom = 44.0
+text = "0"
+horizontal_alignment = 1
+
+[node name="Debug" type="Label" parent="CanvasLayer/PanelContainer/Control" unique_id=2044531315]
+unique_name_in_owner = true
+layout_mode = 0
+offset_left = 8.0
+offset_top = 8.0
+offset_right = 48.0
+offset_bottom = 31.0
+
+[node name="TickTimer" type="Timer" parent="." unique_id=439884902]
+autostart = true
+
+[node name="SpawnPosition" type="Marker2D" parent="." unique_id=1490938145]
+position = Vector2(59, 18)
+
+[node name="Grid" type="TileMapLayer" parent="." unique_id=647850505]
+position = Vector2(5, 6)
+tile_set = SubResource("TileSet_ig7tw")
+
+[node name="Area" type="CollisionShape2D" parent="." unique_id=758334154]
+position = Vector2(59, 72)
+shape = SubResource("RectangleShape2D_h2yge")
+
+[node name="RowOverlay" type="ColorRect" parent="." unique_id=1840142850]
+visible = false
+offset_right = 40.0
+offset_bottom = 40.0
+
+[node name="ProjectionSegments" type="Node2D" parent="." unique_id=962002920]
+visible = false
+modulate = Color(1, 1, 1, 0.39215687)
+
+[node name="ProjectionSegment" type="Sprite2D" parent="ProjectionSegments" unique_id=1439186625]
+texture = ExtResource("4_1bvp3")
+centered = false
+
+[node name="ProjectionSegment2" type="Sprite2D" parent="ProjectionSegments" unique_id=150716240]
+texture = ExtResource("4_1bvp3")
+centered = false
+
+[node name="ProjectionSegment3" type="Sprite2D" parent="ProjectionSegments" unique_id=2060331950]
+texture = ExtResource("4_1bvp3")
+centered = false
+
+[node name="ProjectionSegment4" type="Sprite2D" parent="ProjectionSegments" unique_id=1657273535]
+texture = ExtResource("4_1bvp3")
+centered = false
+
+[connection signal="timeout" from="TickTimer" to="." method="_on_tick_timer_timeout"]
diff --git a/preview-segment-6x6.kra b/preview-segment-6x6.kra
new file mode 100644
index 0000000..39eb7bb
--- /dev/null
+++ b/preview-segment-6x6.kra
Binary files differ
diff --git a/preview-segment-6x6.png b/preview-segment-6x6.png
new file mode 100644
index 0000000..f3a31d2
--- /dev/null
+++ b/preview-segment-6x6.png
Binary files differ
diff --git a/preview-segment-6x6.png.import b/preview-segment-6x6.png.import
new file mode 100644
index 0000000..dc52519
--- /dev/null
+++ b/preview-segment-6x6.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b2xdvg8kpuenh"
+path="res://.godot/imported/preview-segment-6x6.png-13a98961d84cdb7b49604511c432aa53.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://preview-segment-6x6.png"
+dest_files=["res://.godot/imported/preview-segment-6x6.png-13a98961d84cdb7b49604511c432aa53.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/preview-segment-8x8.kra b/preview-segment-8x8.kra
new file mode 100644
index 0000000..955403e
--- /dev/null
+++ b/preview-segment-8x8.kra
Binary files differ
diff --git a/preview-segment-8x8.png b/preview-segment-8x8.png
new file mode 100644
index 0000000..f91f9ca
--- /dev/null
+++ b/preview-segment-8x8.png
Binary files differ
diff --git a/preview-segment-8x8.png.import b/preview-segment-8x8.png.import
new file mode 100644
index 0000000..3c7545b
--- /dev/null
+++ b/preview-segment-8x8.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://1xtaar7etfu5"
+path="res://.godot/imported/preview-segment-8x8.png-b3eda2647f8a35a041dc54a2ccc5ad64.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://preview-segment-8x8.png"
+dest_files=["res://.godot/imported/preview-segment-8x8.png-b3eda2647f8a35a041dc54a2ccc5ad64.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/project.godot b/project.godot
new file mode 100644
index 0000000..e19acc3
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,33 @@
+; 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
+
+[animation]
+
+compatibility/default_parent_skeleton_in_mesh_instance_3d=true
+
+[application]
+
+config/name="Tuxtris"
+run/main_scene="uid://7we6j188njrf"
+config/features=PackedStringArray("4.6", "GL Compatibility")
+config/icon="res://icon.svg"
+
+[display]
+
+window/size/viewport_width=160
+window/size/viewport_height=144
+window/stretch/mode="viewport"
+window/stretch/scale_mode="integer"
+
+[rendering]
+
+textures/canvas_textures/default_texture_filter=0
+renderer/rendering_method="gl_compatibility"
+renderer/rendering_method.mobile="gl_compatibility"
diff --git a/segment-5x5.kra b/segment-5x5.kra
new file mode 100644
index 0000000..80297c5
--- /dev/null
+++ b/segment-5x5.kra
Binary files differ
diff --git a/segment-5x5.png b/segment-5x5.png
new file mode 100644
index 0000000..119b2d5
--- /dev/null
+++ b/segment-5x5.png
Binary files differ
diff --git a/segment-5x5.png.import b/segment-5x5.png.import
new file mode 100644
index 0000000..f6a449a
--- /dev/null
+++ b/segment-5x5.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dqpvdjhwsvyfa"
+path="res://.godot/imported/segment-5x5.png-8f3f98abab920db4c3f30ba2e2dfd5aa.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://segment-5x5.png"
+dest_files=["res://.godot/imported/segment-5x5.png-8f3f98abab920db4c3f30ba2e2dfd5aa.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/segment-6x6.kra b/segment-6x6.kra
new file mode 100644
index 0000000..7bb7007
--- /dev/null
+++ b/segment-6x6.kra
Binary files differ
diff --git a/segment-6x6.png b/segment-6x6.png
new file mode 100644
index 0000000..18b884b
--- /dev/null
+++ b/segment-6x6.png
Binary files differ
diff --git a/segment-6x6.png.import b/segment-6x6.png.import
new file mode 100644
index 0000000..7c8241f
--- /dev/null
+++ b/segment-6x6.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dbud1vd4f3ymh"
+path="res://.godot/imported/segment-6x6.png-464e4ebf9ee3ba88ea2aa493a632f705.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://segment-6x6.png"
+dest_files=["res://.godot/imported/segment-6x6.png-464e4ebf9ee3ba88ea2aa493a632f705.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/segment-8x8.kra b/segment-8x8.kra
new file mode 100644
index 0000000..2647f73
--- /dev/null
+++ b/segment-8x8.kra
Binary files differ
diff --git a/segment-8x8.png b/segment-8x8.png
new file mode 100644
index 0000000..9f3bb3c
--- /dev/null
+++ b/segment-8x8.png
Binary files differ
diff --git a/segment-8x8.png.import b/segment-8x8.png.import
new file mode 100644
index 0000000..d2cd024
--- /dev/null
+++ b/segment-8x8.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dbm1k1quf5f7p"
+path="res://.godot/imported/segment-8x8.png-efea0ffa146e230f4e470636614bfcf7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://segment-8x8.png"
+dest_files=["res://.godot/imported/segment-8x8.png-efea0ffa146e230f4e470636614bfcf7.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/segment.kra b/segment.kra
new file mode 100644
index 0000000..c4c9dc1
--- /dev/null
+++ b/segment.kra
Binary files differ
diff --git a/segment.png b/segment.png
new file mode 100644
index 0000000..22238fb
--- /dev/null
+++ b/segment.png
Binary files differ
diff --git a/segment.png.import b/segment.png.import
new file mode 100644
index 0000000..7807c95
--- /dev/null
+++ b/segment.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d1dv0o7stpfn0"
+path="res://.godot/imported/segment.png-4f8469c0d2d2d0007c471df5d7d2ba3a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://segment.png"
+dest_files=["res://.godot/imported/segment.png-4f8469c0d2d2d0007c471df5d7d2ba3a.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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/tetromino.gd b/tetromino.gd
new file mode 100644
index 0000000..6fd053b
--- /dev/null
+++ b/tetromino.gd
@@ -0,0 +1,101 @@
+@tool
+@abstract
+class_name Tetromino
+extends Node2D
+
+
+var segments: Array[TetrominoSegment]
+
+var grid: TileMapLayer
+
+var current_grid_position: Vector2i: set = set_current_grid_position
+var current_segment_positions: Array[Vector2i]: set = set_current_segment_positions
+
+@onready var base_segment: TetrominoSegment = $BaseSegment
+
+
+func init(init_grid: TileMapLayer, init_position: Vector2i) -> void:
+ grid = init_grid
+ current_grid_position = init_position
+
+
+func _ready() -> void:
+ for segment in %Segments.get_children():
+ segments.append(segment)
+
+ current_segment_positions = get_default_segment_positions()
+
+
+func set_current_grid_position(value: Vector2i) -> void:
+ current_grid_position = value
+
+ global_position = (
+ grid.map_to_local(current_grid_position)
+ # shift to upper left corner of tile
+ - (grid.tile_set.tile_size / 2.0)
+ # apply map offset
+ + grid.position
+ )
+
+
+func set_current_segment_positions(value: Array[Vector2i]) -> void:
+ current_segment_positions = value
+
+ for index in segments.size():
+ var segment = segments[index]
+ segment.position = current_segment_positions[index] * grid.tile_set.tile_size
+
+
+@abstract
+func get_default_segment_positions() -> Array[Vector2i]
+
+
+func get_rotated_segment_positions(direction: float) -> Array[Vector2i]:
+ var mapped := current_segment_positions.map(func (p: Vector2i) -> Vector2i:
+ if direction > 0:
+ return Vector2i(
+ p.y,
+ -p.x
+ )
+ else:
+ return Vector2i(
+ -p.y,
+ -p.x
+ )
+ )
+
+ var result: Array[Vector2i]
+ result.assign(mapped)
+ return result
+
+
+func do_rotation(direction: float) -> void:
+ current_segment_positions = get_rotated_segment_positions(direction)
+
+
+func get_grid_occupations(offset: Vector2i = Vector2.ZERO, rotation_direction: float = 0.0) -> Array[Vector2i]:
+ var grid_occupations: Array[Vector2i]
+
+ grid_occupations.append(current_grid_position + offset)
+
+ if rotation_direction != 0.0:
+ grid_occupations.append_array(get_rotated_segment_positions(rotation_direction).map(func (p: Vector2i):
+ return current_grid_position + offset + p
+ ))
+ else:
+ grid_occupations.append_array(current_segment_positions.map(func (p: Vector2i):
+ return current_grid_position + offset + p
+ ))
+
+ return grid_occupations
+
+
+func get_grid_segments() -> Dictionary[Vector2i, TetrominoSegment]:
+ var grid_segments: Dictionary[Vector2i, TetrominoSegment]
+
+ grid_segments.set(current_grid_position, base_segment)
+ for index in segments.size():
+ var segment = segments[index]
+ grid_segments.set(current_grid_position + current_segment_positions[index], segment)
+
+ return grid_segments
diff --git a/tetromino.gd.uid b/tetromino.gd.uid
new file mode 100644
index 0000000..d4074ca
--- /dev/null
+++ b/tetromino.gd.uid
@@ -0,0 +1 @@
+uid://dbwy2nmirbcms
diff --git a/tetromino.tscn b/tetromino.tscn
new file mode 100644
index 0000000..d00424e
--- /dev/null
+++ b/tetromino.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://grl15ngihv4n"]
+
+[ext_resource type="PackedScene" uid="uid://c5axmi5im65ku" path="res://tetromino_segment.tscn" id="1_ip44q"]
+
+[node name="Tetromino" type="Node2D" unique_id=1706763403]
+
+[node name="BaseSegment" parent="." unique_id=1844265660 instance=ExtResource("1_ip44q")]
+unique_name_in_owner = true
+
+[node name="Segments" type="Node2D" parent="." unique_id=1494382942]
+unique_name_in_owner = true
+
+[node name="TetrominoSegment" parent="Segments" unique_id=315984332 instance=ExtResource("1_ip44q")]
+
+[node name="TetrominoSegment2" parent="Segments" unique_id=2140662852 instance=ExtResource("1_ip44q")]
+
+[node name="TetrominoSegment3" parent="Segments" unique_id=242883871 instance=ExtResource("1_ip44q")]
diff --git a/tetromino_bar.gd b/tetromino_bar.gd
new file mode 100644
index 0000000..93ff900
--- /dev/null
+++ b/tetromino_bar.gd
@@ -0,0 +1,8 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2(0, -1), Vector2(0, 1), Vector2(0, 2),
+ ]
diff --git a/tetromino_bar.gd.uid b/tetromino_bar.gd.uid
new file mode 100644
index 0000000..91fb604
--- /dev/null
+++ b/tetromino_bar.gd.uid
@@ -0,0 +1 @@
+uid://bhg58vhjl27b4
diff --git a/tetromino_bar.tscn b/tetromino_bar.tscn
new file mode 100644
index 0000000..9976bdf
--- /dev/null
+++ b/tetromino_bar.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://bg4yqsk4efgav"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_1aopn"]
+[ext_resource type="Script" uid="uid://bhg58vhjl27b4" path="res://tetromino_bar.gd" id="2_x1bg3"]
+
+[node name="TetrominoBar" unique_id=1706763403 instance=ExtResource("1_1aopn")]
+modulate = Color(1, 0.20392157, 1, 1)
+script = ExtResource("2_x1bg3")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(0, -8)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(0, 8)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(0, 16)
diff --git a/tetromino_cube.gd b/tetromino_cube.gd
new file mode 100644
index 0000000..f34dcb7
--- /dev/null
+++ b/tetromino_cube.gd
@@ -0,0 +1,12 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2(1, 0), Vector2(0, 1), Vector2(1, 1),
+ ]
+
+
+func do_rotation(_direction: float) -> void:
+ pass
diff --git a/tetromino_cube.gd.uid b/tetromino_cube.gd.uid
new file mode 100644
index 0000000..1feb4b9
--- /dev/null
+++ b/tetromino_cube.gd.uid
@@ -0,0 +1 @@
+uid://hom6eog7jm8j
diff --git a/tetromino_cube.tscn b/tetromino_cube.tscn
new file mode 100644
index 0000000..1afd0d7
--- /dev/null
+++ b/tetromino_cube.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://b3vg805oayd5x"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_tyw3i"]
+[ext_resource type="Script" uid="uid://hom6eog7jm8j" path="res://tetromino_cube.gd" id="2_maj8w"]
+
+[node name="TetrominoCube" unique_id=1706763403 instance=ExtResource("1_tyw3i")]
+modulate = Color(0.21568628, 1, 1, 1)
+script = ExtResource("2_maj8w")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(8, 0)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(0, 8)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(8, 8)
diff --git a/tetromino_j.gd b/tetromino_j.gd
new file mode 100644
index 0000000..40648ad
--- /dev/null
+++ b/tetromino_j.gd
@@ -0,0 +1,8 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2i(0, -1), Vector2i(1, 0), Vector2i(2, 0),
+ ]
diff --git a/tetromino_j.gd.uid b/tetromino_j.gd.uid
new file mode 100644
index 0000000..e3f1ea7
--- /dev/null
+++ b/tetromino_j.gd.uid
@@ -0,0 +1 @@
+uid://casiw3qom16h
diff --git a/tetromino_j.tscn b/tetromino_j.tscn
new file mode 100644
index 0000000..c3e3265
--- /dev/null
+++ b/tetromino_j.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://ctm2irgxy6bm1"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_7svxj"]
+[ext_resource type="Script" uid="uid://casiw3qom16h" path="res://tetromino_j.gd" id="2_sr5et"]
+
+[node name="TetrominoJ" unique_id=1706763403 instance=ExtResource("1_7svxj")]
+modulate = Color(0.3019608, 0.24705882, 1, 1)
+script = ExtResource("2_sr5et")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(0, -8)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(8, 0)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(16, 0)
diff --git a/tetromino_l.gd b/tetromino_l.gd
new file mode 100644
index 0000000..c5dc691
--- /dev/null
+++ b/tetromino_l.gd
@@ -0,0 +1,8 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2i(0, -1), Vector2i(-1, 0), Vector2i(-2, 0),
+ ]
diff --git a/tetromino_l.gd.uid b/tetromino_l.gd.uid
new file mode 100644
index 0000000..3318c03
--- /dev/null
+++ b/tetromino_l.gd.uid
@@ -0,0 +1 @@
+uid://cf0vh7sve5hhl
diff --git a/tetromino_l.tscn b/tetromino_l.tscn
new file mode 100644
index 0000000..7039eff
--- /dev/null
+++ b/tetromino_l.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://xjvbxp1ym6u"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_ivshe"]
+[ext_resource type="Script" uid="uid://cf0vh7sve5hhl" path="res://tetromino_l.gd" id="2_64wkf"]
+
+[node name="TetrominoL" unique_id=1706763403 instance=ExtResource("1_ivshe")]
+modulate = Color(1, 0.22352941, 0.25882354, 1)
+script = ExtResource("2_64wkf")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(0, -8)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(-8, 0)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(-16, 0)
diff --git a/tetromino_s.gd b/tetromino_s.gd
new file mode 100644
index 0000000..5123e0a
--- /dev/null
+++ b/tetromino_s.gd
@@ -0,0 +1,8 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2i(-1, 0), Vector2i(0, -1), Vector2i(1, -1),
+ ]
diff --git a/tetromino_s.gd.uid b/tetromino_s.gd.uid
new file mode 100644
index 0000000..30e0087
--- /dev/null
+++ b/tetromino_s.gd.uid
@@ -0,0 +1 @@
+uid://crdrqqyb37ael
diff --git a/tetromino_s.tscn b/tetromino_s.tscn
new file mode 100644
index 0000000..1f6a6a5
--- /dev/null
+++ b/tetromino_s.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://dqe14854alsgx"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_tq3fv"]
+[ext_resource type="Script" uid="uid://crdrqqyb37ael" path="res://tetromino_s.gd" id="2_ar4yt"]
+
+[node name="TetrominoS" unique_id=1706763403 instance=ExtResource("1_tq3fv")]
+modulate = Color(0.78431374, 0.75686276, 0.6862745, 1)
+script = ExtResource("2_ar4yt")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(-8, 0)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(0, -8)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(8, -8)
diff --git a/tetromino_segment.gd b/tetromino_segment.gd
new file mode 100644
index 0000000..d8ad2db
--- /dev/null
+++ b/tetromino_segment.gd
@@ -0,0 +1,2 @@
+class_name TetrominoSegment
+extends Node2D
diff --git a/tetromino_segment.gd.uid b/tetromino_segment.gd.uid
new file mode 100644
index 0000000..eca772e
--- /dev/null
+++ b/tetromino_segment.gd.uid
@@ -0,0 +1 @@
+uid://dbn7noohy1su4
diff --git a/tetromino_segment.tscn b/tetromino_segment.tscn
new file mode 100644
index 0000000..443d6a7
--- /dev/null
+++ b/tetromino_segment.tscn
@@ -0,0 +1,11 @@
+[gd_scene format=3 uid="uid://c5axmi5im65ku"]
+
+[ext_resource type="Script" uid="uid://dbn7noohy1su4" path="res://tetromino_segment.gd" id="1_u7l4c"]
+[ext_resource type="Texture2D" uid="uid://dbud1vd4f3ymh" path="res://segment-6x6.png" id="2_uonfl"]
+
+[node name="TetrominoSegment" type="Node2D" unique_id=1844265660]
+script = ExtResource("1_u7l4c")
+
+[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1307146754]
+texture = ExtResource("2_uonfl")
+centered = false
diff --git a/tetromino_t.gd b/tetromino_t.gd
new file mode 100644
index 0000000..627db90
--- /dev/null
+++ b/tetromino_t.gd
@@ -0,0 +1,8 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2i(-1, 0), Vector2i(1, 0), Vector2i(0, -1),
+ ]
diff --git a/tetromino_t.gd.uid b/tetromino_t.gd.uid
new file mode 100644
index 0000000..bab8f26
--- /dev/null
+++ b/tetromino_t.gd.uid
@@ -0,0 +1 @@
+uid://n0vlemvxqw21
diff --git a/tetromino_t.tscn b/tetromino_t.tscn
new file mode 100644
index 0000000..813d0d5
--- /dev/null
+++ b/tetromino_t.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://rndiqicn4u5x"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_xj4rw"]
+[ext_resource type="Script" uid="uid://n0vlemvxqw21" path="res://tetromino_t.gd" id="2_7sea7"]
+
+[node name="TetrominoT" unique_id=1706763403 instance=ExtResource("1_xj4rw")]
+modulate = Color(1, 1, 0.11764706, 1)
+script = ExtResource("2_7sea7")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(-8, 0)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(8, 0)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(0, -8)
diff --git a/tetromino_z.gd b/tetromino_z.gd
new file mode 100644
index 0000000..152c577
--- /dev/null
+++ b/tetromino_z.gd
@@ -0,0 +1,8 @@
+@tool
+extends Tetromino
+
+
+func get_default_segment_positions() -> Array[Vector2i]:
+ return [
+ Vector2i(1, 0), Vector2i(0, -1), Vector2i(-1, -1),
+ ]
diff --git a/tetromino_z.gd.uid b/tetromino_z.gd.uid
new file mode 100644
index 0000000..c1df740
--- /dev/null
+++ b/tetromino_z.gd.uid
@@ -0,0 +1 @@
+uid://dyktydvpl0td8
diff --git a/tetromino_z.tscn b/tetromino_z.tscn
new file mode 100644
index 0000000..b75e5fc
--- /dev/null
+++ b/tetromino_z.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://c886rx8s3x0sl"]
+
+[ext_resource type="PackedScene" uid="uid://grl15ngihv4n" path="res://tetromino.tscn" id="1_ew5an"]
+[ext_resource type="Script" uid="uid://dyktydvpl0td8" path="res://tetromino_z.gd" id="2_tas7q"]
+
+[node name="TetrominoZ" unique_id=1706763403 instance=ExtResource("1_ew5an")]
+modulate = Color(0.31764707, 0.25490198, 0.32941177, 1)
+script = ExtResource("2_tas7q")
+
+[node name="TetrominoSegment" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="0" unique_id=315984332]
+position = Vector2(8, 0)
+
+[node name="TetrominoSegment2" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="1" unique_id=2140662852]
+position = Vector2(0, -8)
+
+[node name="TetrominoSegment3" parent="Segments" parent_id_path=PackedInt32Array(1494382942) index="2" unique_id=242883871]
+position = Vector2(-8, -8)
diff --git a/theme.tres b/theme.tres
new file mode 100644
index 0000000..db8c961
--- /dev/null
+++ b/theme.tres
@@ -0,0 +1,8 @@
+[gd_resource type="Theme" format=3 uid="uid://qlaurqwpvca4"]
+
+[ext_resource type="FontFile" uid="uid://nkinuhroocu" path="res://Minimal3x5.ttf" id="1_e1x85"]
+
+[resource]
+Label/colors/font_color = Color(0, 0, 0, 1)
+Label/font_sizes/font_size = 8
+Label/fonts/font = ExtResource("1_e1x85")
diff --git a/ui.kra b/ui.kra
new file mode 100644
index 0000000..4773f36
--- /dev/null
+++ b/ui.kra
Binary files differ
diff --git a/ui.png b/ui.png
new file mode 100644
index 0000000..b7d53b1
--- /dev/null
+++ b/ui.png
Binary files differ
diff --git a/ui.png.import b/ui.png.import
new file mode 100644
index 0000000..5912938
--- /dev/null
+++ b/ui.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ck2vq6wfki52d"
+path="res://.godot/imported/ui.png-a8643d8af66e99193e98b106f1906df6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://ui.png"
+dest_files=["res://.godot/imported/ui.png-a8643d8af66e99193e98b106f1906df6.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+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/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+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