本代码参考另一位博主的贪吃蛇的思想。单双人贪吃蛇模式。
编译已通过的平台:VS2019。
如有问题,请伙伴们一起讨论哟。
1. 程序界面功能以及运行截图如下:
(1)程序主界面运行截图:
(2)单人游戏模式截图:
(3)双人游戏模式截图:
2. 系统代码组成部分
(1)DoubleSnake.h文件
// 此处为该程序所需的所有全局变量等。
bool Exit_cons = false;//退出判断值
bool Game_over = false;//游戏结束判定值
bool is_eat = true;//判断食物是否被吃。
char choose; //选择游戏模式
int length = 0; //length用来记录蛇1的长度
int length_ = 0;//length_用来记录蛇2的长度
int face_to = 1; //face_to用来标志蛇1方向
int face_ = 1; //face_用来标记蛇2方向
int respon_time = 0; //respon_time用来记录蛇1的响应时间
int respon_ = 0;//用来记录蛇2的响应时间
int hit_win = 0;//用来记录蛇1与蛇2的相撞情况,如果蛇1撞蛇2,则hit_win=2;蛇2获胜,如果蛇2撞蛇1,则hit_win=1,蛇1获胜。
COORD food, tail, snakebody[100], node;//定义食物、尾部坐标、以及蛇的身体坐标 x,y。
COORD tail_, snakebody_[100], node_;
int score = 0;//记录蛇1的得分。
int score_ = 0;// 记录蛇2的得分。
int W = 50;
int L = 30;
(2)贪吃蛇.cpp :
此文件包含 “main” 函数。程序执行将在此处开始并结束。
#include <windows.h>
#include
#include <conio.h>
#include<time.h>
#include
#include"DoubleSnake.h"
using namespace std;
void menu();
void Color(int color);
void Goto_mark(SHORT x, SHORT y);
void Draw_map();
class Snake1 {
public:
Snake1() {
snakebody[0].X = 11;//初始化一条方向向上、长度为2的蛇。
snakebody[0].Y = 11;
snakebody[1].X = 11;
snakebody[1].Y = 12;
tail.X = 11;
tail.Y = 13;
length = 2;
respon_time = 250;
}
~Snake1() {
}
void Game_instruction() { //通过传入的数据来记录游戏提示信息,
Color(15|0);
Goto_mark(54, 3);
cout << "\t游戏操作简介:" << endl;
Goto_mark(54, 5);
cout << "\t1.向左移动: A" << endl;
Goto_mark(54, 6);
cout << "\t2.向右移动:D" << endl;
Goto_mark(54, 7);
cout << "\t3.向下移动: S" << endl;
Goto_mark(54, 8);
cout << "\t4.向上移动: W" << endl;
Goto_mark(56, 10);
cout << "当前长度:" << length << endl;
Goto_mark(56, 11);
cout << "当前时间:" << respon_time << endl;
Goto_mark(56, 12);
cout << "目前得分为:" << score << endl;
}
void changespeed() {//蛇两个食物速度加201
if (score % 2 == 0)
{
respon_time -= 20;
}
}
void Score(int a) { //计算游戏得分
system("color f0");
cout << " 你最终的总得分为: " << score << endl;
if (a < 5 && a >= 0)
a = 0;
else if (a >= 5 && a < 10)
a = 1;
else if (a >= 10 && a <= 20)
a = 2;
else
a = 3;
switch (a) {
case 0:
cout << " 加油哦!下次再接再厉!\n";
break;
case 1:
cout << " 还不错,再接再厉!\n";
break;
case 2:
cout << " 加油,你很棒,但可以做得更好\n";
break;
case 3:
cout << " 你已经很厉害啦!祝你好运哦\n";
break;
}
}
};
//Snake1类设计结束,因为当时课程要求原因(需要用到继承),博主强行编出了一个Snake2类,读者可自行更改。
class Snake2 : public Snake1 { //继承Snake1
public:
Snake2() {
snakebody_[0].X = 22; //初始化一条方向向上、长度为2的蛇。
snakebody_[0].Y = 11;
snakebody_[1].X = 22;
snakebody_[1].Y = 12;
tail_.X = 22;
tail_.Y = 13;
length_ = 2;
respon_ = 250;
}
~Snake2() {
}
void Game_instruction() { //通过传入的数据来记录游戏提示信息,
Color(15 | 0);
Goto_mark(54, 15);
cout << "\t游戏操作简介:" << endl;
Goto_mark(54, 17);
cout << "\t1.向左移动: ←" << endl;
Goto_mark(54, 18);
cout << "\t2.向右移动:→" << endl;
Goto_mark(54, 19);
cout << "\t3.向下移动: ↓" << endl;
Goto_mark(54, 20);
cout << "\t4.向上移动: ↑" << endl;
Goto_mark(56, 22);
cout << "当前长度:" << length_ << endl;
Goto_mark(56, 23);
cout << "当前响应时间:" << respon_ << endl;
Goto_mark(56, 24);
cout << "目前得分为:" << score_ << endl;
}
void Compare_score( int c) { //将蛇1与蛇2得分对比,决出胜利者。增加一个变量c,用来记录相撞情况。
system("color f0");
if (c == 1) {
cout << " 蛇2撞了蛇1,蛇1获胜" << endl;
}
else if (c == 2) {
cout << " 蛇1撞了蛇2,蛇2直接获胜" << endl;
}
else if (c == 3)
{
cout << " 蛇2撞了自身,默认判定蛇1胜利" << endl;
}
else if (c == 4)
{
cout << " 蛇1撞了自身,默认判定蛇2胜利" << endl;
}
}
void Compare_score(int a, int b,int c) { // 用了一个重载函数,用来判断当c=0时,说明蛇是撞墙而死,因此根据游戏规则比较游戏得分。
system("color f0");
if (c == 0)
{
if (a > b) {
cout << " 蛇1的分数: " << score << " 大于 蛇2的分数:" << score_ << endl;
cout << " 蛇1胜利" << endl;
}
else if (a == b) {
cout << " 蛇1的分数: " << score << " 等于 蛇2的分数:" << score_ << endl;
cout << " 蛇1与蛇2平局" << endl;
}
else {
cout << " 蛇1的分数: " << score << " 小于 蛇2的分数:" << score_ << endl;
cout << " 蛇2胜利" << endl;
}
}
}
};
Snake1* S; //在switch语句外初始化,以免在case语句内定义而报错。同时在vs中局部指针变量未初始化会报错。
Snake2 S2;
void Color(int color) //控制界面字体颜色函数
{
HANDLE hCon = GetStdHandle((STD_OUTPUT_HANDLE)); //获取“标准输出设备的句柄”会把字符输出到屏幕上,用的就是这个句柄。
SetConsoleTextAttribute(hCon, color); //SetConsoleTextAttribute是API设置字体颜色和背景色的函数,
}
void Init_console() { // 初始化该控制台
HANDLE hCon = GetStdHandle((STD_OUTPUT_HANDLE));//获取“标准输出设备的句柄”会把字符输出到屏幕上,用的就是这个句柄。
CONSOLE_CURSOR_INFO _guan_biao = { 1, false }; //设置光标厚度大小,隐藏光标
SetConsoleCursorInfo(hCon, &_guan_biao);
}
void Draw_map() { // 绘制游戏的边框。
for (int i = 0; i < W; i++) {
Color(11);
cout << "◆";
}
cout << endl;
for (int i = 0; i < L - 2; i++)
{
for (int j = 0; j < W; j++) {
if (j == 0) {
Color(11);
cout << "◆";
continue;
}
else if (2 * j == W - 2) {
Color(11);
cout << "◆";
}
else {
cout << " ";
}
}
cout << endl;
}
for (int i = 0; i < W; i++) {
Color(11);
cout << "◆";
}
}
// x轴502;y轴24 界面·设置为到242的x的那一列、30的y的那一行。
void Goto_mark(SHORT x, SHORT y) { //这个函数用于光标控制。
HANDLE hCon = GetStdHandle((STD_OUTPUT_HANDLE));
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(hCon, coord);
}
//菜单函数
void menu() {
ofstream ofs;
ofs.open("A:\\a.txt", ios::out);
if (!ofs) {
cout << "a.txt文件打开失败!" << endl;
cout << "请重新开始!";
system("pause");
exit(0);
}
switch (choose) {
case '1':
system("cls");
Init_console();
Draw_map();
S->Game_instruction();
while (1) {
Goto_mark(0, 0);
Color(11); //浅蓝色
cout << "◆";
Sleep(respon_time); //给定响应时间
if (is_eat == true) {
is_eat = false;
srand(unsigned(time(NULL)));
food.X = rand() % 22 + 1;
food.Y = rand() % 28 + 1;
for (int i = 0; i < length; i++) {
if (food.X * 2 == snakebody[i].X * 2 && food.Y == snakebody[i].Y) //判断随机生成的食物是否和蛇的身体重叠。
{
is_eat = true;
}
}
}
if (is_eat == true)
continue; //如果生成食物的坐标冲突的话,直接进入下一循环,重新随机生成食物。
Goto_mark(food.X * 2, food.Y); //定位食物光标位置,同时在控制台界面生成食物样式
Color(12); //浅红色
cout << "★";
for (int i = 0; i < length; i++) {
if (snakebody[0].X == snakebody[i].X && snakebody[0].Y == snakebody[i].Y && i != 0) { //判断蛇头蛇身是否相撞
system("cls");
system("color f0");
cout << " 你撞到了自身,已死亡,请重新开始" << endl;
ofs << "你的最终得分为:" << " " << score<<" "<<"蛇的最终长度为: "<<length << endl;
ofs << "死亡原因为: 蛇撞到了自己的身体" << endl;
ofs.close();
Game_over = true; //游戏结束;
break;
}
Goto_mark(snakebody[i].X * 2, snakebody[i].Y);
Color(10); //浅绿色
cout << "●";
}
if (Game_over == true) {
break;
}
Goto_mark(tail.X * 2, tail.Y); //
cout << " ";
S->Game_instruction(); //用于改变输出的长度以及得到的分数。
if (snakebody[0].X * 2 == food.X * 2 && snakebody[0].Y == food.Y) { //蛇吃到食物
score++;
is_eat = true;
length++;
S->changespeed();
continue;
}
if (_kbhit()) { // _kbhit() 在执行时,检测是否有按键按下,有按下返回键值,没有按下返回0; 是非阻塞函数
char c;
c = _getch();//接受来自控制台的输入信息。
//控制方向
if ((c == 'w' || c == 'W') && face_to != 2) { //防止相反方向上的冲突。
face_to = 1;
}
if ((c == 's' || c == 'S') && face_to != 1) {
face_to = 2;
}
if ((c == 'a' || c == 'A') && face_to != 4) {
face_to = 3;
}
if ((c == 'd' || c == 'D') && face_to != 3) {
face_to = 4;
}
}
//设置方向,通过增减键盘的值来后续控制蛇的移动
if (face_to == 1) {
node.X = snakebody[0].X;
node.Y = snakebody[0].Y - 1;
}
if (face_to == 2) {
node.X = snakebody[0].X;
node.Y = snakebody[0].Y + 1;
}
if (face_to == 3) {
node.X = snakebody[0].X - 1;
node.Y = snakebody[0].Y;
}
if (face_to == 4) {
node.X = snakebody[0].X + 1;
node.Y = snakebody[0].Y;
}
//判断是否碰撞边界。
if (snakebody[0].X >= 23) {
system("cls");
system("color f0");
cout << " 蛇撞到了右边墙体" << endl;
ofs << "你的最终得分为:" << " " << score << " " << "蛇的最终长度为:" << length << endl;
ofs << "死亡原因为: 蛇撞到了右边墙体" << endl;
ofs.close();
putchar(7); //输出警报声
break;
}
if (snakebody[0].X <= 0) {
system("cls");
system("color f0");
cout << " 蛇撞到了左边墙体" << endl;
ofs << "你的最终得分为:" << " " << score << " " << "蛇的最终长度为:" << length << endl;
ofs << "死亡原因为: 蛇撞到了左边墙体" << endl;
ofs.close();
putchar(7); //输出警报声
break;
}
if (snakebody[0].Y >= 29) {
system("cls");
system("color f0");
cout << " 蛇撞到了下边墙体" << endl;
ofs << "你的最终得分为:" << " " << score << " " << "蛇的最终长度为:" << length << endl;
ofs << "死亡原因为: 蛇撞到了下边墙体" << endl;
ofs.close();
putchar(7); //输出警报声
break;
}
if (snakebody[0].Y <= 0) {
system("cls");
system("color f0");
cout << " 蛇撞到了上边墙体" << endl;
ofs << "你的最终得分为:" << " " << score << " " << "蛇的最终长度为:" << length << endl;
ofs << "死亡原因为: 蛇撞到了上边墙体" << endl;
ofs.close();
putchar(7); //输出警报声
break;
}
//通过将前一次的蛇的各个部位的坐标与当前应该是的坐标互换,达到坐标正确改变的地步。
for (int i = 0; i < length; i++) {
swap(node.X, snakebody[i].X); //交换前后两次的蛇身坐标
swap(node.Y, snakebody[i].Y);
}
tail.X = node.X;
tail.Y = node.Y;
}
S->Score(score);
cout << endl;
break;
case '2':
system("cls");
Init_console();
Draw_map();
S2.Snake1::Game_instruction(); //调用来自基类Snake1的Game_instruction()
S2.Game_instruction();
while (1) {
Goto_mark(0, 0);
Color(11); // 浅蓝色
cout << "◆";
Sleep(respon_time);
if (is_eat == true) {
is_eat = false;
srand(unsigned(time(NULL)));
food.X = rand() % 22 + 1;
food.Y = rand() % 28 + 1;
for (int x = 0; x < length_; x++) {
for (int i = 0; i < length; i++) {
if (food.X * 2 == snakebody[i].X * 2 && food.Y == snakebody[i].Y || (food.X * 2 == snakebody_[x].X * 2 && food.Y == snakebody_[x].Y)) //判断随机生成的食物是否和蛇的身体重叠。
{
is_eat = true;
}
}
}
}
if (is_eat == true)
continue; //如果生成食物的坐标冲突的话,直接进入下一循环,重新随机生成食物。
Goto_mark(food.X * 2, food.Y);
Color(12); //浅红色
cout << "★";
for (int x = 0; x < length_; x++) {
for (int i = 0; i < length; i++) {
if (snakebody[0].X == snakebody[i].X && snakebody[0].Y == snakebody[i].Y && i != 0)
{
system("cls");
Game_over = true; //如果蛇1撞了自身,则退出循环。
ofs << "蛇1最终得分为:" << " " << score <<"蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇1撞到了自身" << endl;
ofs << "蛇1撞了自身,默认判定蛇2胜利!";
ofs.close();
hit_win = 4; //默认蛇2胜利
S2.Compare_score(hit_win);
break; //退出一层for循环
}
if (snakebody[0].X == snakebody_[x].X && snakebody[0].Y == snakebody_[x].Y) {
system("cls");
Game_over = true;//如果蛇1撞了蛇2,则退出循环。
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇1撞了蛇2" << endl;
ofs << "蛇1撞了蛇2,默认判定蛇2胜利!";
ofs.close();
hit_win = 2; //默认判定蛇2胜利
S2.Compare_score(hit_win);
break; //退出一层for循环
}
Goto_mark(snakebody[i].X * 2, snakebody[i].Y);
Color(10); //浅绿色
cout << "●";
}
}
if (Game_over == true) {
break; //退出while循环
}
for (int x = 0; x < length; x++) {
for (int i = 0; i < length_; i++) {
if (snakebody_[0].X == snakebody_[i].X && snakebody_[0].Y == snakebody_[i].Y && i != 0)
{
system("cls");
Game_over = true; //如果蛇2撞了自身,则退出循环
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇2撞到了自身" << endl;
ofs << "蛇2撞了自身,默认判定蛇1胜利!";
ofs.close();
hit_win = 3; //默认判定蛇1胜利
S2.Compare_score(hit_win);
break; //退出一层for循环
}
if (snakebody_[0].X == snakebody[x].X && snakebody_[0].Y == snakebody[x].Y) {//如果蛇2撞了蛇1,则退出循环。
system("cls");
Game_over = true;
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇2撞了蛇1" << endl;
ofs << "蛇2撞了蛇1,默认判定蛇1胜利!";
ofs.close();
hit_win = 1; //默认判定蛇1胜利
S2.Compare_score(hit_win);
break; //退出一层for循环
}
Goto_mark(snakebody_[i].X * 2, snakebody_[i].Y);
Color(11); //浅绿色
cout << "●";
}
}
if (Game_over == true) {
break; //退出while循环
}
Goto_mark(tail.X * 2, tail.Y);
cout << " "; //两个空格相当于一个蛇的点宽度
Goto_mark(tail_.X * 2, tail_.Y);
cout << " ";
S2.Snake1::Game_instruction();
S2.Game_instruction();
if (snakebody[0].X * 2 == food.X * 2 && snakebody[0].Y == food.Y) {
score++;
is_eat = true;
length++;
continue;
}
if (snakebody_[0].X * 2 == food.X * 2 && snakebody_[0].Y == food.Y) {
score_++;
is_eat = true;
length_++;
continue;
}
if (_kbhit()) { // _kbhit() 在执行时,检测是否有按键按下,有按下返回键值,没有按下返回0; 是非阻塞函数
char c,d;
c = _getch();//接受来自控制台的输入信息。
//控制方向
if ((c == 'w' || c == 'W') && face_to != 2) { //防止相反方向上的冲突。
face_to = 1;
}
if ((c == 's' || c == 'S') && face_to != 1) {
face_to = 2;
}
if ((c == 'a' || c == 'A') && face_to != 4) {
face_to = 3;
}
if ((c == 'd' || c == 'D') && face_to != 3) {
face_to = 4;
}
if (c ==-32) {
d = _getch();
if (d==72 && face_ != 2) {
face_ = 1;
}
if (d==80 && face_ != 1) {
face_ = 2;
}
if (d==75&& face_ != 4) {
face_ = 3;
}
if (d== 77 && face_ != 3) {
face_ = 4;
}
}
}
//蛇1朝向
if (face_to == 1) {
node.X = snakebody[0].X;
node.Y = snakebody[0].Y - 1;
}
if (face_to == 2) {
node.X = snakebody[0].X;
node.Y = snakebody[0].Y + 1;
}
if (face_to == 3) {
node.X = snakebody[0].X - 1;
node.Y = snakebody[0].Y;
}
if (face_to == 4) {
node.X = snakebody[0].X + 1;
node.Y = snakebody[0].Y;
}
//蛇2朝向
if (face_ == 1) {
node_.X = snakebody_[0].X;
node_.Y = snakebody_[0].Y - 1;
}
if (face_ == 2) {
node_.X = snakebody_[0].X;
node_.Y = snakebody_[0].Y + 1;
}
if (face_ == 3) {
node_.X = snakebody_[0].X - 1;
node_.Y = snakebody_[0].Y;
}
if (face_ == 4) {
node_.X = snakebody_[0].X + 1;
node_.Y = snakebody_[0].Y;
}
if (snakebody[0].X >= 23 || snakebody_[0].X >= 23) {
system("cls");
system("color f0");
cout << " 蛇撞到了右边墙体" << endl;
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇撞到了右边墙体" << endl;
ofs.close();
putchar(7);
S2.Compare_score(score,score_,hit_win);
break;
}
if (snakebody[0].X <= 0 || snakebody_[0].X <= 0) {
system("cls");
system("color f0");
cout << " 蛇撞到了左边墙体" << endl;
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇撞到了左边墙体" << endl;
ofs.close();
putchar(7);
S2.Compare_score(score, score_, hit_win);
break;
}
if (snakebody[0].Y >= 29 || snakebody_[0].Y >= 29) {
system("cls");
system("color f0");
cout << " 蛇撞到了下边墙体" << endl;
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇撞到了下边墙体" << endl;
ofs.close();
putchar(7);
S2.Compare_score(score, score_, hit_win);
break;
}
if (snakebody[0].Y <= 0 || snakebody_[0].Y <= 0) {
system("cls");
system("color f0");
cout << " 蛇撞到了上边墙体" << endl;
ofs << "蛇1最终得分为:" << " " << score << "蛇的最终长度为: " << length << endl;
ofs << "蛇2最终得分为:" << " " << score_ << "蛇的最终长度为: " << length_ << endl;
ofs << "死亡原因为: 蛇撞到了上边墙体" << endl;
ofs.close();
putchar(7);
S2.Compare_score(score, score_, hit_win);
break;
}
for (int i = 0; i < length; i++) {
swap(node.X, snakebody[i].X);
swap(node.Y, snakebody[i].Y);
}
for (int i = 0; i < length_; i++) {
swap(node_.X, snakebody_[i].X);
swap(node_.Y, snakebody_[i].Y);
}
tail.X = node.X;
tail.Y = node.Y;
tail_.X = node_.X;
tail_.Y = node_.Y;
}
break;
case '3':
break;
default:
cout << "你输错了,重新输入" << endl;
break;
}
}
int main()
{
system(“color f0”);
cout << “\t\t\t*****************\t请选择游戏模式: " << endl;
cout << "\t\t\t\t1.单人贪吃蛇 " << endl;
cout << "\t\t\t\t2.双人贪吃蛇 " << endl;
cout << "\t\t\t\t3.退出 *****************” << endl;
while (1) {
choose = getchar();
getchar(); //读取缓冲区的回车符
menu();
if (choose != '1' && choose != '2'&&choose!='3') {
continue;
}
break;
}
return 0;
}