C语言EasyX实现贪吃蛇详解:从环境配置到完整代码

江岸
江岸
发布时间:2026-10-16 | 4人浏览过
原创

本文详细讲解使用C语言和EasyX库开发贪吃蛇游戏的完整过程,涵盖环境配置、核心结构体设计、游戏初始化、移动与交互逻辑实现,并提供完整的可运行源代码。

开发环境与基础准备

本教程基于Windows平台下的C/C++编译器及EasyX图形库。在使用EasyX之前,需要正确配置IDE环境并链接必要的系统库文件。以下是项目所需的基础依赖和预处理指令:

#include<stdio.h>
#include<graphics.h> // EasyX图形处理库
#include<mmsystem.h> // Windows多媒体接口(用于播放音频)
#include<conio.h>    // _getch() 读取键盘输入
#include<time.h>     // srand() 随机数种子
#include<stdlib.h>   // rand(), malloc()

// 链接winmm.lib以支持多媒体命令
#pragma comment(lib,"winmm.lib")

// 常量定义
#define NUM 200      // 最大蛇身长度
#define SIZE 10      // 每个方块的大小(像素)

// 方向枚举,对应虚拟键值
enum Ch { up=72, down=80, left=75, right=77 };

核心数据结构定义

贪吃蛇游戏的核心在于管理蛇身的坐标变化。我们需要定义结构体来存储蛇的头部位置、身体长度、当前移动方向,以及食物的位置和状态。

// 坐标结构体
struct pos {
    int x;
    int y;
};

// 蛇结构体
struct snake {
    int n;          // 当前蛇身长度
    Ch ch;          // 当前移动方向
    pos szb[NUM];   // 蛇身坐标数组
};

// 食物结构体
struct food {
    int x;
    int y;
    bool iseat;     // 是否已被吃掉(是否需要重新生成)
};

// 全局实例
snake s;
food f;

游戏初始化流程

在进入主循环前,需要对窗口、随机数种子、蛇的初始状态进行设置。

void gameinit()
{
    // 设置随机数种子
    srand((unsigned int)time(NULL));
    
    // 初始化蛇:长度为2,向右移动
    s.n = 2;
    s.ch = right;
    
    // 设置初始位置:两个方块,分别位于(100,100)和(90,100)
    s.szb[0].x = 100; s.szb[0].y = 100;
    s.szb[1].x = 90;  s.szb[1].y = 100;
    
    // 标记食物未被吃,触发首次生成
    f.iseat = true;
}

图像绘制逻辑

每一帧都需要先清屏,然后绘制蛇头和蛇身,最后绘制食物。注意坐标系Y轴向下增长的特性。

void drawgame()
{
    cleardevice(); // 清屏
    
    // 绘制蛇头(红色实心矩形)
    setfillcolor(RED);
    fillrectangle(s.szb[0].x, s.szb[0].y, 
                  s.szb[0].x + SIZE, s.szb[0].y + SIZE);
    
    // 绘制蛇身(绿色空心矩形)
    for (int i = 1; i < s.n; i++) {
        rectangle(s.szb[i].x, s.szb[i].y,
                  s.szb[i].x + SIZE, s.szb[i].y + SIZE);
    }
    
    // 绘制食物(圆形,绿色填充)
    if (!f.iseat) {
        setfillcolor(GREEN);
        fillroundrect(f.x, f.y, f.x + SIZE, f.y + SIZE, 5, 5);
    }
}

第1步:实现蛇的移动算法

蛇的移动本质上是数据结构的移位。除头部外,所有身体部位的坐标都变为前一节身体的坐标,然后根据方向更新头部坐标。

void snakemove()
{
    // 身体跟进:从后往前复制坐标
    for (int i = s.n - 1; i > 0; i--)
    {
        s.szb[i].x = s.szb[i - 1].x;
        s.szb[i].y = s.szb[i - 1].y;
    }
    
    // 根据当前方向移动头部
    switch (s.ch)
    {
    case up:    s.szb[0].y -= SIZE; break;
    case down:  s.szb[0].y += SIZE; break;
    case left:  s.szb[0].x -= SIZE; break;
    case right: s.szb[0].x += SIZE; break;
    }
}

第2步:处理用户输入

使用非阻塞输入函数检测按键,同时防止蛇直接反向移动导致立即死亡(例如正在向右时不能按左)。

void changech()
{
    char key;
    key = _getch(); // 获取按键,不等待回车
    
    switch (key)
    {
    case up:
        if (s.ch != down) s.ch = up;
        break;
    case down:
        if (s.ch != up) s.ch = down;
        break;
    case left:
        if (s.ch != right) s.ch = left;
        break;
    case right:
        if (s.ch != left) s.ch = right;
        break;
    }
}

第3步:生成食物

当食物被吃掉后,在空白区域随机生成新食物,并确保新生成的坐标不与现有蛇身重合。

void creatfood()
{
    bool flag = false;
    if (f.iseat == true) {
        while (1)
        {
            flag = false;
            // 假设窗口大小为640x480,网格大小SIZE=10
            f.x = rand() % (640 / SIZE) * SIZE;
            f.y = rand() % (480 / SIZE) * SIZE;
            
            // 检查是否与蛇身重合
            for (int i = 0; i < s.n; i++)
            {
                if (f.x == s.szb[i].x && f.y == s.szb[i].y)
                {
                    flag = true;
                    break;
                }
            }
            
            if (!flag) {
                f.iseat = false; // 生成成功,标记为已存在
                break;
            }
        }
    }
}

第4步:判定游戏结束

判断条件包括:撞击边界(超出窗口范围)或撞击自身(头部坐标与身体任一部位相同)。

int gameover()
{
    // 撞墙判断
    if (s.szb[0].x < 0 || s.szb[0].x >= 640 || 
        s.szb[0].y < 0 || s.szb[0].y >= 480)
    {
        return 1;
    }
    
    // 撞身判断
    for (int i = 1; i < s.n; i++)
    {
        if (s.szb[0].x == s.szb[i].x && s.szb[0].y == s.szb[i].y)
        {
            return 1;
        }
    }
    
    return 0;
}

第5步:合成主循环

将上述功能模块组合到main函数中,启动图形窗口,并建立“移动-绘制-检测-输入”的游戏循环。

int main()
{
    // 初始化640x480窗口
    initgraph(640, 480);
    
    // 可选:播放背景音乐
    mciSendString(L"open bgm.mp3", 0, 0, 0);
    mciSendString(L"play bgm.mp3", 0, 0, 0);
    
    gameinit();
    
    int isOver = 0;
    
    while (1) {
        // 只有在没有按键按下时才自动移动,否则保持静止等待输入
        // 这种机制允许玩家通过快速按键暂停
        while (!_kbhit()) {
            snakemove();
            drawgame();
            creatfood();
            eatfood();
            
            isOver = gameover();
            if (isOver) break;
            
            Sleep(100); // 控制游戏速度(毫秒)
        }
        
        if (isOver) break;
        
        changech(); // 更新方向
    }
    
    closegraph();
    getchar(); // 暂停以便查看结果
    return 0;
}

// 补充 eatfood 逻辑
void eatfood()
{
    if (s.szb[0].x == f.x && s.szb[0].y == f.y) {
        f.iseat = true; // 标记食物消失,下一帧会重新生成
        s.n++;          // 蛇身变长
    }
}

总结

贪吃蛇的实现关键在于理解二维数组/坐标列表的运动规律。通过将游戏分解为初始化、渲染、逻辑更新和用户输入四个模块,可以清晰地掌握开发流程。以上代码提供了一个基础版本,开发者可根据需要扩展难度、添加分数记录或音效反馈。

以上就是使用C语言和EasyX实现贪吃蛇游戏的详细内容,更多关于C语言小游戏开发的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表