c++贪吃蛇源代码 完整版

c++贪吃蛇源代码 完整版c++实现贪吃蛇,完整源码文章结构:数据结构分析程序运行分析难点分析一点思考源代码总结数据结构分析:1.双向队列:这里我才用双向队列的数据结构存储蛇身节点(这里的蛇身节点我才用结构体来存储蛇身信息)(因为贪吃蛇的实现还是比较简单的,所以也只涉及到了这一种数据结构)程序运行分析程序开始用户随机按下w,a,s,d中任意按键开始游戏并且作为蛇运动的初始方向,然后进入循环持…

大家好,又见面了,我是你们的朋友全栈君。

c++ 实现贪吃蛇, 完整源码

0.非常重要的注意事项

请注意:
1.这是c++代码,请建立.cpp文件而不是.c文件,然后将代码拷贝进去,再使用c++编译器进行编译运行。

2.因为使用了一些c++11标准当中的语法,所以c++编译器的编译标准至少需要设置到c++11以上,不然会报错。编译标准可以在你的IDE里设置,或者使用命令行编译时附加-std=c++11选项。

3.代码中使用了getch()函数,用于无回显的接收用户输入;使用了kbhit()函数用于判断用户是否按下键盘。但是如果你在visual studio中直接运行本代码可能会报错,你可以将上述两个函数替换为_getch()函数和_kbhit()函数就可以了。

1.数据结构分析:

这里我采用双向队列的数据结构存储蛇身节点,目的是:方便,减少屏闪。并且双向队列也能更好的体现贪吃蛇本身的特点。有利于实现,且效率也较高。

2.程序运行分析

程序开始用户随机按下w,a,s,d中任意按键开始游戏并且作为蛇运动的初始方向(如果刚开始觉得蛇的运动速度太慢可以键入’v’使变为当前运行素的1.25倍速,键入’b’则会使之变为当前速度的2/3倍速),然后进入循环持续游戏直到游戏结束,显示分数之后用户输入任意按键退出游戏。

3.难点分析

1.蛇移动怎么显示?

这也就是我采用双向队列的原因,蛇每运动一步,就从双向队列中弹出队尾,然后将新的队首(即蛇头)压入队列首部,然后再清除蛇尾打印蛇身即可,不需要对贪吃蛇全部进行清楚以及打印,可以极大的减少程序运行过程中出现的闪烁现象。如果吃到食物那么本次运动就会在将蛇尾变为蛇头的同时再加入一个蛇身达到使蛇身长度加一的目的(我认为双向队列更能从本质上体现贪吃蛇本来的特点,而每次弹出队尾,加入队首而不对中间的蛇身进行改变也使程序变得更加简洁,运行更流畅)

2.怎么控制吃到食物后蛇的速度的变化?

最开始我设置初始速度为1000(即:Sleep()函数的参数为1000)每次吃到食物就将速度乘以0.8以此达到加速的目的。但我发现到后面速度越来越快没有上限,根本无法控制。
解法:设置一个上限为MaxSpeed,则速度为 MaxSpeed + Index,MaxSpeed 保持不变且较小作为蛇速度的渐进上限,每次乘以0.8(可自定义)则乘到Index上面,这样的话速度就不会无限制的上升。

3.怎么解决屏幕闪烁?

解:不要使用system(“cls”);清屏函数,使用函数SetConsoleCursorPosition控制光标填充空格进行覆盖能大大减少屏闪问题!!这一点要注意了!

4.一些废话

1.首先肯定是存储蛇身的数据结构方面,有很多种选择:链表,双向队列,循环队列,vector甚至数组都可以用来存储蛇身。
2.最开始以为这个比较简单…上手就开始写写废了一次,提醒大家在写程序(特别是这种结构比较复杂且步骤较多的程序)时一定要先进行规划,想清楚要使用的数据结构以及构建方式,想清楚再写,避免浪费时间。

5.源代码

下面是源代码,还需要什么功能大家可以在此基础上进行改动。

#include<iostream>
#include<windows.h>
#include<conio.h>
#include<deque>
#include<ctime>
#include<stdexcept>
using namespace std;

struct Snake { 
    //蛇类结构体
    char image;
    short x, y; //坐标
};

class snakeGame { 
   
	public:
	snakeGame();
	void printMap();
	// 控制光标移动
	void gotoxy(short x, short y) { 
   
		hOut = GetStdHandle(STD_OUTPUT_HANDLE); //获取句柄
		pos = { 
   x, y};
		SetConsoleCursorPosition(hOut, pos); //移动光标
	}
	//隐藏光标
	void HideCursor()
	{ 
   
		HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
		CONSOLE_CURSOR_INFO CursorInfo;
		GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
		CursorInfo.bVisible = false; //隐藏控制台光标
		SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
	}
	// 初始化蛇身,可根据需要更改初始长度
	void initSnake() { 
   
		snake.push_front({ 
   '@', width / 2, height / 2});
		for (int i=0; i<2;++i)
			snake.push_back({ 
   '+', width/2,static_cast<short>(height/2+i+1)});
	}
	// 判断是否食物产生位置与蛇身冲突
	int WrongLocation() { 
   
		for (Snake body : snake)
			if(body.x == food_x && body.y == food_y) return 0;
		return 1;
	}
	// 产生食物,并打印
	void createFood() { 
   
		do { 
   
			food_x = rand() % (width - 4) + 2;
			food_y = rand() % (height - 2) + 1;
		} while (!WrongLocation());//处理冲突
		gotoxy(food_x,food_y); cout << '*' << endl; //打印食物
	}
	void printSnake();
	// 清除蛇尾
	inline void clearSnake(Snake &tail) { 
   
    	gotoxy(tail.x, tail.y); cout << ' '; //覆盖蛇尾,不使用清屏函数,避免了闪烁
	}
	void judgeCrash();
	void foodEaten();
	// 监控用户键盘输入
	void userInput() { 
   
		char ch;
		switch(ch=getch()) { 
   
			case 'w':if (dir != 's') dir = ch;break;
			case 'a':if (dir != 'd') dir = ch;break;
			case 's':if (dir != 'w') dir = ch;break;
			case 'd':if (dir != 'a') dir = ch;break;
			case 'v':speed*=0.8;break; case 'b':speed*=1.5;break;
			case ' ':gotoxy(width / 2, height); cout << "游戏已暂停,任意键继续"; getch();
            gotoxy(width / 2, height); cout << " "; break;
			default:break;
		}
	}
	private:
	// 以下是程序运行当中需要用到的一些中间变量或者是数据变量。
	enum MapSize { 
   height = 40,width = 120}; //地图尺寸
	HANDLE hOut; COORD pos;
	char dir; //direction
	bool beg,eatFood=false;
	double speed=200;
	deque<Snake> snake;
	int food_x,food_y;
	int score=0;
};
// 处理吃到食物的情况
void snakeGame::foodEaten() { 
   
	createFood();
	eatFood=true;
	speed*=.8;
	++score;
}
// 判断蛇是否撞墙或者吃到自己的尾巴
void snakeGame::judgeCrash() { 
   
	int flag=0;
	if (snake.size()>=5) { 
   
		deque<Snake>::iterator iter = snake.begin() + 1;
		int x = (iter-1)->x, y = (iter-1)->y;
		for (; iter != snake.end(); ++iter) { 
   
			if (iter->x == x && iter->y == y) flag=1;
		}}
	if (flag || snake.front().x == 1 || snake.front().x == width - 2 || snake.front().y == 0 || snake.front().y == height - 1)//检测是否撞墙或者是否吃到自身
    { 
   
        gotoxy(width / 2 - 10, height /2);
        cout << "游戏结束!您的分数是: " << score << "分(回车继续)"<<endl;
        while(1) { 
   
            dir = getch();
            if (dir == '\r') break;}
		runtime_error quit("游戏结束,正常退出"); throw quit;
    }
}
// 将蛇身打印出来
void snakeGame::printSnake() { 
   
    deque<Snake>::const_iterator iter = snake.begin();
    for (; iter <= snake.begin() + 1 && iter < snake.end(); ++iter) { 
   
        gotoxy(iter->x, iter->y); cout << iter->image;
    }
}
// 打印出边框
void snakeGame::printMap() { 
   
	int i;
    for (i = 0; i != width; i += 2) cout << "■"; //这个图案宽度占2,高度占1
    gotoxy(0, 1);
    for (i = 1; i != height; ++i) cout << "■" << endl;
    for (i = 1; i != height; ++i) { 
   
        gotoxy(width - 2, i); cout << "■";}
    gotoxy(0, height - 1);
    for (i = 0; i != width; i += 2) cout << "■";
    cout << "贪吃蛇:1.方向键开始游戏 2.*代表食物 3.空格键暂停游戏\n 4.键入'v'加速 5.键入'b'减速";
}
// 类的构造函数。
// 包含了程序的初始化(地图绘制,蛇身初始化),程序运行,程序结束等内容
// 是程序最关键的部分
snakeGame::snakeGame() { 
   
	HideCursor(); // 隐藏光标
	srand(static_cast<unsigned int>(time(NULL)));
	beg=true;
	Snake tmp1,tmp2;
	while (1) { 
   
		if(beg) { 
    // 判断是不是第一次运行程序,因为第一次运行需要打印边框
			printMap();
			dir = getch();
			initSnake();
			createFood();
			beg = eatFood=false;
		}
		tmp2=snake.back();
		tmp1=snake.front();
		snake.pop_back();
		if (eatFood) { 
    // 如果吃到食物...
			tmp2.image='+';
			snake.push_back(tmp2);
			eatFood=false;
		}
		else clearSnake(tmp2);
		// 判断当前的前进方向,根据dir来进行移动
		if      (dir == 's') ++tmp1.y;
        else if (dir == 'a') --tmp1.x;
        else if (dir == 'd') ++tmp1.x;
        else 				 --tmp1.y;
		try{ 
   
			judgeCrash(); // 判断是否撞墙或者吃到自己
		}
		catch(runtime_error &quitSignal) { 
   
			throw quitSignal;
		}
		snake.front().image='+';
		snake.push_front(tmp1);
		printSnake();
		Sleep(speed+30);
		if (tmp1.x == food_x && tmp1.y == food_y) 
			foodEaten();
		// 监测用户的键入
		if(kbhit()) userInput();
	}
}
int main() { 
   
	// 设置小黑框的一些参数
	system("mode con cols=120 lines=42");
	try{ 
   
		snakeGame game;
	}
	catch(runtime_error &gameEnd) { 
   
		system("cls");
		cout<<gameEnd.what();
		getch();
	}
}

6.运行效果展示

将边界改成方块后的运行截图

7.总结

网上真正能用的贪吃蛇源代码还是很少的,就算找到了不是要收费下载就是复制过来一大堆报错或者bug运行不了,所以本着帮助他人的想法自己写了一个版本的。写得不是很好,有不足之处欢迎大家批评指正。
有任何问题可以留在评论区,力所能及可以给予帮助。
peace~

如果代码有报错可以去看看开头的重要注意事项喔~

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141138.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • jQuery

    jQuery前言什么是jQueryjQuery的作用(为什么要用jQuery)jQuery的导入和使用导入jQuery文件:使用jQuery:jQuery下载下载链接:https://j

  • springboot详细讲解_Springboot框架

    springboot详细讲解_Springboot框架一、SpringApplication的几种常用方式二、定制启动Banner三、SpringBoot事件和监听器四、SpringBoot的Web环境信息五、SpringBoot的ApplicationRunner接口和CommandLineRunner接口SpringBoot版本:1.5.13.RELEASE对应官方文档链接:https://docs.s…

  • jmeter并发测试教程_jmeter高并发测试

    jmeter并发测试教程_jmeter高并发测试下载JMEter这里介绍JMEter的简单并发测试下载安装完成后打开bin\jmeter.bat,必须先安装java环境,打开软件后找到Options>chooseLangguage>Chinese,先把软件的语言改为中文,英文好的可以忽略创建一个监听器用于查看运行结果设置要请求的接口或者api请求的设置设置线程组,并发数这是一个…

  • 卡盟网站怎么做_卡盟的货源哪里来

    卡盟网站怎么做_卡盟的货源哪里来服务器系统:cenos7.x64位(购买vps都知道ba?安装7.x以上系统)宝塔安装命令:bt.cn(自行获取)(baota我已经安装好了,接下来给大家演示如何操作搭建卡信乐)ssh输入宝塔命令会自动安装好自己查看一下登陆地址和账号密码就可以登陆面板后安装apache2.4+mysql5.5+php5.6phpadmin4.7(应该都会安装把!)登陆宝塔,打开网站的根目录的home文件夹,上传源码然后解压上传好后解压文件修改vhost文件里的域名创建一个数据库yunos数据库

  • linux mail发送邮件_shell传输文件

    linux mail发送邮件_shell传输文件Linux发邮件之mail命令详解发布于2017-01-0516:44:04|154次阅读|评论:0|来源:网友投递LinuxLinux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。这篇文章主要介绍了Linux发邮件之mail命令详解,详细的讲解…

    2022年10月20日
  • pycharm 2021.11.3激活码【2021最新】

    (pycharm 2021.11.3激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html6B1QWJC8H5-eyJsa…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号