Zig 语言简介:
Zig 是一种系统编程语言,注重安全、性能和可维护性。具有简洁的语法,支持强大的编译时功能,旨在取代 C 语言,适合系统级编程。
本文使用 Zig 实现贪吃蛇游戏,利用 curses
库进行终端显示,包含蛇的移动、食物生成、碰撞检测等逻辑,通过枚举和结构体定义方向和蛇身,使用动态数组存储蛇身,以循环更新游戏状态。
用zig来写贪吃蛇游戏的优缺点:
优点:利用 Zig 的特性保证一定性能和安全性,简洁的语法使代码清晰。
缺点:对 curses
库依赖在 Windows 需额外配置,代码中随机数生成方式较简单,可能不够随机。
以下是一个简单的贪吃蛇游戏的 Zig 代码示例:
// 导入 Zig 的标准库
const std = @import("std");
// 导入 C 的 curses 库,用于在终端中进行图形绘制和输入处理
const c = @cImport({@cInclude("curses.h");
});// 定义游戏窗口的宽度
const WIDTH = 80;
// 定义游戏窗口的高度
const HEIGHT = 24;
// 定义蛇的初始长度
const INITIAL_LENGTH = 4;// 定义一个枚举类型,表示蛇的移动方向
const Direction = enum { UP, DOWN, LEFT, RIGHT };// 定义一个结构体,表示蛇的一个身体部分,包含 x 和 y 坐标
const SnakeSegment = struct {x: i32,y: i32,
};// 存储蛇的身体部分的动态数组
var snake: std.ArrayList(SnakeSegment) = undefined;
// 存储蛇的当前移动方向
var direction: Direction = Direction.RIGHT;
// 存储食物的 x 坐标
var food_x: i32 = 0;
// 存储食物的 y 坐标
var food_y: i32 = 0;
// 标记游戏是否结束
var game_over: bool = false;// 初始化游戏,设置 curses 库的属性,初始化蛇和食物
fn init()!void {// 初始化 curses 库c.initscr();// 开启 cbreak 模式,字符输入直接可用,无需等待回车键c.cbreak();// 关闭输入字符的回显c.noecho();// 启用键盘特殊键处理c.keypad(c.stdscr, c.TRUE);// 隐藏光标c.curs_set(0);// 确保 snake 列表有足够容量存储初始长度的蛇身try snake.ensureTotalCapacity(INITIAL_LENGTH);// 初始化蛇身,从左到右依次添加for (0..INITIAL_LENGTH) |i| {try snake.append(SnakeSegment{.x = i + 1,.y = 1 });}// 生成第一个食物spawnFood();
}// 关闭 curses 库,结束游戏时清理资源
fn deinit() void {c.endwin();
}// 在随机位置生成食物
fn spawnFood() void {// 使用默认随机数生成器在指定范围内生成食物的 x 坐标food_x = std.random.intRangeAtMost(std.rand.DefaultPrng.init(0).random(), 1, WIDTH - 2);// 使用默认随机数生成器在指定范围内生成食物的 y 坐标food_y = std.random.intRangeAtMost(std.rand.DefaultPrng.init(0).random(), 1, HEIGHT - 2);
}// 清除屏幕并绘制蛇和食物
fn draw() void {// 清除屏幕c.clear();// 绘制蛇的每个身体部分for (snake.items) |segment| {c.mvaddch(@intCast(c_int, segment.y), @intCast(c_int, segment.x), c.ACS_CKBOARD);}// 绘制食物c.mvaddch(@intCast(c_int, food_y), @intCast(c_int, food_x), c.ACS_DIAMOND);// 刷新屏幕显示c.refresh();
}// 更新蛇的位置,处理碰撞检测等
fn update()!void {// 获取蛇的头部位置var head = snake.items[snake.items.len - 1];// 根据当前方向更新头部位置switch (direction) {Direction.UP => head.y -= 1,Direction.DOWN => head.y += 1,Direction.LEFT => head.x -= 1,Direction.RIGHT => head.x += 1,}// 检查蛇是否撞到边界if (head.x == 0 or head.x == WIDTH - 1 or head.y == 0 or head.y == HEIGHT - 1) {game_over = true;return;}// 检查蛇是否撞到自身for (snake.items[0..snake.items.len - 1]) |segment| {if (segment.x == head.x and segment.y == head.y) {game_over = true;return;}}// 在尾部添加新的头部位置try snake.append(head);// 如果蛇吃到食物,生成新食物,否则移除尾部if (head.x == food_x and head.y == food_y) {spawnFood();} else {_ = snake.orderedRemove(0);}
}// 处理用户输入,更新蛇的移动方向
fn handleInput()!void {// 获取用户输入的字符const ch = c.getch();// 根据输入的字符更新蛇的方向switch (ch) {c.KEY_UP => direction = Direction.UP,c.KEY_DOWN => direction = Direction.DOWN,c.KEY_LEFT => direction = Direction.LEFT,c.KEY_RIGHT => direction = Direction.RIGHT,else => {},}
}pub fn main()!void {// 创建一个通用目的分配器var gpa = std.heap.GeneralPurposeAllocator(.{}){};// 获取分配器const allocator = gpa.allocator();// 初始化存储蛇身的动态数组snake = std.ArrayList(SnakeSegment).init(allocator);// 程序结束时释放资源defer snake.deinit();// 初始化游戏try init();// 程序结束时清理 curses 库defer deinit();// 游戏循环while (!game_over) {// 绘制游戏界面draw();// 处理用户输入try handleInput();// 更新游戏状态try update();// 睡眠一段时间,控制游戏速度std.time.sleep(100 * std.time.ns_per_ms);}// 显示游戏结束信息c.mvprintw(HEIGHT / 2, WIDTH / 2 - 5, "Game Over");c.refresh();// 暂停一段时间,让用户看到游戏结束信息std.time.sleep(3 * std.time.ns_per_s);
}
代码解释:
- 导入部分:
const std = @import("std");
:导入 Zig 的标准库。const c = @cImport({ @cInclude("curses.h"); });
:导入 C 的curses
库,用于在终端中进行图形绘制和输入处理。
- 常量部分:
WIDTH
和HEIGHT
:定义游戏窗口的宽度和高度。INITIAL_LENGTH
:蛇的初始长度。Direction
:定义一个枚举类型,表示蛇的移动方向。SnakeSegment
:定义一个结构体,表示蛇的一个身体部分,包含x
和y
坐标。
- 全局变量部分:
snake
:存储蛇的身体部分的动态数组。direction
:存储蛇的当前移动方向。food_x
和food_y
:存储食物的位置。game_over
:标记游戏是否结束。
- 函数部分:
init()
:初始化curses
库,设置一些curses
的属性,初始化蛇的初始位置和长度,并生成第一个食物。deinit()
:关闭curses
库。spawnFood()
:在随机位置生成食物。draw()
:清除屏幕并绘制蛇和食物。update()
:更新蛇的位置,处理碰撞检测,根据是否吃到食物来增长或缩短蛇,并检查游戏是否结束。handleInput()
:根据用户输入更新蛇的移动方向。main()
:主函数,创建GeneralPurposeAllocator
分配内存,初始化snake
列表,调用init()
,在游戏循环中调用draw()
、handleInput()
和update()
,并处理游戏结束状态。
使用说明:
- 编译代码:你可以使用
zig build-exe
命令编译这个程序,例如zig build-exe snake.zig
。 - 运行程序:编译成功后,在终端中运行生成的可执行文件。
- 控制蛇:使用箭头键控制蛇的移动。
请注意,这只是一个非常简单的示例,还有很多可以改进的地方,例如增加分数、增加难度、添加边界检查、处理错误等。此外,这个程序使用了 curses
库进行终端绘制,因此在 Windows 系统上可能需要额外的配置,而在 Linux 或 macOS 系统上应该可以直接运行。 你可以根据需要扩展和完善这个游戏。