C语言:链表实现贪吃蛇游戏(Windows控制台全流程解析)

1. 项目总览:为什么用C语言和链表做贪吃蛇?

大家好,我是老张,一个在C语言和嵌入式领域摸爬滚打了十多年的老程序员。今天想和大家聊聊一个特别经典,也特别能锻炼编程基本功的项目——用C语言在Windows控制台里实现贪吃蛇游戏,而且核心数据结构用的是链表

你可能觉得,现在游戏引擎那么多,图形界面那么炫,为啥还要折腾这个黑乎乎的“控制台”游戏?我告诉你,这个项目麻雀虽小,五脏俱全。它逼着你去理解几个非常核心的东西:数据结构在真实场景下的应用操作系统底层的API调用,以及游戏循环和状态管理的基本思想。链表用来管理动态增长的蛇身,简直是天作之合;而Windows控制台的那些API,能让你抛开图形库的束缚,直接和“终端”对话,这种掌控感是高级语言框架很难给你的。

我当年带新人,第一个实战项目往往就是这个。能独立把它啃下来,你对指针、内存管理、结构体的理解会上一个大台阶。网上能找到的代码很多,但不少只是把代码堆砌出来,缺少“为什么这么做”的深度解析。今天,我就带你从零开始,不光把代码写出来,更要把每一步背后的设计思路和踩过的坑讲清楚。我们目标是:让你看完就能自己动手,做出一个可玩、可扩展的贪吃蛇。

2. 环境搭建与核心工具准备

工欲善其事,必先利其器。我们是在Windows环境下开发,用的就是最经典的Visual Studio(我用的是VS 2022社区版,免费的,大家可以去官网下)。当然,你用其他IDE比如Code::Blocks、Dev-C++,甚至直接用记事本和MinGW GCC命令行编译,也完全没问题,原理都是相通的。

2.1 解决第一个“坑”:控制台终端设置

如果你直接用VS运行C程序,弹出的那个黑框,有时候显示会有点问题,比如宽字符显示不全,或者光标闪得烦人。这里有个小技巧需要设置一下。

在VS里,右键点击你的项目,选择“属性”。找到“链接器” -> “系统”,把“子系统”这一项从“控制台 (/SUBSYSTEM:CONSOLE)”改成“Windows (/SUBSYSTEM:WINDOWS)”。别担心,改了之后程序还是控制台程序,只是启动方式有点变化,对宽字符显示更友好。或者,你也可以在“调试” -> “命令”里,把终端改为“控制台主机”。这个小改动能避免很多后续显示上的诡异问题。

2.2 认识我们的“画笔”和“画布”:Windows控制台API

我们的游戏画面,全是在那个黑色的控制台窗口里,用字符“画”出来的。这就需要用到一组Windows提供的函数,我们称之为Win32 API。别被“API”吓到,你就把它想象成一套工具箱,专门用来操作这个黑框窗口。

首先,我们得能控制这个窗口的大小和标题吧?这里用到一个非常直接的函数:system()。它可以直接执行系统命令。

#include <stdlib.h> // 别忘了头文件

// 设置控制台窗口为100列,30行
system("mode con cols=100 lines=30");
// 把窗口标题改成“贪吃蛇”
system("title 贪吃蛇");

这两行代码通常放在游戏初始化最开始。cols是列数,对应x轴;lines是行数,对应y轴。这里有个关键点:我们后面打印的墙体、蛇身用的是宽字符(比如),一个宽字符占2个普通字符的宽度。所以,如果你计划地图宽度是58个宽字符,那么cols最好设置为58*2=116左右,留点边距。我这里设100列,地图内宽是56(即28个墙块),两边留点空间打印分数信息。

2.3 隐藏烦人的闪烁光标

控制台里有个一直闪烁的光标,很影响游戏画面的整洁。我们必须把它藏起来。这个过程稍微绕一点,需要三个API配合。

  1. GetStdHandle: 获取控制台输出设备的“句柄”。句柄你可以理解为一个门票或者遥控器,有了它,你才能对控制台进行后续操作。

    #include <windows.h>
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    
  2. GetConsoleCursorInfo: 获取当前光标的信息,比如它的大小和是否可见。我们需要把这些信息存到一个结构体里。

    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(hOutput, &cursorInfo);
    

    这个CONSOLE_CURSOR_INFO结构体有两个成员:dwSize(光标大小百分比,1-100)和bVisible(是否可见,TRUE或FALSE)。

  3. SetConsoleCursorInfo: 修改结构体里的信息,然后再设置回去,才能真正生效。

    cursorInfo.bVisible = FALSE; // 设置为不可见
    SetConsoleCursorInfo(hOutput, &cursorInfo);
    

我当初在这里踩过一个坑:以为改了cursorInfo就行了,忘了调用SetConsoleCursorInfo,结果光标死活隐藏不了,排查了半天。所以记住这个流程:获取 -> 修改 -> 设置

2.4 精准定位:在控制台上“坐标”打印

我们的蛇和食物,需要出现在特定的位置,不能总是从左上角开始打印。控制台也有自己的坐标系:左上角是原点(0, 0),X轴向右增长,Y轴向下增长。

这里用到另一个结构体COORD和函数SetConsoleCursorPosition

typedef struct _COORD
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值