0341-Tetris-渲染多个方块
环境
- Time 2023-08-22
- Zig 0.12.0-dev.161+6a5463951
- WSL-Ubuntu 22.04.3 LTS
前言
说明
参考资料:
目标
到现在为止,还只有一个方块,没有生成新的方块。其实在下落碰撞时,应该保存老方块,生成新方块。
display.zig
...
pub fn drawSolid(self: *Screen, x: usize, y: usize, rgba: u32) void {
self.draw(x, y, rgba);
self.buffer[x][y] = rgba;
}
...
drawSolid 方法不仅画出当前方块,还将其保存的缓存中。
app.zig
...
pub fn moveDown(self: *Game, screen: *Screen) void {
if (self.move(screen, 0, 1)) {
self.current.solid = true;
draw(&self.current, screen);
self.current = Tetrimino.random(&self.prng);
}
}
fn draw(block: *const Tetrimino, screen: *Screen) void {
const value = block.position();
var index: usize = 0;
while (index < value.len) : (index += 2) {
const row: usize = @intCast(block.x + value[index]);
const col: usize = @intCast(block.y + value[index + 1]);
if (block.solid) {
screen.drawSolid(row, col, block.color);
} else {
screen.draw(row, col, block.color);
}
}
}
...
向下移动的时候,如果有碰撞,则应该保存老方块,生成全新的一个方块。
效果

总结
实现了向下移动时发生碰撞,另外生成一个方块,保存老方块。使界面可以同时显示多个方块。
附录
display.zig 源码
const c = @import("c.zig");
pub const WIDTH = 10;
pub const HEIGHT = 20;
const FPS = 60;
const SCALE = 40; // 放大倍数
const BORDER = 2; // 边框
pub const Screen = struct {
buffer: [WIDTH][HEIGHT]u32 = undefined,
window: *c.SDL_Window = undefined,
renderer: *c.SDL_Renderer = undefined,
pub fn init(self: *Screen) void {
if (c.SDL_Init(c.SDL_INIT_EVERYTHING) < 0) c.sdlPanic();
const center = c.SDL_WINDOWPOS_CENTERED;
self.window = c.SDL_CreateWindow("俄罗斯方块", center, center, //
400, 800, c.SDL_WINDOW_SHOWN) orelse c.sdlPanic();
self.renderer = c.SDL_CreateRenderer(self.window, -1, 0) //
orelse c.sdlPanic();
}
pub fn update(self: *Screen) void {
_ = c.SDL_SetRenderDrawColor(self.renderer, 0x3b, 0x3b, 0x3b, 0xff);
_ = c.SDL_RenderClear(self.renderer);
for (0..WIDTH) |row| {
for (0..HEIGHT) |col| {
var color = self.buffer[row][col];
if (color == 0) color = 0x404040ff;
self.draw(row, col, color);
}
}
}
pub fn draw(self: *Screen, x: usize, y: usize, rgba: u32) void {
const r: u8 = @truncate((rgba >> 24) & 0xff);
const g: u8 = @truncate((rgba >> 16) & 0xff);
const b: u8 = @truncate((rgba >> 8) & 0xff);
const a: u8 = @truncate((rgba >> 0) & 0xff);
_ = c.SDL_SetRenderDrawColor(self.renderer, r, g, b, a);
const rect = c.SDL_Rect{
.x = @intCast(x * SCALE + BORDER),
.y = @intCast(y * SCALE + BORDER),
.w = @intCast(SCALE - BORDER),
.h = @intCast(SCALE - BORDER),
};
_ = c.SDL_RenderFillRect(self.renderer, &rect);
}
pub fn drawSolid(self: *Screen, x: usize, y: usize, rgba: u32) void {
self.draw(x, y, rgba);
self.buffer[x][y] = rgba;
}
pub fn hasSolid(self: *const Screen, x: usize, y: usize) bool {
if (x >= WIDTH) return false;
return y >= HEIGHT or self.buffer[x][y] != 0;
}
pub fn present(self: *Screen) void {
c.SDL_RenderPresent(self.renderer);
c.SDL_Delay(1000 / FPS);
}
pub fn deinit(self: *Screen) void {
c.SDL_DestroyRenderer(self.renderer);
c.SDL_DestroyWindow(self.window);
c.SDL_Quit();
}
};
app.zig 源码
const std = @import("std");
const Screen = @import("display.zig").Screen;
const Tetrimino = @import("block.zig").Tetrimino;
pub const Game = struct {
current: Tetrimino,
prng: std.rand.DefaultPrng,
pub fn new() Game {
const seed = @as(u64, @intCast(std.time.timestamp()));
var rand = std.rand.DefaultPrng.init(seed);
return Game{
.current = Tetrimino.random(&rand),
.prng = rand,
};
}
pub fn drawCurrent(self: *Game, screen: *Screen) void {
draw(&self.current, screen);
}
pub fn moveLeft(self: *Game, screen: *Screen) void {
_ = self.move(screen, -1, 0);
}
pub fn moveRight(self: *Game, screen: *Screen) void {
_ = self.move(screen, 1, 0);
}
pub fn moveDown(self: *Game, screen: *Screen) void {
if (self.move(screen, 0, 1)) {
self.current.solid = true;
draw(&self.current, screen);
self.current = Tetrimino.random(&self.prng);
}
}
fn move(self: *Game, screen: *const Screen, x: i8, y: i8) bool {
self.current.x = self.current.x + x;
self.current.y = self.current.y + y;
self.current.locateIn();
return if (self.isFit(screen)) {
_ = self.move(screen, -x, -y);
return true;
} else false;
}
pub fn rotate(self: *Game, screen: *Screen) void {
_ = screen;
self.current.rotate();
self.current.locateIn();
}
fn isFit(self: *const Game, screen: *const Screen) bool {
const value = self.current.position();
var index: usize = 0;
while (index < value.len) : (index += 2) {
const col = self.current.y + value[index + 1];
if (col < 0) return true;
const row: usize = @intCast(self.current.x + value[index]);
if (screen.hasSolid(row, @intCast(col))) return true;
}
return false;
}
};
fn draw(block: *const Tetrimino, screen: *Screen) void {
const value = block.position();
var index: usize = 0;
while (index < value.len) : (index += 2) {
const row: usize = @intCast(block.x + value[index]);
const col: usize = @intCast(block.y + value[index + 1]);
if (block.solid) {
screen.drawSolid(row, col, block.color);
} else {
screen.draw(row, col, block.color);
}
}
}

浙公网安备 33010602011771号