M board.ha => board.ha +61 -0
@@ 1,4 1,5 @@
use sdl2;
+use fmt; // XXX: TEMP
def BOARD_WIDTH: int = 10;
def BOARD_HEIGHT: int = 20;
@@ 54,6 55,12 @@ fn draw_board(state: *state, board: *board) (void | sdl2::error) = {
h = tex.height * BOARD_SCALE,
})?;
};
+ switch (state.state) {
+ case gamestate::CLEAR =>
+ return;
+ case => void;
+ };
+
const active = (board.active_x, board.active_y);
for (let y = 0; y < TETROMINO_HEIGHT; y += 1)
for (let x = 0; x < TETROMINO_WIDTH; x += 1) {
@@ 75,3 82,57 @@ fn draw_board(state: *state, board: *board) (void | sdl2::error) = {
})?;
};
};
+
+fn commit(state: *state) void = {
+ let board = &state.board.cells;
+ let active = &state.board.active[state.board.active_i];
+ const active_x = state.board.active_x;
+ const active_y = state.board.active_y;
+ for (let y = 0; y < TETROMINO_HEIGHT; y += 1)
+ for (let x = 0; x < TETROMINO_WIDTH; x += 1) {
+ const board_ix = (y + active_y) * BOARD_WIDTH + (x + active_x);
+ const active_ix = y * TETROMINO_WIDTH + x;
+ if (board_ix: size >= len(board)) {
+ continue;
+ };
+ if (active[active_ix] != 0) {
+ board[board_ix] = active[active_ix];
+ };
+ };
+
+ static let clearbuf: [TETROMINO_HEIGHT]int = [0...];
+ let clear = clearbuf[..0];
+ state.state = gamestate::SPAWN;
+ for (let y = active_y; y < BOARD_HEIGHT; y += 1)
+ for (let x = 0, sum = 0; x < BOARD_WIDTH; x += 1) {
+ const board_ix = y * BOARD_WIDTH + x;
+ const cell = state.board.cells[board_ix];
+ if (cell != 0) {
+ sum += 1;
+ };
+ if (sum == BOARD_WIDTH) {
+ state.state = gamestate::CLEAR;
+ static append(clear, y);
+ };
+ };
+ state.clearlines = clear;
+ state.clearframe = -1;
+};
+
+fn shiftrows(state: *state) void = {
+ let j = 0;
+ for (let i = len(state.clearlines): int - 1; i >= 0; i -= 1) {
+ shiftrow(state, state.clearlines[i] + j);
+ j += 1;
+ };
+};
+
+fn shiftrow(state: *state, row: int) void = {
+ const cells = &state.board.cells;
+ for (let y = row; y > 0; y -= 1) {
+ for (let x = 0; x < BOARD_WIDTH; x += 1) {
+ const src = &cells[(y - 1) * BOARD_WIDTH + x];
+ cells[y * BOARD_WIDTH + x] = *src;
+ };
+ };
+};
A draw.ha => draw.ha +52 -0
@@ 0,0 1,52 @@
+use sdl2;
+
+fn draw(state: *state) (void | sdl2::error) = {
+ sdl2::set_render_draw_color(state.render, 0, 0, 0, 255)?;
+ sdl2::render_clear(state.render)?;
+ sdl2::render_copy(state.render, state.scene.tex, null, &sdl2::rect{
+ x = 0,
+ y = 0,
+ w = 640,
+ h = 480,
+ })?;
+
+ draw_board(state, &state.board)?;
+
+ switch (state.state) {
+ case gamestate::CLEAR =>
+ draw_clear(state)?;
+ case => void; // No special drawing required
+ };
+
+ sdl2::render_present(state.render);
+};
+
+fn draw_clear(state: *state) (void | sdl2::error) = {
+ if (state.clearframe < 0) {
+ return;
+ };
+ for (let i = 0z; i < len(state.clearlines); i += 1) {
+ draw_clearline(state, state.clearlines[i])?;
+ };
+};
+
+fn draw_clearline(state: *state, y: int) (void | sdl2::error) = {
+ const inrect = &sdl2::rect {
+ x = state.clearframe * 4,
+ y = 0,
+ w = 4,
+ h = 4,
+ };
+ const tex = state.clear;
+ const board = &state.board;
+ const offs = (board.offs_x * SCENE_SCALE, board.offs_y * SCENE_SCALE);
+ for (let x = 0; x < BOARD_WIDTH; x += 1) {
+ const outrect = &sdl2::rect {
+ x = offs.0 + x * BOARD_SCALE * TETROMINO_WIDTH,
+ y = offs.1 + y * BOARD_SCALE * TETROMINO_HEIGHT,
+ w = TETROMINO_WIDTH * BOARD_SCALE,
+ h = TETROMINO_HEIGHT * BOARD_SCALE,
+ };
+ sdl2::render_copy(state.render, tex.tex, inrect, outrect)?;
+ };
+};
M main.ha => main.ha +1 -36
@@ 35,6 35,7 @@ type state = struct {
faster: bool,
lastcolor: color,
clearframe: int,
+ clearlines: []int,
};
export fn main() void = {
@@ 106,42 107,6 @@ fn run() (void | sdl2::error) = {
};
};
-fn draw(state: *state) (void | sdl2::error) = {
- sdl2::set_render_draw_color(state.render, 0, 0, 0, 255)?;
- sdl2::render_clear(state.render)?;
- sdl2::render_copy(state.render, state.scene.tex, null, &sdl2::rect{
- x = 0,
- y = 0,
- w = 640,
- h = 480,
- })?;
-
- draw_board(state, &state.board)?;
-
- switch (state.state) {
- case gamestate::CLEAR =>
- draw_clear(state);
- case => void; // No special drawing required
- };
-
- sdl2::render_present(state.render);
-};
-
-fn draw_clear(state: *state) void = {
- // TODO: Expand me
- sdl2::render_copy(state.render, state.clear.tex, &sdl2::rect{
- x = state.clearframe * 4,
- y = 0,
- w = 4,
- h = 4,
- }, &sdl2::rect{
- x = 0,
- y = 0,
- w = 8,
- h = 8,
- })?;
-};
-
fn load_texture(render: *sdl2::renderer, path: str) (texture | sdl2::error) = {
const tex = image::load_texture(render, path)?;
let width = 0, height = 0;
M notes.txt => notes.txt +1 -1
@@ 2,7 2,6 @@
- instant place
- fix thumbsticks
- scorekeeping/display
-- clear completed rows (+animation)
- try to accomodate rotation by moving pieces left/right
- piece swapping
- keyboard input
@@ 10,6 9,7 @@
- victory (+animation)
- music
- sound effects
+- alternate clear animations
later:
- menu system
M update.ha => update.ha +17 -34
@@ 116,6 116,15 @@ fn do_clear(state: *state, now: u32) void = {
state.clearframe += 1;
state.clearframe %= 12;
state.next = now + (state.speed / 6);
+
+ if (state.clearframe == 4) {
+ clear_lines(state);
+ };
+ if (state.clearframe == 9) {
+ state.state = gamestate::SPAWN;
+ state.board.active_y = -4;
+ shiftrows(state);
+ };
};
fn schedule_tick(state: *state, now: u32) void = {
@@ 126,40 135,6 @@ fn schedule_tick(state: *state, now: u32) void = {
};
};
-fn commit(state: *state) void = {
- let board = &state.board.cells;
- let active = &state.board.active[state.board.active_i];
- const active_x = state.board.active_x;
- const active_y = state.board.active_y;
- for (let y = 0; y < TETROMINO_HEIGHT; y += 1)
- for (let x = 0; x < TETROMINO_WIDTH; x += 1) {
- const board_ix = (y + active_y) * BOARD_WIDTH + (x + active_x);
- const active_ix = y * TETROMINO_WIDTH + x;
- if (board_ix: size >= len(board)) {
- continue;
- };
- if (active[active_ix] != 0) {
- board[board_ix] = active[active_ix];
- };
- };
-
- static let clearbuf: [TETROMINO_HEIGHT]int = [0...];
- let clear = clearbuf[..0];
- state.state = gamestate::SPAWN;
- for (let y = active_y; y < BOARD_HEIGHT; y += 1)
- for (let x = 0, sum = 0; x < BOARD_WIDTH; x += 1) {
- const board_ix = y * BOARD_WIDTH + x;
- const cell = state.board.cells[board_ix];
- if (cell != 0) {
- sum += 1;
- };
- if (sum == BOARD_WIDTH) {
- state.state = gamestate::CLEAR;
- static append(clear, y);
- };
- };
-};
-
fn move_left(state: *state) void = {
if (state.board.active_x > 0) {
state.board.active_x -= 1;
@@ 243,3 218,11 @@ fn canmove(
};
return true;
};
+
+fn clear_lines(state: *state) void = {
+ for (let i = 0z; i < len(state.clearlines); i += 1)
+ for (let x = 0; x < BOARD_WIDTH; x += 1) {
+ const y = state.clearlines[i];
+ state.board.cells[y * BOARD_WIDTH + x] = 0;
+ };
+};