贪吃蛇游戏的实现:C++ 控制台版

news2024/11/18 21:52:44

功能概述

  • 控制蛇的移动:使用WASD键控制蛇的移动方向。
  • 随机生成食物:蛇吃到食物后,食物会在游戏区域内随机生成。
  • 显示分数:游戏中会显示当前分数。
  • 游戏结束条件:当蛇碰到自己或走出边界时,游戏结束并显示“游戏失败”消息。
  • 清屏防止闪屏:使用光标控制函数

代码解释

游戏初始化 (Setup 函数)

  • dir = STOP;: 初始化蛇的移动方向为停止状态。
  • snake.clear();: 清空蛇的身体。
  • snake.push_back({ WIDTH / 2, HEIGHT / 2 });: 将蛇的头部放置在游戏区域的中心。
  • score = 0;: 重置分数。
  • food = { rand() % WIDTH, rand() % HEIGHT };: 随机生成食物的位置。
  • gameOver = false;: 游戏状态设置为“未结束”。

绘制游戏界面 (Draw 函数)

  • system("cls");: 清除控制台屏幕。
  • for (int i = 0; i < WIDTH + 2; i++) cout << "#";: 绘制游戏区域的边框。
  • for (int y = 0; y < HEIGHT; y++) { ... }: 绘制游戏区域的每一行。
  • if (x == food.x && y == food.y) cout << "F";: 在食物位置绘制F
  • if (x == 0) cout << "#";: 绘制左边框。
  • if (x == WIDTH - 1) cout << "#";: 绘制右边框。
  • if (gameOver) { ... }: 如果游戏结束,显示游戏结束消息。

处理用户输入 (Input 函数)

  • if (_kbhit()) { char c = _getch(); ... }: 检测并读取用户的键盘输入。
  • case 'a':: 处理向左移动。
  • case 'd':: 处理向右移动。
  • case 'w':: 处理向上移动。
  • case 's':: 处理向下移动。
  • case 'x':: 处理退出游戏。

更新游戏逻辑 (Logic 函数)

  • Point prev = snake[0];: 保存蛇头的当前坐标。
  • snake[0].x += (dir == RIGHT) - (dir == LEFT);: 根据当前方向更新蛇头的x坐标。
  • snake[0].y += (dir == DOWN) - (dir == UP);: 根据当前方向更新蛇头的y坐标。
  • if (snake[0].x >= WIDTH || snake[0].x < 0 || snake[0].y >= HEIGHT || snake[0].y < 0): 检查蛇是否走出边界。
  • if (snake[0].x == food.x && snake[0].y == food.y): 检查蛇是否吃到食物。
  • for (int i = 1; i < snake.size(); i++): 检查蛇是否碰到自己。
  • for (int i = 1; i < snake.size(); i++) { prev2 = snake[i]; snake[i] = prev; prev = prev2; }: 移动蛇的身体。

清屏防止闪屏

原理: 通过控制光标的位置来实现清屏和更新内容,而不是使用 system("cls") 这样的全屏清除方法。

实现:

  • 使用 gotoxy(int x, int y) 函数移动光标到指定位置。
  • 在每次更新屏幕时,先将光标移动到屏幕的起始位置 (0, 0) 清除内容,然后绘制新的内容。

优点: 避免了整个屏幕的清除和重绘,减少了闪烁。

效果图

源代码

编译时在连接器命令行加入以下命令

-std=c++11

 

#include <iostream>
#include <conio.h> // 用于 _getch() 读取键盘输入
#include <windows.h> // 用于 Sleep() 暂停游戏
#include <vector>
#include <ctime>
#include <cstdlib>

using namespace std;

// 定义游戏常量
const int WIDTH = 15;  // 游戏区域的宽度
const int HEIGHT = 15; // 游戏区域的高度
int score = 0;         // 玩家得分
bool gameOver = false; // 游戏是否结束的标志

// 定义方向控制的枚举
enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN };
Direction dir; // 当前蛇的移动方向

// 表示二维空间中的一个点
struct Point {
    int x, y;
};

// 存储蛇的身体段的向量
vector<Point> snake;
Point food; // 当前食物的位置

// 函数声明
void Setup();
void Draw();
void Input();
void Logic();
void gotoxy(int x, int y); // 函数声明:移动光标到指定位置

// 初始化游戏状态的函数
void Setup() {
    dir = STOP; // 设置蛇的初始移动方向为停止
    snake.clear(); // 清空蛇的身体
    snake.push_back({ WIDTH / 2, HEIGHT / 2 }); // 将蛇的头部放置在游戏区域的中心
    score = 0; // 重置分数
    food = { rand() % WIDTH, rand() % HEIGHT }; // 随机生成食物的位置
    gameOver = false; // 游戏状态设置为“未结束”
}

// 移动光标到指定位置
void gotoxy(int x, int y) {
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备的句柄
    COORD pos = { static_cast<SHORT>(x), static_cast<SHORT>(y) }; // 设置光标位置
    SetConsoleCursorPosition(handle, pos); // 移动光标
}

// 绘制游戏界面的函数
void Draw() {
    gotoxy(0, 0); // 移动光标到控制台的左上角

    // 绘制游戏区域的上边框
    for (int i = 0; i < WIDTH + 2; i++)
        cout << "#";
    cout << endl;

    // 绘制游戏区域的每一行
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            if (x == 0)
                cout << "#"; // 绘制左边框

            if (x == food.x && y == food.y)
                cout << "F"; // 绘制食物
            else {
                bool print = false;
                // 检查当前坐标是否被蛇的身体占据
                for (auto s : snake) {
                    if (s.x == x && s.y == y) {
                        cout << "O"; // 绘制蛇的身体段
                        print = true;
                    }
                }
                if (!print)
                    cout << " "; // 空白区域
            }

            if (x == WIDTH - 1)
                cout << "#"; // 绘制右边框
        }
        cout << endl;
    }

    // 绘制游戏区域的下边框
    for (int i = 0; i < WIDTH + 2; i++)
        cout << "#";
    cout << endl;

    // 显示当前得分
    cout << "Score: " << score << endl;

    // 如果游戏结束,显示“游戏结束”消息
    if (gameOver) {
        cout << "Game Over! Press any key to exit..." << endl;
    }
}

// 处理用户输入的函数
void Input() {
    if (_kbhit()) { // 检测是否有键盘输入
        char c = _getch(); // 获取按下的键
        switch (c) {
        case 'a': // 向左移动
            if (dir != RIGHT) // 确保蛇不会反向移动
                dir = LEFT;
            break;
        case 'd': // 向右移动
            if (dir != LEFT)
                dir = RIGHT;
            break;
        case 'w': // 向上移动
            if (dir != DOWN)
                dir = UP;
            break;
        case 's': // 向下移动
            if (dir != UP)
                dir = DOWN;
            break;
        case 'x': // 退出游戏
            gameOver = true;
            break;
        }
    }
}

// 更新游戏逻辑的函数
void Logic() {
    if (gameOver) return; // 如果游戏结束,跳过逻辑更新

    // 更新蛇头的位置
    Point prev = snake[0];
    Point prev2;
    snake[0].x += (dir == RIGHT) - (dir == LEFT); // 根据方向更新蛇头的x坐标
    snake[0].y += (dir == DOWN) - (dir == UP); // 根据方向更新蛇头的y坐标

    // 检查蛇是否超出边界
    if (snake[0].x >= WIDTH || snake[0].x < 0 || snake[0].y >= HEIGHT || snake[0].y < 0) {
        gameOver = true; // 游戏结束
    }

    // 检查蛇是否碰到自己
    for (int i = 1; i < snake.size(); i++) {
        if (snake[i].x == snake[0].x && snake[i].y == snake[0].y) {
            gameOver = true; // 游戏结束
        }
    }

    // 检查蛇是否吃到食物
    if (snake[0].x == food.x && snake[0].y == food.y) {
        score++; // 增加分数
        food = { rand() % WIDTH, rand() % HEIGHT }; // 生成新的食物位置
        snake.push_back(prev); // 将新的一节添加到蛇的身体
    }

    // 移动蛇的身体
    for (int i = 1; i < snake.size(); i++) {
        prev2 = snake[i];
        snake[i] = prev;
        prev = prev2;
    }
}

// 主函数
int main() {
    srand(static_cast<unsigned>(time(0))); // 用当前时间作为随机数生成的种子
    Setup(); // 初始化游戏

    while (!gameOver) { // 游戏循环
        Draw(); // 绘制游戏界面
        Input(); // 处理用户输入
        Logic(); // 更新游戏逻辑
        Sleep(100); // 暂停100毫秒
    }

    Draw(); // 绘制结束界面显示“游戏结束”
    _getch(); // 等待用户输入后退出程序
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991313.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从巴黎到乐清,奥运精神引领全民健身新风尚!

16位火炬手接力&#xff0c;乐清点燃全民健身新篇章&#xff01; 作者&#xff1a;华夏之音总监&#xff0f;李望 在巴黎奥运会如火如荼进行的第11天&#xff0c;中国体育代表团以22枚金牌的骄人战绩领跑金牌榜&#xff0c;每一枚金牌都闪耀着中华体育精神的璀璨光芒&#xff…

c++ 连接mysql

其实就是MYsql c语言的API #define _CRT_SECURE_NO_WARNINGS 1 #define HOST "192.168.226.1" #define USER "root" #define PASSWORD "123456" #define PORT 3066#include <iostream> #include <stdlib.h> #include <mysql.…

【北斗授时服务】NTP网络时间服务器 安徽京准智造

【北斗授时服务】NTP网络时间服务器 安徽京准智造 【北斗授时服务】NTP网络时间服务器 安徽京准智造 一、NTP网络时间服务器产品介绍&#xff1a; NTP网络时间服务器是针对计算机、自动化装置等进行校时而研发的高科技设备&#xff0c;该产品可从GPS卫星&#xff08;北斗卫星、…

数据采集工具之Canal

本文主要介绍canal采集mysql数据的tcp、datahub(kafka)模式如何实现 1、下载canal https://aliyun-datahub.oss-cn-hangzhou.aliyuncs.com/tools/canal.deployer-1.1.5-SNAPSHOT.tar.gz 2、TCP模式的实现 a、canal.properties 打开看看即可&#xff0c;不需要调整 ######…

蚁群求解旅行商问题(TSP)的MATLAB例程

程序概况 输入需要经过的节点坐标&#xff1a; 运行程序后&#xff0c;即可得到&#xff1a; 运行结果 左图为遍历各点的运动轨迹&#xff0c;最终会回到起点右图为平均距离&#xff08;红线&#xff09;和最短距离在迭代时的变化情况 源代码 代码下载链接如下&#xff1a…

【工具类】JAVA (Android Studio )+ JS 加密解密 AES + Base 64

JAVA &#xff08;Android Studio &#xff09; JS 加密解密 AES Base 64 前言JAVA 代码&#xff08;解密&#xff09;JS代码&#xff08;加密&#xff09; 前言 整个过程&#xff1a; JS 接口先用AES加密&#xff0c;然后加密内容转Base64 编码&#xff1b;JAVA进行Base64解…

虹科干货 | 如何确保干冰运输的安全和稳定?

在上篇文章中&#xff0c;我们介绍了液氮罐运输和存储温度监测解决方案&#xff0c;本文我们将会了解医药供应链中干冰运输和温度监测的关键要点。 干冰在医药行业的应用 干冰是固体二氧化碳&#xff0c;当表面温度为 -78.5℃时&#xff0c;一块冷冻的干冰会直接转变为气体&am…

Ubuntu-18.04.1安装JetBrains PyCharm 2018.1.6 专业版(永久破解方法)

软件安装包下载地址&#xff1a;Other Versions - PyCharm 将安装包放置Ubuntu系统中解压&#xff0c;到bin目录下找到pycharm.sh即可打开。 补丁破解方式&#xff08;需关闭软件pycharm&#xff0c;否则会打不开pycharm&#xff01;&#xff01;&#xff01;&#xff09;&am…

昂科烧录器支持MindMotion灵动微电子的32位微控制器MM32F5287L9P

芯片烧录行业领导者-昂科技术近日发布最新的烧录软件更新及新增支持的芯片型号列表&#xff0c;其中MindMotion灵动微电子的32位微控制器MM32F5287L9P已经被昂科的通用烧录平台AP8000所支持。 MM32F5287L9P搭载Armv8-M 架构“星辰”STAR-MC1处理器&#xff0c;最高工作频率可达…

CSS技巧专栏:一日一例 20-纯CSS实现点击会凹陷的按钮

本例图片 案例分析 其实这个按钮非常的简单啊&#xff0c;主要就是利用了box-shadow的inset。 布局代码 <button class"base">凹下的按钮</button> 基础样式 :root{--main-bg-color: #dcdcdc; /* 将页面背景色调整为浅灰色 */--color:#000;--hover-…

Cesium手动建模模型用Cesiumlab转3D Tiles模型位置不对,调整模型位置至指定经纬度

Cesium加载3Dtiles模型的平移和旋转_3dtiles先旋转再平移示例-CSDN博客 Cesium 平移cesiumlab生产的3Dtiles切片模型到目标经纬度-CSDN博客 【ArcGISCityEngine】自行制作Lod1城市大尺度白膜数据_cityengine 生成指定坐标集指定区域的白模-CSDN博客 以上次ArcGISCityEngine制…

IEEE Transactions on Intelligent Transportation Systems投稿指南

投稿记录 submitted 2024-5-29 Awaiting AE Assignment 2024-6-11 Under review 2024-6-15 Awaiting EIC Decision 2024-6-24 感觉要拒稿的节奏 Resubmit To Another Journal 2024-6-25 与期刊不符合 下载模板 IEEE Transactions on Intelligent Transportation Syste…

java.lang.NoClassDefFoundError: ch/qos/logback/core/util/StatusPrinter2

1、问题 SpringBoot升级报错&#xff1a; Exception in thread "main" java.lang.NoClassDefFoundError: ch/qos/logback/core/util/StatusPrinter2 类找不到&#xff1a; Caused by: java.lang.ClassNotFoundException: ch.qos.logback.core.util.StatusPrinter22、…

【Vue3】Pinia $subscribe

【Vue3】Pinia $subscribe 背景简介开发环境开发步骤及源码 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子…

前端框架(三件套)

学习网站 HTML 系列教程&#xff08;有广告&#xff09; HTML&#xff08;超文本标记语言&#xff09; | MDN (mozilla.org)&#xff08;英文不太友好&#xff09; 1.HTML5 & CSS3 1.1HTML5表格 <!DOCTYPE html> <html lang"en"> <head>…

常见框架漏洞详解②!!

中间件 中间件&#xff08;英语&#xff1a;Middleware&#xff09;是提供系统软件和应⽤软件之间连接的软件&#xff0c;以便于软件各部 件之间的沟通。 中间件处在操作系统和更⾼⼀级应⽤程序之间。他充当的功能是&#xff1a;将应⽤程序运⾏环境与操作系统隔离&#xff0c;…

setState执行机制

当this.setState()被调用时&#xff0c;React会重新调用render方法来重新绘制UI 异步更新 setState通过一个队列机制实现state的更新当执行setState时&#xff0c;会将需要更新的state合并后放入状态队列&#xff0c;而不是立刻更新队列机制可以高效的批量更新state&#xff…

武汉流星汇聚:亚马逊跨境电商蓝海中的领航者,共绘商业新蓝图

在全球化日益加深的今天&#xff0c;跨境电商已成为连接世界市场的桥梁&#xff0c;为企业提供了前所未有的发展机遇。在这片充满机遇的蓝海中&#xff0c;武汉流星汇聚电子商务有限公司凭借其深厚的行业底蕴、卓越的用户体验以及“以客户为中心”的坚定理念&#xff0c;在亚马…

嵌入式学习day12(LinuxC高级)

由于C高级部分比较零碎&#xff0c;各部分之间没有联系&#xff0c;所以学起来比较累&#xff0c;多练习就好了 一丶Linux起源 寻科普|第二期:聊聊Linux的前世今生 UNIX和linux的区别&#xff1a; &#xff08;1&#xff09;linux是开发源代码的自由软件&#xff0e;而unix是…

前端模块化-探究webpack loader的原理以及实现常见的loader

前言 本节主要介绍这些插件的基本原理并手写一些常用的 Loader。 本节对应的 demo 可以在这里找到。 什么是 Loader 在 Webpack 中&#xff0c;Loader 是用于对模块的源代码进行转换的工具。Webpack 将一切视为模块&#xff0c;而这些模块可能是各种类型的文件&#xff0c;如…