7589b2bf60
The scripts were streamlined using more or less the following conventions: - space after a comma in lists of arguments - spaces around weak operators (+, -), no spaces around strong operators (*, /) - spaces around comparison operators and compound assignment operators - space after a comment start (#) - removed trailing spaces or tabs, apart from those that delimit the function indentation level (those could be removed too but since they are added automatically by the editor when typing code, keeping them for now) - function blocks separate by two newlines - comment sentences start with an upper-case letter
195 lines
4.3 KiB
GDScript
195 lines
4.3 KiB
GDScript
|
|
extends Control
|
|
|
|
# Simple Tetris-like demo, (c) 2012 Juan Linietsky
|
|
# Implemented by using a regular Control and drawing on it during the _draw() callback.
|
|
# The drawing surface is updated only when changes happen (by calling update())
|
|
|
|
# Member variables
|
|
var score = 0
|
|
var score_label = null
|
|
|
|
const MAX_SHAPES = 7
|
|
|
|
var block = preload("block.png")
|
|
|
|
var block_colors = [
|
|
Color(1, 0.5, 0.5),
|
|
Color(0.5, 1, 0.5),
|
|
Color(0.5, 0.5, 1),
|
|
Color(0.8, 0.4, 0.8),
|
|
Color(0.8, 0.8, 0.4),
|
|
Color(0.4, 0.8, 0.8),
|
|
Color(0.7, 0.7, 0.7)]
|
|
|
|
var block_shapes = [
|
|
[ Vector2(0, -1), Vector2(0, 0), Vector2(0, 1), Vector2(0, 2) ], # I
|
|
[ Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(0, 1) ], # O
|
|
[ Vector2(-1, 1), Vector2(0, 1), Vector2(0, 0), Vector2(1, 0) ], # S
|
|
[ Vector2(1, 1), Vector2(0, 1), Vector2(0, 0), Vector2(-1, 0) ], # Z
|
|
[ Vector2(-1, 1), Vector2(-1, 0), Vector2(0, 0), Vector2(1, 0) ], # L
|
|
[ Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(-1, 0) ], # J
|
|
[ Vector2(0, 1), Vector2(1, 0), Vector2(0, 0), Vector2(-1, 0) ]] # T
|
|
|
|
var block_rotations = [
|
|
Matrix32(Vector2(1, 0), Vector2(0, 1), Vector2()),
|
|
Matrix32(Vector2(0, 1), Vector2(-1, 0), Vector2()),
|
|
Matrix32(Vector2(-1, 0), Vector2(0, -1), Vector2()),
|
|
Matrix32(Vector2(0, -1), Vector2(1, 0), Vector2())]
|
|
|
|
var width = 0
|
|
var height = 0
|
|
|
|
var cells = {}
|
|
|
|
var piece_active = false
|
|
var piece_shape = 0
|
|
var piece_pos = Vector2()
|
|
var piece_rot = 0
|
|
|
|
|
|
func piece_cell_xform(p, er = 0):
|
|
var r = (4 + er + piece_rot) % 4
|
|
return piece_pos + block_rotations[r].xform(p)
|
|
|
|
|
|
func _draw():
|
|
var sb = get_stylebox("bg", "Tree") # Use line edit bg
|
|
draw_style_box(sb, Rect2(Vector2(), get_size()).grow(3))
|
|
|
|
var bs = block.get_size()
|
|
for y in range(height):
|
|
for x in range(width):
|
|
if (Vector2(x, y) in cells):
|
|
draw_texture_rect(block, Rect2(Vector2(x, y)*bs, bs), false, block_colors[cells[Vector2(x, y)]])
|
|
|
|
if (piece_active):
|
|
for c in block_shapes[piece_shape]:
|
|
draw_texture_rect(block, Rect2(piece_cell_xform(c)*bs, bs), false, block_colors[piece_shape])
|
|
|
|
|
|
func piece_check_fit(ofs, er = 0):
|
|
for c in block_shapes[piece_shape]:
|
|
var pos = piece_cell_xform(c, er) + ofs
|
|
if (pos.x < 0):
|
|
return false
|
|
if (pos.y < 0):
|
|
return false
|
|
if (pos.x >= width):
|
|
return false
|
|
if (pos.y >= height):
|
|
return false
|
|
if (pos in cells):
|
|
return false
|
|
|
|
return true
|
|
|
|
|
|
func new_piece():
|
|
piece_shape = randi() % MAX_SHAPES
|
|
piece_pos = Vector2(width/2, 0)
|
|
piece_active = true
|
|
piece_rot = 0
|
|
if (piece_shape == 0):
|
|
piece_pos.y += 1
|
|
|
|
if (not piece_check_fit(Vector2())):
|
|
# Game over
|
|
game_over()
|
|
|
|
update()
|
|
|
|
|
|
func test_collapse_rows():
|
|
var accum_down = 0
|
|
for i in range(height):
|
|
var y = height - i - 1
|
|
var collapse = true
|
|
for x in range(width):
|
|
if (Vector2(x, y) in cells):
|
|
if (accum_down):
|
|
cells[Vector2(x, y + accum_down)] = cells[Vector2(x, y)]
|
|
else:
|
|
collapse = false
|
|
if (accum_down):
|
|
cells.erase(Vector2(x, y + accum_down))
|
|
|
|
if (collapse):
|
|
accum_down += 1
|
|
|
|
score += accum_down*100
|
|
score_label.set_text(str(score))
|
|
|
|
|
|
func game_over():
|
|
piece_active = false
|
|
get_node("gameover").set_text("Game over!")
|
|
update()
|
|
|
|
|
|
func restart_pressed():
|
|
score = 0
|
|
score_label.set_text("0")
|
|
cells.clear()
|
|
get_node("gameover").set_text("")
|
|
piece_active = true
|
|
get_node("../restart").release_focus()
|
|
update()
|
|
|
|
|
|
func piece_move_down():
|
|
if (!piece_active):
|
|
return
|
|
if (piece_check_fit(Vector2(0, 1))):
|
|
piece_pos.y += 1
|
|
update()
|
|
else:
|
|
for c in block_shapes[piece_shape]:
|
|
var pos = piece_cell_xform(c)
|
|
cells[pos] = piece_shape
|
|
test_collapse_rows()
|
|
new_piece()
|
|
|
|
|
|
func piece_rotate():
|
|
var adv = 1
|
|
if (not piece_check_fit(Vector2(), 1)):
|
|
return
|
|
piece_rot = (piece_rot + adv) % 4
|
|
update()
|
|
|
|
|
|
func _input(ie):
|
|
if (not piece_active):
|
|
return
|
|
if (!ie.is_pressed()):
|
|
return
|
|
|
|
if (ie.is_action("move_left")):
|
|
if (piece_check_fit(Vector2(-1, 0))):
|
|
piece_pos.x -= 1
|
|
update()
|
|
elif (ie.is_action("move_right")):
|
|
if (piece_check_fit(Vector2(1, 0))):
|
|
piece_pos.x += 1
|
|
update()
|
|
elif (ie.is_action("move_down")):
|
|
piece_move_down()
|
|
elif (ie.is_action("rotate")):
|
|
piece_rotate()
|
|
|
|
|
|
func setup(w, h):
|
|
width = w
|
|
height = h
|
|
set_size(Vector2(w, h)*block.get_size())
|
|
new_piece()
|
|
get_node("timer").start()
|
|
|
|
|
|
func _ready():
|
|
# Initalization here
|
|
setup(10, 20)
|
|
score_label = get_node("../score")
|
|
|
|
set_process_input(true)
|