M board.ha => board.ha +97 -3
@@ 1,5 1,4 @@
use sdl2;
-use fmt; // XXX: TEMP
def BOARD_WIDTH: int = 10;
def BOARD_HEIGHT: int = 20;
@@ 33,6 32,8 @@ type board = struct {
active_i: int,
active_x: int,
active_y: int,
+ ghost_x: int,
+ ghost_y: int,
offs_x: int,
offs_y: int,
};
@@ 55,25 56,38 @@ 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);
+ draw_active(state, board.ghost_x, board.ghost_y, 128)?;
+ draw_active(state, board.active_x, board.active_y, 255)?;
+};
+
+fn draw_active(
+ state: *state,
+ x: int, y: int,
+ alpha: u8,
+) (void | sdl2::error) = {
+ const active = (x, y);
+ const board = &state.board, tex = &state.piece;
+ const offs = (board.offs_x * SCENE_SCALE, board.offs_y * SCENE_SCALE);
for (let y = 0; y < TETROMINO_HEIGHT; y += 1)
for (let x = 0; x < TETROMINO_WIDTH; x += 1) {
let cell = board.active[board.active_i][y * TETROMINO_WIDTH + x];
if (cell == color::EMPTY) {
continue;
};
- const x = x + board.active_x, y = y + board.active_y;
+ const x = x + active.0, y = y + active.1;
if (y < 0) {
continue;
};
let color = &color_map[cell];
sdl2::set_texture_color_mod(tex.tex, color.0, color.1, color.2)?;
+ sdl2::set_texture_alpha_mod(tex.tex, alpha)?;
sdl2::render_copy(state.render, tex.tex, null, &sdl2::rect {
x = offs.0 + x * BOARD_SCALE * tex.width,
y = offs.1 + y * BOARD_SCALE * tex.height,
@@ 83,6 97,49 @@ fn draw_board(state: *state, board: *board) (void | sdl2::error) = {
};
};
+fn canmove(
+ state: *state,
+ active: *[TETROMINO_LEN]color,
+ dx: int, dy: int,
+) bool = {
+ const board = &state.board.cells;
+ 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 active_ix = y * TETROMINO_WIDTH + x;
+ if (active[active_ix] == 0) {
+ continue;
+ };
+ if (x + active_x < 0 || x + active_x >= BOARD_WIDTH) {
+ return false;
+ };
+ if (y + dy + active_y < 0) {
+ continue;
+ };
+ const x = x + dx, y = y + dy;
+ const board_ix = (y + active_y) * BOARD_WIDTH + (x + active_x);
+ if (board_ix: size >= len(board) || board[board_ix] != 0) {
+ return false;
+ };
+ };
+ return true;
+};
+
+fn update_ghost(state: *state) void = {
+ const board = &state.board;
+ const cells = &board.cells;
+ const active = &board.active[board.active_i];
+ let width = 0, height = 0;
+ activesize(state, &width, &height);
+
+ let y = 1;
+ for (canmove(state, active, 0, y); y += 1) void;
+
+ board.ghost_x = board.active_x;
+ board.ghost_y = board.active_y + y - 1;
+};
+
fn commit(state: *state) void = {
let board = &state.board.cells;
let active = &state.board.active[state.board.active_i];
@@ 136,3 193,40 @@ fn shiftrow(state: *state, row: int) void = {
};
};
};
+
+fn activesize(
+ state: *state,
+ width: nullable *int,
+ height: nullable *int,
+) void = {
+ let max_x = 0, max_y = 0;
+ const active = &state.board.active[state.board.active_i];
+ for (let y = 0; y < TETROMINO_HEIGHT; y += 1)
+ for (let x = 0; x < TETROMINO_WIDTH; x += 1) {
+ const active = active[y * TETROMINO_WIDTH + x] != 0;
+ if (active && x > max_x) {
+ max_x = x;
+ };
+ if (active && y > max_y) {
+ max_y = y;
+ };
+ };
+ match (width) {
+ case let ptr: *int =>
+ *ptr = max_x + 1;
+ case null => void;
+ };
+ match (height) {
+ case let ptr: *int =>
+ *ptr = max_y + 1;
+ case null => void;
+ };
+};
+
+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;
+ };
+};
M main.ha => main.ha +5 -1
@@ 57,7 57,8 @@ fn run() (void | sdl2::error) = {
640, 480, window_flags::NONE)?;
defer sdl2::destroy_window(win);
- const render = sdl2::create_renderer(win, -1, renderer_flags::NONE)?;
+ const render = sdl2::create_renderer(win, -1,
+ renderer_flags::ACCELERATED)?;
defer sdl2::destroy_renderer(render);
const seed = time::now(time::clock::MONOTONIC).sec: u64;
@@ 79,6 80,9 @@ fn run() (void | sdl2::error) = {
};
defer sdl2::destroy_texture(state.piece.tex);
defer sdl2::destroy_texture(state.scene.tex);
+ defer sdl2::destroy_texture(state.clear.tex);
+
+ sdl2::set_texture_blend_mode(state.piece.tex, sdl2::blend_mode::BLEND)?;
let controller: nullable *sdl2::gamecontroller = null;
for (let i = 0; i < sdl2::numjoysticks()?; i += 1) {
M notes.txt => notes.txt +0 -1
@@ 1,4 1,3 @@
-- ghost blocks
- instant place
- fix thumbsticks
- scorekeeping/display
M update.ha => update.ha +4 -66
@@ 97,6 97,7 @@ fn do_spawn(state: *state, now: u32) void = {
state.board.active_y = -height;
state.board.active_x = BOARD_WIDTH / 2 - width / 2;
state.state = gamestate::FALL;
+ update_ghost(state);
schedule_tick(state, now);
};
@@ 138,6 139,7 @@ fn schedule_tick(state: *state, now: u32) void = {
fn move_left(state: *state) void = {
if (state.board.active_x > 0) {
state.board.active_x -= 1;
+ update_ghost(state);
};
};
@@ 146,6 148,7 @@ fn move_right(state: *state) void = {
activesize(state, &width, null);
if (state.board.active_x < BOARD_WIDTH - width) {
state.board.active_x += 1;
+ update_ghost(state);
};
};
@@ 159,70 162,5 @@ fn rotate(state: *state) void = {
return;
};
board.active_i = next;
-};
-
-fn activesize(
- state: *state,
- width: nullable *int,
- height: nullable *int,
-) void = {
- let max_x = 0, max_y = 0;
- const active = &state.board.active[state.board.active_i];
- for (let y = 0; y < TETROMINO_HEIGHT; y += 1)
- for (let x = 0; x < TETROMINO_WIDTH; x += 1) {
- const active = active[y * TETROMINO_WIDTH + x] != 0;
- if (active && x > max_x) {
- max_x = x;
- };
- if (active && y > max_y) {
- max_y = y;
- };
- };
- match (width) {
- case let ptr: *int =>
- *ptr = max_x + 1;
- case null => void;
- };
- match (height) {
- case let ptr: *int =>
- *ptr = max_y + 1;
- case null => void;
- };
-};
-
-fn canmove(
- state: *state,
- active: *[TETROMINO_LEN]color,
- dx: int, dy: int,
-) bool = {
- let board = &state.board.cells;
- 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 active_ix = y * TETROMINO_WIDTH + x;
- if (active[active_ix] == 0) {
- continue;
- };
- if (x + active_x < 0 || x + active_x >= BOARD_WIDTH) {
- return false;
- };
- if (y + active_y < 0) {
- continue;
- };
- const x = x + dx, y = y + dy;
- const board_ix = (y + active_y) * BOARD_WIDTH + (x + active_x);
- if (board_ix: size >= len(board) || board[board_ix] != 0) {
- return false;
- };
- };
- 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;
- };
+ update_ghost(state);
};