C++游戏--贪吃蛇

前言

今天捏,我来带大家打游戏
啊,不对,写游戏!

贪吃蛇游戏规则

你可以使用w,a,s,d来控制贪吃蛇进行上下左右的移动
在移动过程中,每吃到一个果子,你就能增加1分,同时你也会变长 1 格
但,如果你在移动过程中碰到了自己或者墙壁,那么你就GAMEOVER了!
当然,你也可以按下 n 键提前结束游戏。

代码分析

引入

#include <iostream>
#include <termios.h>
#include <cstring>
#include <iomanip>
#include <list>
#include <unistd.h>
#define clear() cout << "\033c" << flush
using namespace std;

定义蛇和全局变量

struct node
{
    int x, y;
};
int num[15][15];
int x, y;
node head, food;
bool Food = false;
list<node> snake;
char ch = 0;
int score = 0;
static struct termios initial_settings, new_settings;
static int peek_character = -1;
void init_keyboard();
void close_keyboard();
bool kbhit();
char readch();
void changeNum();
void drawBoard();
void move();
int scanKeyboard();
void init_snake();
void fullFood();
bool getFood();
void longer();
bool gameOver();
void intro();
int getch(); // 不回显函数

主函数

int main()
{
    init_snake();  //初始化蛇
    init_keyboard();  //初始化键盘
    x = 0, y = 0;     //初始化移动方向
    
    intro();          //介绍游戏规则
    char a = getch();
    fullFood();       //填充食物
    drawBoard();      //绘制游戏界面
    while(ch != 'n') {
        usleep(200000);
        if(kbhit())  //如果按下按键
        {
             ch = readch(); //读取按键值
        }
        int nx = x, ny = y;
        if (ch == 'w') nx = -1,ny = 0;  //预设移动方向
        if (ch == 's') nx = 1, ny = 0;
        if (ch == 'a') nx = 0, ny = -1;
        if (ch == 'd') nx = 0, ny = 1;
        if (ch == 'n') return 0;
        if (nx != -x || ny != -y)
            x = nx, y = ny;

        if (getFood())
        {
            score++;
            longer();
            fullFood();
        }
        else move();
        
        if (gameOver()) 
        {
            drawBoard();
            cout << "GameOver!!" << endl;
            return 0;
        }
        drawBoard();
    }
    close_keyboard();
    return 0;
}

GameOver函数

bool gameOver()
{
    head = snake.front();
    if (head.x  <= 0 || head.x > 12)
        return true;
    if (head.y <= 0 || head.y > 12)
        return true;
    if (num[head.x][head.y] == 1)
        return true;
    return false;
}

初始化键盘与关闭键盘

void init_keyboard()
{
    tcgetattr(0,&initial_settings);
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_lflag &= ~ISIG;
    new_settings.c_cc[VMIN] = 1;
    new_settings.c_cc[VTIME] = 0;
    tcsetattr(0, TCSANOW, &new_settings);
}

void close_keyboard()
{
    tcsetattr(0, TCSANOW, &initial_settings);
}

读取键盘数据

bool kbhit()
{
    char ch;
    int nread;
    if(peek_character != -1)
        return 1;
    new_settings.c_cc[VMIN]=0;
    tcsetattr(0, TCSANOW, &new_settings);
    nread = read(0,&ch,1);
    new_settings.c_cc[VMIN]=1;
    tcsetattr(0, TCSANOW, &new_settings);
    if(nread == 1) {
          peek_character = ch;
          return 1;
    }
    return 0;
}

char readch()
{
    char ch;
    if(peek_character != -1) {
        ch = peek_character;
        peek_character = -1;
        return ch;
    }
    read(0,&ch,1);
    return ch;
}

填充数据

void fullFood() // 填充数据
{
    int x[200] = {}, y[200] = {}, cur = 0;
    for (int i = 1; i <= 12; i++)
    {
        for (int j = 1; j <= 12; j++)
        {
            if (num[i][j] == 0)
            {
                cur++;
                x[cur] = i;
                y[cur] = j;
            }
        }
    }
    if (cur > 0) // 还有空位
    {
        srand(time(0));
        int cc = rand() % cur + 1; // 随机从空位中取出一个
        food.x = x[cc];
        food.y = y[cc];
    }
}

变化位置

void changeNum()
{
    if(snake.empty()) return;
    memset(num, 0, sizeof(num));
    for (auto pos = snake.begin(); pos != snake.end(); pos++)
    {
        num[(*pos).x][(*pos).y] = 1;
    }
    num[food.x][food.y] = 3;
    auto pos = snake.begin();
    num[(*pos).x][(*pos).y] = 2;
}

打印表格

void drawBoard() // 打印当前表格
{
    changeNum();
    clear();
    cout << "    ╔";
    for (int i = 1; i <= 6; i++) cout << "════";
    cout << "═╗\n";
    // 输出中间部分
    for (int i = 1; i <= 12; i++) // 行
    {
        cout << "    ║";
        for (int j = 1; j <= 12; j++) // 列
        {
            if (num[i][j] == 1)
                cout << "\033[41m  \033[0m";
            else if (num[i][j] == 2)
                cout << "\033[42m  \033[0m";
            else if (num[i][j] == 3)
                cout << "\033[43m  \033[0m";
            else
                cout << "  ";
        }
        cout << " ║" << endl;
    }
    cout << "    ╚";
    for (int i = 1; i <= 6; i++) cout << "════";
    cout << "═╝\n";

    cout << "score:" << score << endl;
}

蛇的移动

void move()
{
    clear();
    if (x == 0 && y == 0)
    {
        drawBoard();
        return;
    }
    node next = snake.front();
    next.y += y;
    next.x += x;
    snake.pop_back();
    snake.push_front(next);
}

键盘读入

int scanKeyboard()
{
    int in;
    struct termios new_settings;
    struct termios stored_settings;
    tcgetattr(0,&stored_settings);
    new_settings = stored_settings;
    new_settings.c_lflag &= (~ICANON);
    new_settings.c_cc[VTIME] = 0;
    tcgetattr(0,&stored_settings);
    new_settings.c_cc[VMIN] = 1;
    tcsetattr(0,TCSANOW,&new_settings);
    in = getchar();
    tcsetattr(0,TCSANOW,&stored_settings);
    return in;
}

定义蛇

void init_snake()
{
    head.x = 1, head.y = 1;
    snake.push_back(head);
    for (int i = 2; i <= 4; i++)
    {
        node a;
        a.x = 1, a.y = i;
        snake.push_back(a);
    }
    changeNum();
}

吃到了食物与变得更长

bool getFood()
{
    head = snake.front();
    if(num[head.x + x][head.y + y] == 3) return true;
    else return false;
}

void longer()
{
    node temp = snake.front();
    temp.x += x;
    temp.y += y;
    snake.push_front(temp);
}

游戏规则介绍

void intro()
{
    cout << "欢迎来到贪吃蛇小游戏" << endl;
    cout << "游戏规则介绍:" << endl;
    cout << "你可以使用w,a,s,d来控制贪吃蛇进行上下左右的移动"  << endl;
    cout << "在移动过程中,每吃到一个果子,你就能增加1分,同时你也会变长 1 格" << endl;
    cout << "但,如果你在移动过程中碰到了自己或者墙壁,那么你就GAMEOVER了!" << endl;
    cout << "当然,你也可以按下 n 键提前结束游戏。好了,现在按下任意键开始游戏吧!" << endl;
}

读入信息(getch)

int getch()
{
    struct termios nts, ots;
    // 得到当前终端(0表示标准输入)的设置
    if (tcgetattr(0, &ots) < 0) return EOF;
    // 设置终端为Raw原始模式,该模式下所有的输入数据以字节为单位被处理
    nts = ots;
    cfmakeraw(&nts); 
    // 设置上更改之后的设置
    if (tcsetattr(0, TCSANOW, &nts) < 0) return EOF;
    // 设置还原成老的模式
    int cr;
    cr = getchar();
    if (tcsetattr(0, TCSANOW, &ots) < 0)  return EOF;
    return cr;
}

游戏截图

在这里插入图片描述
在这里插入图片描述

结束语

不知不觉中就又写了300行代码,这个游戏好玩吗?

猜你想看

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HellowZheng

老铁,您的打赏是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值