tetris
Diffstat (limited to 'Tetris.gd')
-rw-r--r--Tetris.gd248
1 files changed, 248 insertions, 0 deletions
diff --git a/Tetris.gd b/Tetris.gd
new file mode 100644
index 0000000..b475068
--- /dev/null
+++ b/Tetris.gd
@@ -0,0 +1,248 @@
+tool
+class_name Tetris
+extends MarginContainer
+
+const ROWS = 20
+const COLUMNS = 10
+
+export(PoolColorArray) var colors
+export(PoolColorArray) var transcolors
+export(Color) var grid_color
+export(Color) var bg_color
+
+var current_shape: TetrisPiece
+var matrix := Logic.create_matrix(ROWS, COLUMNS)
+var bg_squares := []
+var squares := []
+var nxt_p_squares := []
+
+var bag := Logic.piece_bag.duplicate(true)
+onready var next_shape: Array = bag.pop_at(randi() % len(bag))
+
+
+func random_shape() -> Array:
+ var n = next_shape
+ next_shape = bag.pop_at(randi() % len(bag))
+ if bag.empty():
+ bag = Logic.piece_bag.duplicate(true)
+ draw_nxt_p_shape()
+ return n
+
+
+func draw_nxt_p_shape():
+ var clr = colors[Logic.piece_indexs[next_shape]]
+ var n = [0, 0, 0, 0]
+ n.append_array(next_shape.duplicate())
+ for i in range(4 * 4):
+ nxt_p_squares[i].color = Color.transparent
+ if i > len(n) - 1 or n[i] == 0:
+ continue
+ nxt_p_squares[i].color = clr
+
+
+func get_square(at: Vector2) -> Control:
+ return squares[at.y * COLUMNS + at.x]
+
+
+func init_squares(on: Control):
+ var aspect = AspectRatioContainer.new()
+ aspect.alignment_vertical = aspect.ALIGN_BEGIN
+ aspect.ratio = float(COLUMNS) / float(ROWS)
+ aspect.name = "aspect"
+ expand_control(aspect)
+ on.add_child(aspect)
+ var sqs := create_grid_container("squares")
+ aspect.add_child(sqs)
+ for _i in range(ROWS * COLUMNS):
+ squares.append(create_square(sqs, "%d" % _i))
+
+
+func create_square(to: GridContainer, name: String, bg := true) -> ColorRect:
+ var fg_square := ColorRect.new()
+ fg_square.color = Color.transparent
+ fg_square.name = name
+ fg_square.rect_min_size = Vector2(10, 10)
+ expand_control(fg_square)
+ to.add_child(fg_square)
+ if bg:
+ var bg_square := ReferenceRect.new()
+ bg_square.editor_only = false
+ bg_square.border_width = 1.5
+ bg_square.border_color = grid_color
+ bg_square.name = name
+ bg_square.show_behind_parent = true
+ expand_control(bg_square)
+ fg_square.add_child(bg_square)
+ return fg_square
+
+
+func create_grid_container(name: String, cols := COLUMNS, expand := true) -> GridContainer:
+ var g := GridContainer.new()
+ g.columns = cols
+ g.name = name
+ g.add_constant_override("vseparation", 0)
+ g.add_constant_override("hseparation", 0)
+ if expand:
+ expand_control(g)
+ return g
+
+
+func expand_control(c: Control) -> void:
+ c.size_flags_horizontal = SIZE_EXPAND_FILL
+ c.size_flags_vertical = SIZE_EXPAND_FILL
+ c.set_anchors_and_margins_preset(PRESET_WIDE)
+
+
+func init_bg() -> void:
+ var c := ColorRect.new()
+ c.name = "bg"
+ expand_control(c)
+ c.color = bg_color
+ add_child(c)
+
+
+func init_next_preview(on: Control):
+ var aspect := AspectRatioContainer.new()
+ aspect.alignment_vertical = aspect.ALIGN_BEGIN
+ aspect.name = "aspect"
+ aspect.set_anchors_and_margins_preset(PRESET_WIDE)
+ on.add_child(aspect)
+ var next = create_grid_container("next-block-preview", 4, false)
+ aspect.add_child(next)
+ for _i in range(4 * 4):
+ nxt_p_squares.append(create_square(next, "%d" % _i, false))
+
+ var square = ReferenceRect.new()
+ square.name = "next-block-outline"
+ square.border_width = 1.5
+ square.border_color = grid_color
+ square.editor_only = false
+ expand_control(square)
+ aspect.add_child(square)
+
+
+func _ready() -> void:
+ set_process(false)
+ init_bg()
+ var h = HBoxContainer.new()
+ h.add_constant_override("hseparation", 5)
+ h.name = "hbox"
+ add_child(h)
+ init_squares(h)
+ init_next_preview(h)
+ if not Engine.editor_hint:
+ start()
+
+
+func start() -> void:
+ set_process(true)
+ # warning-ignore-all:integer_division
+ current_shape = TetrisPiece.new(Vector2((COLUMNS / 2) - 2, 0), random_shape())
+ tick()
+
+
+func draw_board() -> void:
+ var mat := matrix.duplicate(true)
+ current_shape.embed(mat)
+ var set_squares = draw_preview()
+ for y in range(ROWS):
+ for x in range(COLUMNS):
+ if mat[y][x] > 0:
+ get_square(Vector2(x, y)).color = colors[mat[y][x] - 1]
+ elif set_squares.find(Vector2(x, y)) == -1:
+ get_square(Vector2(x, y)).color = Color.transparent
+
+
+func draw_preview(shape: TetrisPiece = current_shape) -> PoolVector2Array:
+ var p = shape.position
+ shape.fall(matrix)
+ var set_squares: PoolVector2Array = []
+ for y in range(4):
+ for x in range(4):
+ if Logic.get_index_or_null(shape.shape, y, x) > 0:
+ set_squares.append(Vector2(x, y) + shape.position)
+ get_square(Vector2(x, y) + shape.position).color = transcolors[shape.shape_type]
+ shape.position = p
+ return set_squares
+
+
+func highlight_clearable_lines() -> void:
+ var mat := matrix.duplicate(true)
+ current_shape.embed(mat)
+ var lines = Logic.clear_lines(mat.duplicate(true))
+ for l in lines:
+ for x in range(COLUMNS):
+ var c = colors[mat[l][x] - 1]
+ c.v += .2
+ get_square(Vector2(x, l)).color = c
+
+
+func _input(event):
+ if event is InputEventSwipe:
+ match event.direction.round().normalized():
+ Vector2.RIGHT:
+ current_shape.move(Vector2.RIGHT, matrix)
+ Vector2.LEFT:
+ current_shape.move(Vector2.LEFT, matrix)
+ Vector2.DOWN:
+ current_shape.fall(matrix)
+ tick(false)
+ _:
+ current_shape.rotate(matrix)
+ tick(false)
+
+ if event.is_action_pressed("left", true):
+ current_shape.move(Vector2.LEFT, matrix)
+ elif event.is_action_pressed("right", true):
+ current_shape.move(Vector2.RIGHT, matrix)
+ if event.is_action_pressed("rotate_cw"):
+ current_shape.rotate(matrix, true)
+ elif event.is_action_pressed("rotate_anti_cw"):
+ current_shape.rotate(matrix, false)
+ if event.is_action_pressed("down"):
+ current_shape.fall(matrix)
+ tick(false)
+ else:
+ draw_board()
+
+
+func tick(create_timer := true):
+ var no_draw := false
+ var t_length := .25
+ if not current_shape.move(Vector2(0, 1), matrix): # invalid move: cant go down
+ if current_shape.position.y == 0:
+ get_tree().reload_current_scene()
+ if current_shape.stopped:
+ print(ascii(matrix))
+ current_shape.embed(matrix)
+ current_shape = TetrisPiece.new(Vector2(randi() % (COLUMNS - 4), 0), random_shape())
+ Logic.clear_lines(matrix)
+ else:
+ current_shape.stopped = true
+ draw_board()
+ highlight_clearable_lines()
+ no_draw = true
+ t_length = .5
+ if create_timer:
+ var t := get_tree().create_timer(t_length, false)
+ t.connect("timeout", self, "tick")
+ if not no_draw:
+ draw_board()
+
+
+#warning-ignore:shadowed_variable
+func ascii(matrix):
+ var s = "+"
+ for _x in range(COLUMNS):
+ s += "-"
+ s += "+"
+ #warning-ignore:shadowed_variable
+ for y in range(ROWS):
+ s += "\n" + ("|" if y != ROWS - 1 else "+")
+ for x in range(COLUMNS):
+ if matrix[y][x] > 0:
+ s += "ﱢ"
+ else:
+ s += "-"
+ s += ("|" if y != ROWS - 1 else "+")
+ return s