趣味贪吃蛇

贪吃蛇部分

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

数据
界面
控制器

数据分析

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.csdn.net/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();
}

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

猜你喜欢

转载自blog.csdn.net/qq_41804778/article/details/80930481