zig语言初探:来写贪吃蛇游戏

devtools/2025/1/16 3:54:56/

在这里插入图片描述

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 库,用于在终端中进行图形绘制和输入处理。
  • 常量部分
    • WIDTHHEIGHT:定义游戏窗口的宽度和高度。
    • INITIAL_LENGTH:蛇的初始长度。
    • Direction:定义一个枚举类型,表示蛇的移动方向。
    • SnakeSegment:定义一个结构体,表示蛇的一个身体部分,包含 xy 坐标。
  • 全局变量部分
    • snake:存储蛇的身体部分的动态数组。
    • direction:存储蛇的当前移动方向。
    • food_xfood_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 系统上应该可以直接运行。 你可以根据需要扩展和完善这个游戏


http://www.ppmy.cn/devtools/150833.html

相关文章

RocketMQ

目录 一、什么是RocketMQ 主要特点: 应用场景: 二、RocketMQ的使用 添加依赖 配置RocketMQ 创建生产者服务 创建消费者监听器 编写测试Controller 启动Spring Boot应用 三、RocketMQ与Kafka的异同 相似点 不同点 一、什么是RocketMQ Rocke…

【C++学习篇】红黑树 从入门到进阶

目录 1.红黑树的概念 1.1红黑树的规则 1.2红黑树的效率 2. 红黑树的实现 2.1 红黑树的结构 2.2红黑树的插入 2.2.1红黑树插入,旋转的一些细节 2.2.1.1 u(uncle)不存在 ,c为p的左孩子(单旋变色) 2.2.…

C#读写ini配置文件保存设置参数

本示例使用设备:https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1b5P5rkA&ftt&id22173428704 [DllImport("kernel32", CharSet CharSet.Unicode)] public static extern uint GetPrivateProfileString(string lpAppName, stri…

服务器出现蓝屏现象的原因有什么?

当服务器定期出现蓝屏的现象,则会影响到企业业务的连续性,同时还可能会导致重要数据信息丢失和系统稳定性下降,是一种较为复杂的技术问题,本文就来探讨一下导致服务器出现蓝屏的原因都有什么。 服务器出现蓝屏有可能是硬件出现了故…

在Ubuntu下安装PostgreSQL数据库以及安装pgAdmin4工具

文章目录 1. 环境安装2. 基础操作3. 配置数据库4. 安装pgAdmin45. 注意 1. 环境安装 PostgreSQL是一个功能强大的开源对象-关系型数据库系统 QT安装数据库 sudo apt-get update sudo apt-get install libqt5sql5-psql2. 基础操作 sudo su - postgres //进入数据库 psql //数…

深入理解多线程 线程的start方法 底层原理 为何Java=(C++)--

目录 Java 并发包 祖师爷 四大口诀 为什么多线程及其重要 硬件:摩尔定律失效 软件:系统需求 Start 方法 C 源码解读 底层逻辑 操作系统分配 Java 并发包 Java Util Concurrent 祖师爷 四大口诀 为什么多线程及其重要 硬件:摩尔定律…

java fastjson2将 map、实体类、list等 类型转换为JSON介绍

Fastjson2 提供了强大的类型转换功能,可以方便地将 JSON 字符串解析为 Java 对象、集合类型,或者其他自定义类型。这些功能使得 Fastjson2 在 JSON 数据的处理上更为灵活和高效。下面详细介绍 Fastjson2 的类型转换方法和相关用法。 1. 基本的类型转换 …

如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等)

如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等) 如何在本地部署大模型并实现接口访问( Llama3、Qwen、DeepSeek等)模型地址模型下载模型部署指定显卡运行app.py 运行环境requirements 调用接口代码调用 结语 如何…