基于Visual Studio的贪吃蛇

首先需要安装eazyx库:EasyX Graphics Library for C++

#define _CRT_SECURE_NO_WARNINGS  1  //解决scanf等函数不安全
#undef UNICODE  //解决没有与参数列表匹配的重载函数"outtextxy"实例
#undef _UNICODE  //解决没有与参数列表匹配的重载函数"settextstyle"实例
#include <graphics.h>
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <cstdio>

#define    WIDTH 40        
#define HEIGHT 30        
#define SIZE 20            

int blocks[WIDTH][HEIGHT] = { 0 };        //用以表示所有方格
char dir;            //表示运动方向
char lastdir;            //旧的移动方向
int fx, fy;                //food食物坐标
int speed = 15;        //控制初始速度
int failure = 0;        //用以判断游戏是否失败,失败赋值为 1
int score = 0;            //记录分数
int highscore = 0;            //记录最高分
int k = 1;                //奖励机制初始值
char num[20];            //输出分数数组
char best[20];            //最高分数组    

void initGame();
void show();            //图像绘制更新显示函数
void WithInput();        //与输入有关的更新
void WithoutInput();    //与输入无关的更新
void movesnake();        //蛇的移动函数
void readscore();        //读取分数
void writescore();        //写入分数
void ShowWord();        //界面文字
void drawmenu();        //主菜单
void gamestart();        //开始游戏
void seerule();            //查看规则
void back();            //退出游戏

void initGame() {
    int i;
    initgraph(1000, 600);        //初始化绘图窗口,格子个数乘格子大小即为长度
    setbkcolor(CYAN);        //设置背景颜色
    BeginBatchDraw();        //easyx中实现批绘图功能的函数,可以消除图像闪烁
    cleardevice();            //使用当前背景色清空绘图设备
    setlinecolor(WHITE);    //划线颜色为白色

    for (i = Size; i < Width * Size + 1; i += Size) {        //用for循环绘制多条线
        line(i, 0, i, Height * Size);                //竖线坐标从x1(i,0)-> y1(i,Height * Size)
    }
    for (i = Size; i < Height * Size; i += Size) {
        line(0, i, Width * Size, i);                //横线坐标从x2(0,i) -> y2(Width * Size, i)
    }

    moveDir = oldmove = 'd';            //初始化默认蛇行进方向朝右

    blocks[Width / 2][Height / 2] = 1;                /*正中间画蛇头,蛇为赋值的方格
                                                    0则为空白区域*/
    for (i = 1; i < 4; i++) {
        blocks[Width / 2 - i][Height / 2] = i + 1;    //y坐标不变,更改x坐标,在蛇头后方画蛇身
    }

    srand(time(0));                                    //srand函数产生一个时间种子,从而达到真正的随机效果
    fx = rand() % (Width - 1) + 1;                    //随机数除39取余并+1,则为食物所生成的格子x坐标
    fy = rand() % (Height - 1) + 1;                    //随机数除取余并+1,则为食物所生成的格子y坐标
}

void show() {
    cleardevice();
    for (int i = 0; i < Width; i++) {                //遍历所有方格,更新蛇的颜色
        for (int j = 1; j < Height; j++) {
            if (blocks[i][j] != 0) {
                setfillcolor(HSVtoRGB(blocks[i][j] * 10, 0.9, 1));    //HSV转RGB颜色,色调H 0°->360°,此处设置每长一个蛇身,提升10°色调,饱和度0.9,明度1
            }
            else {
                setfillcolor(CYAN);                    //否则更新为正常背景颜色
            }
            fillrectangle(i * Size, j * Size, (i + 1) * Size, (j + 1) * Size);        //填充,(参数为左上角和右下角坐标)
        }
    }
    setfillcolor(LIGHTGREEN);                        //食物颜色
    fillrectangle(fx * Size, fy * Size, (fx + 1) * Size, (fy + 1) * Size);

    ShowWord();

    FlushBatchDraw();                /*BeginBatchDraw执行后,任何绘图操作都将暂时不输出到绘图窗口上
                                直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。*/
}

void ShowWord() {
    if (failure) {
        settextcolor(LIGHTRED);                        //设置字体颜色
        settextstyle(80, 0, _T("宋体"));                //设置字体样式
        setbkmode(TRANSPARENT);
        outtextxy(240, 220, "游戏失败");
        settextstyle(40, 0, _T("宋体"));
        sprintf(num, "%d", score);                        //将int转换为char并存入num中
        outtextxy(260, 360, "分数:");                    //显示的字体及坐标
        outtextxy(380, 360, num);
    }
    else {                                                //②
        settextcolor(BLACK);                            //设置分数颜色
        settextstyle(25, 0, _T("隶书"));                //设置字体样式
        setbkmode(TRANSPARENT);                            //设置当前设备图案填充和文字输出时的背景模式,THANSPARENT为透明背景
        sprintf(num, "%d", score);                        //将int转换为char并存入num中
        outtextxy(860, 40, "分数:");                    //显示的字体及坐标
        outtextxy(940, 42, num);
        outtextxy(845, 73, "最高分:");
        sprintf(best, "%d", max);
        outtextxy(940, 75, best);
    }
}
void readscore() {                                        //③
    FILE* fpread = fopen("score.txt", "r");                //以只读的方式打开文件
    if (fpread == NULL) {
        return;
    }
    fscanf(fpread, "%d", &max);
    fclose(fpread);
}

void writescore() {
    FILE* fpWrite = fopen("score.txt", "w");            //"w"打开并写入文本文件.(若不存在则新建,反之,则从头写,覆盖原内容)
    if (fpWrite == NULL) {
        return;
    }
    fprintf(fpWrite, "%d", score);
    fclose(fpWrite);
}

void WithInput() {
    if (_kbhit() && failure == 0) {
        //键盘输入控制蛇的方向
        char input = _getch();

        if (input == 'a' || input == 's' || input == 'd' || input == 'w') {
            moveDir = input;
            //设定规则:当向某一方向行动时,按下反向键不起作用(防止误触导致判断为咬到蛇身游戏失败),强制将按下的反向键变为当前运动方向
            if (moveDir == 'a' && oldmove == 'd') {
                moveDir = 'd';
            }
            else if (moveDir == 's' && oldmove == 'w') {
                moveDir = 'w';
            }
            else if (moveDir == 'd' && oldmove == 'a') {
                moveDir = 'a';
            }
            else if (moveDir == 'w' && oldmove == 's') {
                moveDir = 's';
            }
            else {
                oldmove = input;
            }
            movesnake();
        }
    }
}

void WithoutInput() {

    if (failure) {                //先判断是否失败,失败则返回
        return;
    }
    //Sleep(100);                //更新速度控制蛇的移动速度,但使用sleep会产生键盘控制与画面的延迟,所以不使用
    //movesnake();
    static int speed = 1;        //设置一个静态变量speed,利用循环特定次数来触发movesnake函数
    speed++;
    if (speed == addspeed) {    //每15帧移动一次,同时实现长按方向键加快蛇的移动速度
        movesnake();
        speed = 1;
    }
}

void movesnake() {
    int i, j;
    //对蛇进行更新,蛇每个格数值都+1,以便后面预备一个数值为1的新蛇头,当吃到食物时,新蛇头改变颜色加入蛇身中
    for (i = 0; i < Width; i++) {
        for (j = 0; j < Height; j++) {
            if (blocks[i][j] != 0) {
                blocks[i][j]++;
            }
        }
    }

    int oldhx, oldhy, oldtx, oldty;            //旧蛇头和旧蛇尾的坐标
    int tailblock = 0;
    for (i = 0; i < Width; i++) {
        for (j = 0; j < Height; j++) {
            if (tailblock < blocks[i][j]) {
                tailblock = blocks[i][j];    //遍历找出最大值即为蛇尾
                oldtx = i;
                oldty = j;
            }
            if (blocks[i][j] == 2) {            //寻找旧蛇头
                oldhx = i;
                oldhy = j;
            }
        }
    }
    //根据蛇的运动方向来赋值新蛇头的xy坐标
    int newhx = oldhx, newhy = oldhy;        //定义新蛇头
    switch (moveDir) {
    case'a':
        newhx -= 1;
        break;
    case's':
        newhy += 1;
        break;
    case'd':
        newhx += 1;
        break;
    case'w':
        newhy -= 1;
        break;
    }
    //判断游戏是否失败
    if (newhx >= Width || newhx < 0 || newhy >= Height || newhy < 0 || blocks[newhx][newhy] != 0) {
        failure = 1;
        return;
    }
    //令蛇头方格值为1
    blocks[newhx][newhy] = 1;
    //对吃到食物以及蛇尾的处理                ⑤
    if (newhx == fx && newhy == fy) {        //吃到食物,重新随机数生成新食物坐标
        score = score + k;                    //吃到食物分数+k
        if (score % 2 == 0) {                //通过判断吃食物的数量来叠加奖励分
            k = k + 1;
        }

        if (score > max) {                    //与最高分判断,条件成立才能覆盖最高分
            writescore();                    //写入最高分
        }
        //④
        if (score) {                        //“加速”判断,通过判断分数增大的取值,加快蛇的运动速度,score不为0时进入该判断语句
            if (score % 2 == 0) {            //便于测试结果明显,设置每吃2个食物,蛇速度加快1帧
                addspeed--;
            }
        }
        fx = rand() % (Width - 1) + 1;
        fy = rand() % (Height - 1) + 1;
    }
    else {                                    //未吃到食物
        blocks[oldtx][oldty] = 0;
    }


}

void drawmenu() {
    MOUSEMSG m;                    //定义结构体鼠标m
    initgraph(600, 600);        //定义画布大小
    setbkcolor(CYAN);            //设置背景颜色
    cleardevice();                //使用当前背景色清空绘图设备,类似system(cls)的刷新
    setfillcolor(WHITE);    //方框颜色

    fillrectangle(140, 50, 460, 170);            //矩形左上角xy坐标和右下角xy坐标
    fillrectangle(120, 220, 480, 350);            //矩形左上角xy坐标和右下角xy坐标
    fillrectangle(100, 400, 500, 540);            //矩形左上角xy坐标和右下角xy坐标

    settextcolor(BLACK);                        //设置字体颜色
    settextstyle(50, 0, _T("楷体"));            //设置字体格式
    setbkmode(TRANSPARENT);                        //去除文字背景

    outtextxy(200, 85, "开始游戏");                //文字输出位置的xy坐标
    outtextxy(200, 260, "查看规则");
    outtextxy(200, 445, "退出游戏");

    while (1) {
        m = GetMouseMsg();                        //获取一个鼠标消息
        if (m.x >= 140 && m.x <= 460 && m.y >= 50 && m.y <= 170) {        //判断鼠标点击的位置
            if (m.uMsg == WM_LBUTTONDOWN) {        //当鼠标按下左键
                gamestart();                    //开始游戏
            }
        }
        else if (m.x >= 120 && m.x <= 480 && m.y >= 220 && m.y <= 350) {
            if (m.uMsg == WM_LBUTTONDOWN) {        //当鼠标按下左键
                seerule();                    //查看规则
            }
        }
        else if (m.x >= 100 && m.x <= 500 && m.y >= 400 && m.y <= 540) {
            if (m.uMsg == WM_LBUTTONDOWN) {        //当鼠标按下左键
                back();                    //关闭菜单退出游戏
            }
        }
    }
}

void gamestart() {
    readscore();        //读取最高分
    initGame();            //游戏初始化
    while (1) {            //循环进行界面实时刷新,直至游戏判定失败
        show();            //界面显示
        WithoutInput();    //先调用与输入无关的更新
        WithInput();
    }
}

void seerule() {
    MOUSEMSG m;                    //定义结构体鼠标m

    readscore();                //读取历史最高分

    initgraph(600, 600);        //定义画布大小
    setbkcolor(CYAN);            //设置背景颜色
    cleardevice();                //使用当前背景色清空绘图设备,类似system(cls)的刷新
    setfillcolor(WHITE);    //方框颜色

    fillrectangle(100, 400, 500, 540);            //矩形左上角xy坐标和右下角xy坐标

    settextcolor(BLACK);                        //设置字体颜色
    settextstyle(50, 0, _T("楷体"));            //设置字体格式
    setbkmode(TRANSPARENT);                        //去除文字背景
    outtextxy(200, 445, "返回菜单");

    settextcolor(BLACK);                        //设置字体颜色
    settextstyle(30, 0, _T("楷体"));            //设置字体格式
    setbkmode(TRANSPARENT);                        //去除文字背景
    outtextxy(45, 30, "WASD控制蛇移动,长按方向键可加速移动");
    outtextxy(45, 80, "碰到墙壁游戏失败");
    outtextxy(45, 130, "吃的食物越多,分数奖励越高");
    outtextxy(45, 180, "历史最高分:");
    sprintf(best, "%d", max);
    outtextxy(220, 180, best);

    while (1) {
        m = GetMouseMsg();                        //获取一个鼠标消息
        if (m.x >= 100 && m.x <= 500 && m.y >= 400 && m.y <= 540) {
            if (m.uMsg == WM_LBUTTONDOWN) {        //当鼠标按下左键
                drawmenu();                    //返回主菜单
            }
        }
    }
}

void back() {
    closegraph();        //关闭画面
    exit(0);            //退出程序
}

int main() {
    drawmenu();
    return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以为您提供一些指导。首先,您需要安装 Visual Studio。然后,在 Visual Studio 中创建一个新的控制台应用程序项目。接下来,您需要编写代码来实现贪吃游戏的逻辑。您可以使用C++或C#等语言来编写代码。 以下是一个简单的C++示例代码,用于创建一个基本的贪吃游戏: ``` #include <iostream> #include <conio.h> #include <Windows.h> using namespace std; bool gameOver;//游戏是否结束的变量 const int width = 20;//游戏窗口的宽度 const int height = 20;//游戏窗口的高度 int x, y, fruitX, fruitY, score;//的头的位置,水果的位置和分数 int tailX[100], tailY[100];//记录的尾巴的位置 int nTail;//的长度 enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN };//定义方向 eDirection dir;//当前的方向 void Setup()//游戏初始化函数 { gameOver = false;//将gameOver设置为false dir = STOP;//将的方向初始化为停止 x = width / 2;//将的x坐标初始化为窗口的中央 y = height / 2;//将的y坐标初始化为窗口的中央 fruitX = rand() % width;//将水果的x坐标随机分配 fruitY = rand() % height;//将水果的y坐标随机分配 score = 0;//将分数初始化为零 } void Draw()//绘制游戏窗口函数 { system("cls");//清空屏幕 for (int i = 0; i < width + 2; i++) cout << "#"; cout << endl; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (j == 0) cout << "#"; if (i == y && j == x) cout << "O"; else if (i == fruitY && j == fruitX) cout << "F"; else { bool print = false; for (int k = 0; k < nTail; k++) { if (tailX[k] == j && tailY[k] == i) { cout << "o"; print = true; } } if (!print) cout << " "; } if (j == width - 1) cout << "#"; } cout << endl; } for (int i = 0; i < width + 2; i++) cout << "#"; cout << endl; cout << "Score:" << score << endl;//显示分数 } void Input()//获取玩家的输入函数 { if (_kbhit()) { switch (_getch()) { case 'a': dir = LEFT;//将的方向设置为向左 break; case 'd': dir = RIGHT;//将的方向设置为向右 break; case 'w': dir = UP;//将的方向设置为向上 break; case 's': dir = DOWN;//将的方向设置为向下 break; case 'x': gameOver = true;//将gameOver设置为true break; } } } void Logic()//游戏逻辑函数 { int prevX = tailX[0];//记录的尾巴之前的x坐标 int prevY = tailY[0];//记录的尾巴之前的y坐标 int prev2X, prev2Y;//经过交换之后记录的尾巴位置的变量 tailX[0] = x;//将的尾巴移到头部的位置 tailY[0] = y; for (int i = 1; i < nTail; i++) { prev2X = tailX[i];//记录的尾巴之前的x坐标 prev2Y = tailY[i];//记录的尾巴之前的y坐标 tailX[i] = prevX;//将的尾巴移动到它的前一节 tailY[i] = prevY; prevX = prev2X; prevY = prev2Y; } switch (dir) { case LEFT: x--;//将的x坐标减1 break; case RIGHT: x++;//将的x坐标加1 break; case UP: y--;//将的y坐标减1 break; case DOWN: y++;//将的y坐标加1 break; default: break; } if (x > width || x < 0 || y > height || y < 0)//如果碰到了窗口的边缘,则游戏结束 gameOver = true; for (int i = 0; i < nTail; i++) if (tailX[i] == x && tailY[i] == y)//如果碰到了自己的尾巴,则游戏结束 gameOver = true; if (x == fruitX && y == fruitY)//如果吃到了水果,则分数加1 { score += 10; fruitX = rand() % width;//将水果的x坐标随机分配 fruitY = rand() % height;//将水果的y坐标随机分配 nTail++;//的长度增加1 } } int main()//主函数 { Setup();//初始化游戏 while (!gameOver)//游戏循环 { Draw();//绘制游戏窗口 Input();//获取玩家的输入 Logic();//游戏逻辑 Sleep(50);//暂停50毫秒,用于控制游戏速度 } return 0; } ``` 这只是一个简单的示例,您可以根据自己的需求进行修改和扩展。希望对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值