趣味贪吃蛇

本文详细介绍了一个基于Windows控制台的贪吃蛇游戏开发过程,包括游戏的主要组成部分、界面设计、控制器逻辑及伪代码实现等内容。通过具体代码展示了蛇的移动、食物生成、碰撞检测等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

贪吃蛇部分

三个角度分析贪吃蛇的主要组成部分

数据
界面
控制器

数据分析

1:只有一条蛇
2:每次屏幕上只有一个食物
3:每(300毫秒)往前走一步

目标界面


食物

游戏界面

  • 蛇结构体
    坐标系中的坐标
    蛇的每个节点结构
    蛇的运动方向

  • 蛇本身
    {
    蛇头
    蛇尾
    蛇方向
    }

食物

  • 游戏结构本身
    game
    {

    食物
    蛇的当前得分
    每个食物的得分
    蛇的速度 sleeptime
    }

  • 伪代码部分
    int gamerun
    {
    //初始化工作
    1、蛇初始化
    蛇的身子
    蛇的方向
    2、食物生成
    边界之内。
    不能和蛇重叠
    随机
    3、基本数据初始化(得分、速度等)

    while(1)
    {
    下个格子坐标
    给蛇加一格,给蛇的结构体加上下一个格子的坐标
    1、蛇会前进
    2、如果按方向键,蛇能改变方向
    3、可能会吃到食物
    1、蛇增长
    2、重新生成食物
    3、加分
    //游戏结束
    1。撞墙
    2。撞自己
    3。ESC退出
    }
    }

其中要使用到的Windows函数

Windows函数
键盘接收函数 接收异步状态

GetAsyncKetState

SHORT WINAPI GetAsyncKeyState(In int vKey);
返回值 按住不放 返回一个很复杂的数 按过一次返回1 没按过返回0

示例

#include <Windows.h>
while(1)
{
    SHORT r=GetAsyncKeyState(VK_UP);
    printf("%d\n",r);
    Sleep(300);
}

//调用标准输出函数
//hStdout 就是平时看到的stdout,类型不一样
//stdout FILE * 类型
//hStdout    HANDLE 类型

移动光标函数
SetConsoleCursorPosition
设置控制台光标坐标
原型

BOOL  WINAPI SetConsoleCursorPosition
(
    _In_ HANDLE hconsoleoutput        GetStdHandle
    _In_ COORD dwCursorPosition
);

示例
移动光标函数 得到标准句柄

HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE)

int i;

COORD coord;
for(i=0; i<6;i++)
{
    coord.X = 2 * i;
    coord.Y = i;
    SetConsoleCursorPosition(hStdout, coord);
    printf("%d",i);
}

控制输出框的界面大小

mod con cols = 10 line = 20
system("mode con cols=60 lines=30");

改变输出字体颜色函数
SetConsoleTextAttribute
设置控制台文本属性

#include <Windows.h>
#include <stdio.h>
int main()
{    //控制台 句柄
    HANDLE consolehwnd =GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(consolehwnd,FOREGROUND_INTENSITY|FOREGROUND_RED);
    printf("RED");
    return 0;
}
FOREGROUND_RED 表示设置前景色为红色,即字体颜色为红色
//前景
FOREGROUND_INTENSITY表示设置前景色为高亮显示,FOREGROUND_GREEN表示绿色,两个参数中间加|表示前景色为高亮绿色                //前景
BACKGROUND_INTENSITY表示设置背景色为高亮显示,BACKGROUND_BULE表示背景色为蓝色
要表示红色字体,白色背景可以使用
SetConsoleTextAttribute(GetStdHandle(STD_OUT_HANDLE),BACKGROUND_INTENSITY|FOREGROUND_INTENSITY|FOREGROUND_RED|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BULE)

https://blog.youkuaiyun.com/sum7mer/article/details/79003631
播放音乐使用步骤连接

#include"resource.h"//导入资源之后有一个resource.h头文件 记得加上
#include<Windows.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")

int main()
{
    PlaySound(LPWSTR(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_LOOP);
    //PlaySound(MAKEINTRESOURCE(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_LOOP);
*     //上面两种方式都可以  IDR_WAVE1 是导入资源的ID     
*     //下面针对第三个参数做一下解释  
*     //SND_RESOURCE 表示使用的资源文件(如果是文本文件 exe要带上一个音乐文件才能实现音乐播放)  
*     //SND_ASYNC  异步播放   
*     //SND_LOOP  循环播放  必须要用到SND_ASYNC  
    return 0;
}

正式代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <Windows.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")

#define ROW (28)
#define COL (28)
//每个节点坐标
typedef struct Pos
{
    int x;
    int y;
}Pos;
//蛇的方向
typedef enum FangXiang
{
    UP,DOWN,LEFT,RIGHT
}FX;
//蛇每个节点结构体
typedef struct SnakeNode
{
    Pos pos;
    struct SnakeNode *pNext;
}SnakeNode;
//蛇结构体
typedef struct Snake
{
    SnakeNode *pHead;
    SnakeNode *pTail;
    FX fx;
}Snake;
//游戏结构体
typedef struct Game
{
    Snake snake;
    Pos FoodPos;
    int score;
    int scorePerFood;
    int sleeptime;
}Game;

void Move(int x, int y);
void DelSnakeBlock(Pos pos);
void PrintSnakeBlock(Pos pos);
//初始化蛇体,生成位置,蛇体长度等
void SnakeInit(Snake *snake)
{
    Pos pos;
    int i = 0;
    SnakeNode *snakenode;
    snake->pHead = NULL;
    for(i=0; i<3; i++)
    {
        pos.x = 5+i;
        pos.y = 5;
        snakenode = (SnakeNode *)malloc(sizeof(SnakeNode));
        assert(snakenode);
        snakenode->pos = pos;

        snakenode->pNext = snake->pHead;
        snake->pHead = snakenode;
    }
    snake->pTail = snake->pHead->pNext->pNext;
    snake->fx = RIGHT;
}
//生成食物时,是否与蛇体重叠
int IsOverlapSnake(int x, int y, Snake *snake)
{
    SnakeNode *pNode;
    pNode = snake->pHead;
    while(pNode != NULL)
    {
        if(pNode->pos.x == x && pNode->pos.y == y)
            return 1;
        pNode = pNode->pNext;
    }
    return 0;

}
//初始化食物
void FoodInit(Pos *pos, Snake *snake)
{
    int x,y;
    do{
        x = rand() % (ROW-1);
        y = rand() % (COL-1);
    }while(IsOverlapSnake(x,y,snake));

    pos->x = x;
    pos->y = y;
}
//初始化
void GameInit(Game *game)
{
    SnakeInit(&game->snake);
    FoodInit(&game->FoodPos,&game->snake);
    game->score = 10;
    game->scorePerFood = 10;
    game->sleeptime = 300;
}
//判断蛇的下一步走到哪个格子
Pos GetNextPos(Snake *snake)
{
    Pos pos = snake->pHead->pos;
    if(snake->fx == RIGHT)
    {
        pos.x += 1;
        return pos;
    }
    else if(snake->fx == UP)
    {
        pos.y -= 1;
        return pos;
    }
    else if(snake->fx == DOWN)
    {
        pos.y += 1;
        return pos;
    }   
    else
    {
        pos.x -= 1;
        return pos;
    }
}
//判断是否吃到食物
int IsEatFood(Pos pos1,Pos pos)
{
    return pos1.x == pos.x && pos1.y == pos.y;
}
//吃到食物,增加一格
void SnakeAdd(Snake *snake,Pos pos)
{
    SnakeNode *pNode = (SnakeNode *)malloc(sizeof(SnakeNode));
    assert(pNode);

    pNode->pos = pos;
    pNode->pNext = snake->pHead;
    snake->pHead = pNode;
    PrintSnakeBlock(pos);
}
//蛇前进
void SnakeRemoveTail(Snake *snake)
{
    SnakeNode *pNode;
    pNode = snake->pHead;
    while(pNode->pNext->pNext != NULL)
    {
        pNode = pNode->pNext;
    }
    DelSnakeBlock(pNode->pNext->pos);
    free(pNode->pNext);
    pNode->pNext = NULL;
}
//是否撞墙
int IsKillByWall(Pos pos)
{
    if(pos.x < 0)
        return 1;
    if(pos.y < 0)
        return 1;
    if(pos.x > ROW-2)
        return 1;
    if(pos.y > COL-2)
        return 1;
    return 0;
}
//是否撞到自己
int IsSuicide(Snake *snake)
{
    Pos pos = snake->pHead->pos;
    SnakeNode *pNode = snake->pHead->pNext;
    while(pNode != NULL)
    {
        if(pNode->pos.x == pos.x && pNode->pos.y == pos.y)
            return 1;
        pNode = pNode->pNext;
    }
    return 0;
}
//暂停函数
void StopRun()
{
    while(1)
    {
        Sleep(300);
        if(GetAsyncKeyState(VK_SPACE))
        {
            return;
        }
    }
}
//移动光标
void Move(int x, int y)
{
    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(hStdout, coord);
}
//字符颜色
//生成蓝色
void PrintColorBlue()
{
    HANDLE c = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(c,FOREGROUND_INTENSITY|FOREGROUND_BLUE);
}
//生成红色
void PrintColorRed()
{
    HANDLE c = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(c,FOREGROUND_INTENSITY|FOREGROUND_RED);
}
//生成绿色
void PrintColorGreen()
{
    HANDLE c = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(c,FOREGROUND_INTENSITY|FOREGROUND_GREEN);
}
//打印墙体
void PrintWall()
{
    int i=0;
    //上方
    system("cls");
    Move(2,1);
    for(i=0; i<ROW;i++)
    {
        Sleep(20);
        PrintColorBlue();
        printf("█");
    }
    //下方
    Move(2,COL+2);
    for(i=0; i<ROW+1;i++)
    {
        Sleep(20);
        PrintColorBlue();
        printf("█");
    }
    //左方
    for(i=0; i<COL+1; i++)
    {
        Sleep(20);
        Move(2,i+1);
        PrintColorBlue();
        printf("█");
    }
    //右方
    for(i=0; i<COL+1; i++)
    {
        Sleep(20);
        Move((ROW+1)*2,i+1);
        PrintColorBlue();
        printf("█");
    }
    Move((ROW+1)*2+20,COL/2);
    PrintColorRed();
    printf("↑↓←→移动");   
    Move((ROW+1)*2+20,COL/2+2);
    printf("F1加速、F2减速");
    Move((ROW+1)*2+20,COL/2+4);
    printf("按空格键暂停,再按一次继续游戏");
    Move((ROW+1)*2+20,COL/2+8);
    printf("当前得分%-3d,食物得分%-2d",10,10);
}
//打印蛇增加的那部分
void PrintSnakeAdd(Pos pos)
{
    PrintColorGreen();
    Move((pos.x+1)*2+2,pos.y+2);
    printf("█");
}
//擦除蛇走过的部分
void PrintDelSnake(Snake *snake)
{
    SnakeNode *pNode;
    pNode = snake->pHead;
    while(pNode->pNext->pNext != NULL)
    {
        pNode = pNode->pNext;
    }
    Move((pNode->pos.x+1)*2+2,pNode->pos.y+2);
    printf("  ");
}
//打印食物
void Printfood(Pos pos)
{
    Move((pos.x+1)*2+2,pos.y+2);
    PrintColorRed();
    printf("¤");
}
//打印一格蛇
void PrintSnakeBlock(Pos pos)
{
    PrintColorGreen();
    Move((pos.x+1)*2+2,pos.y+2);
    printf("█");
}

//擦除一格蛇
void DelSnakeBlock(Pos pos)
{
    Move((pos.x+1)*2+2,pos.y+2);
    printf("  ");
}
//打印蛇
void PrintfSnake(Snake *snake)
{
    SnakeNode *pNode = snake->pHead;
    while(pNode != NULL)
    {
        PrintSnakeBlock(pNode->pos);
        pNode = pNode->pNext;
    }
}
//欢迎函数,打印墙体
void Welcome()
{
    char str[] = "这是你没有玩过的船新版本我是渣渣辉我在贪吃蛇等你";
    int i = 0;  
    PrintColorRed();
    Move((ROW+1)*2-2*7,COL/2);
    for(i=0; i < 24 ;i=i+2)
    {
        Sleep(50);
        printf("%c%c",str[i],str[i+1]);
    }
    Move((ROW+1)*2-2*4+1,COL/2+2);
    Sleep(500);
    for(i=24; i < 34;i=i+2)
    {
        Sleep(20);
        printf("%c%c",str[i],str[i+1]);
    }
    Sleep(500);
    Move((ROW+1)*2-2*5+1,COL/2+4);
    for(i=34; i < 48;i=i+2)
    {
        Sleep(20);
        printf("%c%c",str[i],str[i+1]);
    }
    Sleep(1500);
    Move((ROW+1)*2-2*5,COL/2+6);
    printf("什么?我没在中间?");
    system("mode con cols=100 lines=40");
    Sleep(800);
    Move((ROW+1)*2-2*5,COL/2+7);
    printf("我还没在中间?");
    Sleep(800);
    system("mode con cols=120 lines=40");
    Move((ROW+1)*2-2*5,COL/2+7);
    printf("这下好了");
    Move((ROW+1)*2-2*5,COL/2+8);
    system("pause");

}
void run()
{
    char buf[2] = {0};
    Game game;
    Pos pos;
    //bgm函数
    PlaySound("D:\\1C作业\\Snake\\Snake\\Legend.wav",NULL,SND_FILENAME|SND_ASYNC);
START:
    PrintWall();
    GameInit(&game);
    Printfood(game.FoodPos);
    PrintfSnake(&(game.snake));
    while(1)
    {
        //根据按键方向
        if(GetAsyncKeyState(VK_UP) && game.snake.fx != DOWN){
            game.snake.fx = UP;
        }else if(GetAsyncKeyState(VK_DOWN) && game.snake.fx != UP){
            game.snake.fx = DOWN;
        }else if(GetAsyncKeyState(VK_RIGHT) && game.snake.fx != LEFT){
            game.snake.fx = RIGHT;
        }else if(GetAsyncKeyState(VK_LEFT) && game.snake.fx != RIGHT){
            game.snake.fx = LEFT;
        }
        if(GetAsyncKeyState(VK_SPACE)){
            StopRun();
        }
        //按esc退出游戏
        if(GetAsyncKeyState(VK_ESCAPE)){
            Move((ROW+1)+1-2*2,COL/2);
            printf("游戏结束");
            break;
        }
        //按F1F2加速减速
        if(GetAsyncKeyState(VK_F1)){
            if(game.sleeptime >=200)
                if(game.scorePerFood <= 20)
                    game.scorePerFood += 10;
            if(game.sleeptime >= 100)
                game.sleeptime -= 20;
        }
        if(GetAsyncKeyState(VK_F2)){
            if(game.sleeptime <= 600)
                game.sleeptime += 20;
        }
        //game->snake.fx = RIGHT;
        //下一个格子坐标是什么
        pos = GetNextPos(&(game.snake));
        //判断蛇是否吃到食物
        if(IsEatFood(game.FoodPos,pos))
        {   
            //吃到了  蛇加一节  没吃到继续刷新蛇
            //先删除最后的尾巴,再往蛇头加下一个坐标
            SnakeAdd(&(game.snake),pos);
            FoodInit(&(game.FoodPos),&game.snake);
            Printfood(game.FoodPos);
            game.score += game.scorePerFood;
            //Move((ROW+1)*2+3,COL/2+8);
            Move((ROW+1)*2+20,COL/2+8);
            PrintColorRed();
            printf("当前得分%-3d,食物得分%-2d",game.score,game.scorePerFood);
        }
        else
        {
            SnakeRemoveTail(&(game.snake));
            SnakeAdd(&(game.snake),pos);
        }
        //是否撞墙
        if(IsKillByWall(pos))
        {
            Move((ROW+1)+1-2*6,COL/2);
            printf("撞墙了,游戏结束");
            break;
        }
        ////是否撞自己
        if(IsSuicide(&(game.snake)))
        {
            Move((ROW+1)+1-2*8,COL/2);
            printf("撞到自己了,游戏结束");
            break;
        }
        //睡眠时间
        Sleep(game.sleeptime);
    }
}

//主要调用函数
void test()
{   
    //调用音乐函数
    PlaySound("D:\\1C作业\\Snake\\Snake\\Remember (Original Mix) - Sensitive_Bogdan Bondarenko.wav",NULL,SND_FILENAME|SND_ASYNC);
    Welcome();
    srand((unsigned)time(NULL));
    run();
    Move(0,COL+3);
    printf("\n");
}

引入音乐自动带出来的头文件

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by she.rc
//
#define IDR_WAVE1                       101
#define IDR_WAVE2                       102

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

名存实亡的主函数

#include "Snake.h"

int main()
{
    test();
}

跑起来的样子:
这里写图片描述

1. 用户与权限管理模块 角色管理: 学生:查看实验室信息、预约设备、提交耗材申请、参与安全考核 教师:管理课题组预约、审批学生耗材申请、查看本课题组使用记录 管理员:设备全生命周期管理、审核预约、耗材采购与分发、安全检查 用户操作: 登录认证:统一身份认证(对接学号 / 工号系统,模拟实现),支持密码重置 信息管理:学生 / 教师维护个人信息(联系方式、所属院系),管理员管理所有用户 权限控制:不同角色仅可见对应功能(如学生不可删除设备信息) 2. 实验室与设备管理模块 实验室信息管理: 基础信息:实验室编号、名称、位置、容纳人数、开放时间、负责人 功能分类:按学科(计算机实验室 / 电子实验室 / 化学实验室)标记,关联可开展实验类型 状态展示:实时显示当前使用人数、设备运行状态(正常 / 故障) 设备管理: 设备档案:名称、型号、规格、购置日期、单价、生产厂家、存放位置、责任人 全生命周期管理: 入库登记:管理员录入新设备信息,生成唯一资产编号 维护记录:记录维修、校准、保养信息(时间、内容、执行人) 报废处理:登记报废原因、时间,更新设备状态为 "已报废" 设备查询:支持按名称、型号、状态多条件检索,显示设备当前可用情况 3. 预约与使用模块 预约管理: 预约规则:学生可预约未来 7 天内的设备 / 实验室,单次最长 4 小时(可设置) 预约流程:选择实验室→选择设备→选择时间段→提交申请(需填写实验目的) 审核机制:普通实验自动通过,高危实验(如化学实验)需教师审核 使用记录: 签到 / 签退:到达实验室后扫码签到,离开时签退,系统自动记录实际使用时长 使用登记:填写实验内容、设备运行情况(正常 / 异常),异常情况需详细描述 违规管理:迟到 15 分钟自动取消预约,多次违规限制预约权限 4. 耗材与安全管理模块 耗材管理: 耗材档案:名称、规格、数量、存放位置、
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值