贪吃蛇控制台版本c++

这是一个贪吃蛇游戏的控制台版本。
游戏制作的思路是用二维数组表示地图,用链表表示蛇身,通过对链表的增添节点、删除节点模拟蛇的移动、进食。通过随机函数随机生成食物,蛇运动速度随得分增多而增加。

Snake类的定义。

class Snake
{
private:
    int map[25][25];                              //地图
    int length;                                   //蛇的长度
    int direction_x, direction_y;
    PsnakeItem head, tail;                        //蛇头、蛇尾

    int start_x, start_y;                         //出发点
    int level;                                    //级别
    int grade;                                    //分数  
    int maxgrade;                                 //最高分
public:
    Snake()
    {
        for (int i = 0; i < 25; i++)
            for (int j = 0; j < 25; j++)
                map[i][j] = 0;
        length = 0;

        direction_x = 1;
        direction_y = 0;

        start_x = 15;
        start_y = 15;
        level = 1;      //游戏等级
        grade = 0;      //分数
        maxgrade = 0;   //最高分

        head = tail = NULL;
    }
    void SetColor(int colorID);                   //设置颜色
    void Welcome(void);                           //绘制欢迎界面
    void DrawInterface(void);                     //绘制游戏界面
    void DrawBox(int position_x, int position_y);    //绘制方块
    void RedrawBox(int position_x, int position_y);  //擦除方块
    void MakeBlock(void);                         //随机生成食物
    void UpdataHead(int position_x, int position_y);  //在蛇的头部增加一个节点
    void DeleteTail(void);  //删去蛇尾部最后一个节点
    void DrawSnake(void);
    void Move(void);
    void Run(void);
    int Judge(void);
    void Updata(void);         //更新分数及等级
};

蛇身节点

typedef struct snakenode NsnakeItem;          //定义节点
struct snakenode {
    int position_x;
    int position_y;
    NsnakeItem *Next;
};
typedef NsnakeItem *PsnakeItem;               //节点指点

这里采用宏定义的方式简化表示各种方块。

#define blank 0
#define body  1
#define wall  2
#define top   3
#define food  4

通过变量direction_x,direction_y来表示蛇的当前运动方向,通过W A S D改变方向。以上为游戏的底层实现方法。

对于界面的绘制,调用系统函数来设定光标位置。

void SetPos(int i, int j)//设定光标位置 i代表列数  j代表行数 
{
    COORD pos = { (short)i,(short)j };//坐标对象,用来设置光标的行列位置
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

由于游戏中使用■表示个元素,其宽度为普通字符2倍,所以如下定义方块绘制函数。

void Snake::DrawBox(int position_x, int position_y)
{
    int nx = position_x, ny = position_y;
    SetPos( position_x * 2, position_y );
    cout << "■";
}

下面是游戏实现的核心,蛇的运动及与键盘交互的部分。

void Snake::Run(void)
{
    int i = 0;//用于控制下落时间
    char x;   //储存用户输入的字符
    int Count;//计数器

#pragma region draw;
    //蛇的初始绘制
    UpdataHead(10, 12);
    UpdataHead(10, 13);
    UpdataHead(10, 14);
    UpdataHead(10, 15);
    UpdataHead(11, 15);
    UpdataHead(12, 15);
    UpdataHead(13, 15);
    UpdataHead(14, 15);
    DrawSnake();
    DrawInterface();
    //绘制结束
#pragma endregion;
    MakeBlock();
    while (1)
    {
        if (level < 10)
            Count = 500 - level * 50;    //快慢 ,Count决定了下落运动间隔
        else
            Count = 50 - level * 2;
        if (i >= Count)                  //如果i大于Count,表明时间过了Count毫秒
        {
            i = 0;
            Move();                      //蛇的移动
        }
        if (_kbhit())                    //读取字符
        {
            x = _getch();
            if (x == 'a' || x == 'A')
            {
                if (!(direction_x == 1 && direction_y == 0))
                {
                    direction_x = -1;
                    direction_y = 0;
                }
            }
            else if (x == 'd' || x == 'D')
            {
                if (!(direction_x == -1 && direction_y == 0))
                {
                    direction_x = 1;
                    direction_y = 0;
                }
            }
            else if (x == 'w' || x == 'W')
            {
                if (!(direction_x == 0 && direction_y == 1))
                {
                    direction_x = 0;
                    direction_y = -1;
                }
            }
            else if (x == 's' || x == 'S')
            {
                if (!(direction_x == 0 && direction_y == -1))
                {
                    direction_x = 0;
                    direction_y = 1;
                }
            }
            else if (x == 'p' || x == 'P')
            {
                while (1)
                {
                    x = _getch();
                    if (x == 'p' || x == 'P')
                        break;
                }
            }
            while (_kbhit())               //此处作用为除去运行中缓冲区多余字符
                x = _getch();
        }
        Sleep(1);                   //延迟1毫秒
        i++;
    }
}

程序由VS2017编译。以下是源代码

// pch.h

#ifndef PCH_H
#define PCH_H

#define _CRT_SECURE_NO_WARNINGS
using namespace std;
#include <Windows.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
#include<stdlib.h>
#include<cstdio>
#include<string>
#include <algorithm>

typedef struct snakenode NsnakeItem;          //定义节点
struct snakenode {
    int position_x;
    int position_y;
    NsnakeItem *Next;
};
typedef NsnakeItem *PsnakeItem;               //节点指针

struct scoredata{
        char name[10];
        int grade;
};
typedef struct scoredata *Scoredata;
// TODO: 添加要在此处预编译的标头

#endif //PCH_H

#include "pch.h"
#include <iostream>

#pragma region DefinationOfBlock

#define blank 0
#define body  1
#define wall  2
#define top   3
#define food  4

#pragma endregion

class Snake
{
private:
    int map[25][25];                              //地图
    int length;                                   //蛇的长度
    int direction_x, direction_y;
    PsnakeItem head, tail;                        //蛇头、蛇尾

    int start_x, start_y;                         //出发点
    int level;                                    //级别
    int grade;                                    //分数  
    int maxgrade;                                 //最高分
public:
    Snake()
    {
        for (int i = 0; i < 25; i++)
            for (int j = 0; j < 25; j++)
                map[i][j] = 0;
        length = 0;

        direction_x = 1;
        direction_y = 0;

        start_x = 15;
        start_y = 15;
        level = 1;      //游戏等级
        grade = 0;      //分数
        maxgrade = 0;   //最高分

        head = tail = NULL;
    }
    void SetColor(int colorID);                   //设置颜色
    void Welcome(void);                           //绘制欢迎界面
    void DrawInterface(void);                     //绘制游戏界面
    void DrawBox(int position_x, int position_y);    //绘制方块
    void RedrawBox(int position_x, int position_y);  //擦除方块
    void MakeBlock(void);                         //随机生成食物
    void UpdataHead(int position_x, int position_y);  //在蛇的头部增加一个节点
    void DeleteTail(void);  //删去蛇尾部最后一个节点
    void DrawSnake(void);
    void Move(void);
    void Run(void);
    int Judge(void);
    void Updata(void);         //更新分数及等级
};

void SetPos(int i, int j)//设定光标位置 i代表列数  j代表行数  特殊字符列需要比行多一个位置输出
{
    COORD pos = { (short)i,(short)j };//坐标对象,用来设置光标的行列位置
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

void Snake::SetColor(int colorID)
{
    int n_color;
    switch (colorID)
    {
    case 0: n_color = 0x08; break;
    case 1: n_color = 0x0C; break;
    case 2: n_color = 0x0D; break;
    case 3: n_color = 0x0E; break;
    case 4: n_color = 0x0A; break;
    case 5: n_color = 0x0B; break;
    case 6: n_color = 0xDC; break;
    case 7: n_color = 0xEC; break;
    }
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n_color);
}

void Snake::DrawBox(int position_x, int position_y)
{
    int nx = position_x, ny = position_y;
    SetPos( position_x * 2, position_y );
    cout << "■";
}

void Snake::RedrawBox(int position_x, int position_y)
{
    int nx = position_x, ny = position_y;
    SetPos(position_x * 2, position_y);
    cout << "  ";
}

void Snake::DrawInterface(void)                     
{
    SetPos(0, 0);
    SetColor(0);
        FILE *fp;                                       //从文件中读取地图
    if ((fp = fopen("map.txt", "r")) == NULL)
    {
        printf("File open error!\n");
        exit(0);
    }
    for (int i = 0; i < 25; i++)
        for (int j = 0; j < 25; j++)
            fscanf(fp, "%d", &map[j][i]);
    if (fclose(fp))
    {
        printf("Can not close the file!\n");
        exit(0);
    }                                               //读取结束
    for (int i = 0; i < 25; i++)
        for (int j = 0; j < 25; j++)
            if(map[i][j] == wall)
                DrawBox(i, j);
    for (int i = 27; i < 37; i++)           //游戏副边框
    {
        DrawBox(i, 9);
        DrawBox(i, 19);
    }
    for (int i = 9; i <= 19; i++)
    {
        DrawBox(27, i); 
        DrawBox(37, i);
    }

    if ((fp = fopen("score.dat", "r")) == NULL)
    {
        printf("File open error!\n");
        exit(0);
    }
    fscanf(fp, "%d", &maxgrade);
    if (fclose(fp))
    {
        printf("Can not close the file!\n");
        exit(0);
    }
    SetPos(30*2, 11);
    SetColor(2);
    cout << "等级:" << level;
    SetPos(30*2, 13);
    cout << "分数:" << grade;
    SetPos(30 * 2, 15);
    cout << "最高分:" << maxgrade;
    SetColor(0);
}

void Snake::DrawSnake(void)
{
    PsnakeItem ptravel = head;
    SetColor(7);
    DrawBox(ptravel->position_x, ptravel->position_y);
    ptravel = ptravel->Next;
    SetColor(6);
    while (ptravel != NULL)
    {
        DrawBox(ptravel->position_x, ptravel->position_y);
        ptravel = ptravel->Next;
    }
    SetColor(0);
}

void Snake::UpdataHead(int position_x, int position_y)
{
    PsnakeItem pnew = (PsnakeItem)malloc(sizeof(NsnakeItem));
    pnew->position_x = position_x;
    pnew->position_y = position_y;
    if (head == NULL)
    {
        pnew->Next = NULL;
        head = tail = pnew;
    }
    else
    {
        pnew->Next = head;
        head = pnew;
        map[head->Next->position_y][head->Next->position_x] = body;
    }
    if(map[position_y][position_x]== blank|| map[position_y][position_x] == food)
        map[position_y][position_x] = top;
    if (!Judge())
    {
        if (grade > maxgrade)
        {
            FILE *p;
            if ((p = fopen("score.dat", "w")) == NULL)
            {
                printf("File open error!\n");
                exit(0);
            }
            fprintf(p, "%d", grade);
            if (fclose(p))
            {
                printf("Can not close the file!\n");
                exit(0);
            }
        }
        system("cls");
        printf("Game Over");
        Sleep(1000);
        for (int i = 0; i < 25; i++)
            for (int j = 0; j < 25; j++)
                map[i][j] = blank;
        direction_x = 1; direction_y = 0;
        grade = 0;
        level = 1;
        head = NULL;
        Welcome();
    }
}

void Snake::DeleteTail(void)
{
    PsnakeItem ptravel = head;
    while (ptravel->Next != tail)
    {
        ptravel = ptravel->Next;
    }
    map[tail->position_y][tail->position_x] = blank;
    free(tail);
    tail = ptravel;
    tail->Next = NULL;
}

void Snake::Move(void)
{
    int nextPosition_x = head->position_x + direction_x;    //下个节点的坐标
    int nextPosition_y = head->position_y + direction_y;

    if (map[nextPosition_y][nextPosition_x] == food)
    {
        UpdataHead(nextPosition_x, nextPosition_y);             //将节点更新为头
        DrawSnake();
        MakeBlock();
        Updata();
    }
    else
    {
        UpdataHead(nextPosition_x, nextPosition_y);             //将节点更新为头
        RedrawBox(tail->position_x, tail->position_y);          //擦
        DeleteTail();                                           //除去尾部节点
        DrawSnake();
    }
}

int Snake::Judge(void)               
{
    if (map[head->position_y][head->position_x] == wall || map[head->position_y][head->position_x] == body)
        return 0;
    else
        return 1;
}

void Snake::MakeBlock(void)
{
    SetColor(3);
    srand((int)time(0));
    int x, y;
    do {
        x = rand() % 25;
        y = rand() % 25;
    } while (map[y][x] == wall || map[y][x] == body || map[y][x] == top||map[y][x] == food);
    DrawBox(x, y);
    map[y][x] = food;                                    //添加地图food
    SetColor(0);
}

void Snake::Updata(void)
{
    grade += 10;
    level = (grade+40) / 40;
    SetColor(2);
    SetPos(30 * 2, 11); 
    cout << "等级:" << level;
    SetPos(30 * 2, 13);

    cout << "分数:" << grade;
    SetPos(30 * 2, 15);
    cout << "最高分:" << maxgrade;
    SetColor(0);
}

void Snake::Run(void)
{
    int i = 0;//用于控制下落时间
    char x;   //储存用户输入的字符
    int Count;//计数器

#pragma region draw;
    //蛇的初始绘制
    UpdataHead(10, 12);
    UpdataHead(10, 13);
    UpdataHead(10, 14);
    UpdataHead(10, 15);
    UpdataHead(11, 15);
    UpdataHead(12, 15);
    UpdataHead(13, 15);
    UpdataHead(14, 15);
    DrawSnake();
    DrawInterface();
    //绘制结束
#pragma endregion;
    MakeBlock();
    while (1)
    {
        if (level < 10)
            Count = 500 - level * 50;    //快慢 ,Count决定了下落运动间隔
        else
            Count = 50 - level * 2;
        if (i >= Count)
        {
            i = 0;
            Move();
        }
        if (_kbhit())
        {
            x = _getch();
            if (x == 'a' || x == 'A')
            {
                if (!(direction_x == 1 && direction_y == 0))
                {
                    direction_x = -1;
                    direction_y = 0;
                }
            }
            else if (x == 'd' || x == 'D')
            {
                if (!(direction_x == -1 && direction_y == 0))
                {
                    direction_x = 1;
                    direction_y = 0;
                }
            }
            else if (x == 'w' || x == 'W')
            {
                if (!(direction_x == 0 && direction_y == 1))
                {
                    direction_x = 0;
                    direction_y = -1;
                }
            }
            else if (x == 's' || x == 'S')
            {
                if (!(direction_x == 0 && direction_y == -1))
                {
                    direction_x = 0;
                    direction_y = 1;
                }
            }
            else if (x == 'p' || x == 'P')
            {
                while (1)
                {
                    x = _getch();
                    if (x == 'p' || x == 'P')
                        break;
                }
            }
            while (_kbhit())
                x = _getch();
        }
        Sleep(1);
        i++;
    }
}

void Snake::Welcome(void)
{
    char choose;    //界面选择
    SetColor(0);
    while (1)
    {
        SetPos(0, 0);
        cout << "■■■■■■■■■■■■■■■■■■■" << endl;
        cout << "■         贪吃蛇控制台版           ■" << endl;
        cout << "■■■■■■■■■■■■■■■■■■■" << endl;
        cout << "■     A,D左右移动  WS左右移动      ■" << endl;
        cout << "■             P  暂停              ■" << endl;
        cout << "■■■■■■■■■■■■■■■■■■■" << endl;
        cout << "■                                  ■" << endl;
        cout << "■          1.运行游戏              ■" << endl;
        cout << "■                                  ■" << endl;
        cout << "■          2.退出游戏              ■" << endl;
        cout << "■                                  ■" << endl;
        cout << "■■■■■■■■■■■■■■■■■■■" << endl;
        choose = _getch();
        switch (choose)
        {
            case '1': system("cls"); Run(); break;
            case '2': exit(0); break;
            default: break;
        }
    }
}

int main()
{
    Snake snake;
    snake.Welcome();
}   

以下为资源文件map.txt为地图,score.dat储存最高分。

//map.txt
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
//score.dat
0

以下为运行截图
游戏初始界面
游戏运行界面

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值