最近看到好多人会敲贪吃蛇,我也学起来了。
喝水不忘挖井人!
感谢:https://blog.youkuaiyun.com/qq_40694605/article/details/104537168?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242
我这个是双人版贪吃蛇:控制键是wasd和1235.下面是代码。等有时间再写注释。
今天有一点时间,开始管管我的屎山 吧_
#include<cstdio>
#include<ctime>
#include<windows.h>
#include<conio.h>
#include<vector>
using namespace std;
//移动光标函数
void gotoxy(int x,int y)//老实说这个函数我也不知道是怎么实现的,反正我是参考大佬的,然后背下来。
{
COORD pos = {x,y};//x,y表示坐标 // 横 : x // 竖 : y
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
//隐藏光标函数
void hidecursor()//这个我也。。。等我会了再说
{
CONSOLE_CURSOR_INFO cursor_info = {1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
//食物类
class Food
{
private:
int m_x,m_y;//食物的坐标
public:
void srandfood()//产生随机的食物
{
srand((int)time(NULL));
m_x = 1;//初始化
while(m_x & 1)//因为实际上在DEVC++控制面板上:一个y == 两个x(为了美观)
//且后面蛇的横坐标初始化也是偶数,//所以要保证食物横坐标也为偶数(建议实践出真理)
{
m_x = rand() % (85) + 2;//保证2 <= m_x <= 86;
m_y = rand() % (25) + 2;//保证2 <= m_y <= 26;
}
gotoxy(m_x,m_y);//将食物显示在控制面板上
printf("人"); //食物类型随意(吃人不好吧 *_* 可怕)
}
int get_food_x() {return m_x;}//返回食物的横坐标
int get_food_y() {return m_y;}//返回食物的纵坐标
};
//蛇类
class Snake
{
private:
struct Snakelocal{
int x,y;//来个结构体表示横纵坐标
};
//下面我们来两个容器储存蛇的各个部位的坐标
vector<Snakelocal> snakelocal1;//字母键位的蛇 :蛇一
vector<Snakelocal> snakelocal2;//数字键位的蛇 :蛇二
void judge_dir(Snakelocal& nexthead1,Snakelocal& nexthead2)
{
static char key1 = 'd';//静态变量是灵魂所在(保存最新的输入方向)
static char key2 = '3'; //两者初始化不同(这里找了一个晚上加一个早上) bug是一生之敌 :哭哭
if(_kbhit())//_kbhit():当有敲键盘这个操作时,返回值为真
{
char temp = _getch();//不用摁回车键,直接输入
switch(temp)//判断原来蛇的方向有没有改变的必要
{
case 'w':
case 's':
case 'a':
case 'd':
//方向相反就不用改变了
if((temp == 'w' && key1 != 's') || (temp == 's'&& key1 != 'w')\
|| (temp == 'a' && key1 != 'd') || (temp == 'd' && key1 != 'a'))
key1 = temp;
break;
case '1':
case '2':
case '3':
case '5':
if((temp == '1' && key2 != '3') || (temp == '3'&& key2 != '1')\
|| (temp == '2' && key2 != '5') || (temp == '5' && key2 != '2'))
key2 = temp;
break;
default : break;//使程序具有鲁棒性(开始用专业术语装逼,其实根本不懂^_^)
}
}
//下面分别对两条蛇的蛇头坐标进行处理
//如果方向不变也要运行下面两个switch(自行领会)
switch(key1)
{
case 'w':nexthead1.x = snakelocal1[0].x;
nexthead1.y = snakelocal1[0].y - 1; break;
case 's':nexthead1.x = snakelocal1[0].x;
nexthead1.y = snakelocal1[0].y + 1; break;
case 'a':nexthead1.x = snakelocal1[0].x - 2;
nexthead1.y = snakelocal1[0].y ; break;
case 'd':nexthead1.x = snakelocal1[0].x + 2;
nexthead1.y = snakelocal1[0].y ; break;
}
switch(key2)
{
case '1':nexthead2.x = snakelocal2[0].x - 2;
nexthead2.y = snakelocal2[0].y; break;
case '3':nexthead2.x = snakelocal2[0].x + 2;
nexthead2.y = snakelocal2[0].y; break;
case '5':nexthead2.x = snakelocal2[0].x ;
nexthead2.y = snakelocal2[0].y - 1; break;
case '2':nexthead2.x = snakelocal2[0].x ;
nexthead2.y = snakelocal2[0].y + 1; break;
}
}
//终结程序:有人触犯了规则而死亡
void finish_game(const int score1,const int score2,int flag)
{
system("cls");
gotoxy(30,10);
if(flag == 1)
printf("胜利者为使用字母键位的选手!恭喜!");
else
printf("胜利者为使用数字键位的选手!恭喜!");
gotoxy(30,15);
printf("字母选手得分为 :%d",score1);
gotoxy(30,20);
printf("数字选手得分为 :%d",score2);
gotoxy(0,25);
exit(0);//终结程序
}
//判断有没有人犯规
void judge_finish_game(const int score1,const int score2)
{
for(int i = 1;i < snakelocal1.size();i++)
{//蛇一吃到自己的身体
if(snakelocal1[0].x == snakelocal1[i].x && \
snakelocal1[0].y == snakelocal1[i].y)
finish_game(score1,score2,2);
//蛇二吃到蛇一的身体
if(snakelocal2[0].x == snakelocal1[i].x && \
snakelocal2[0].y == snakelocal1[i].y)
finish_game(score1,score2,1);
}
//下同
for(int i = 1;i < snakelocal2.size();i++)
{
if(snakelocal2[0].x == snakelocal2[i].x && \
snakelocal2[0].y == snakelocal2[i].y)
finish_game(score1,score2,1);
if(snakelocal1[0].x == snakelocal2[i].x && \
snakelocal1[0].y == snakelocal2[i].y)
finish_game(score1,score2,2);
}
//蛇一碰壁
if(snakelocal1[0].x >= 88 || snakelocal1[0].x < 0 || \
snakelocal1[0].y >= 28 || snakelocal1[0].y < 0)
finish_game(score1,score2,2);
//下同
if(snakelocal2[0].x >= 88 || snakelocal2[0].x < 0 || \
snakelocal2[0].y >= 28 || snakelocal2[0].y < 0)
finish_game(score1,score2,1);
}
public:
Snake()//应该是叫作构造函数:目的是为了两条蛇的初始化
{
Snakelocal temp1,temp2;
for(int i = 4;i >= 0;i--)
{
temp1.x = 16 + (i << 1);//横坐标为偶数
temp1.y = 8;
temp2.x = 16 + (i << 1);
temp2.y = 20;
snakelocal1.push_back(temp1);//存入容器
snakelocal2.push_back(temp2);
}
}
void move(Food& food,int& score1,int& score2)
{
Snakelocal nexthead1,nexthead2;//设两个蛇头的坐标
bool flag1 = true,flag2 = true;//自行体会这两个bool的作用
//经过judge_dir函数得到蛇的蛇头坐标
judge_dir(nexthead1,nexthead2);
//将**新蛇头**的坐标插在**旧蛇头**的坐标的前面
//此时蛇的长度无条件加一(即使没有吃到食物也加一**是暂时性的,后面会减回来**)
snakelocal1.insert(snakelocal1.begin(),nexthead1);
snakelocal2.insert(snakelocal2.begin(),nexthead2);
//判断规则有没有被破坏
judge_finish_game(score1,score2);
//下面让我们更新得分:(我玩自己编写的第一个程序居然连100分都到不了:我还是太菜了*_*)
gotoxy(0,0);
printf("让我们猎个痛快!");
gotoxy(0,1);
printf("字母蛇得分为 :%d",score1);
gotoxy(0,2);
printf("数字蛇得分为 :%d",score2);
//判断蛇一有没有吃到食物
if(snakelocal1[0].x == food.get_food_x() && snakelocal1[0].y == \
food.get_food_y())
{
score1++;
flag1 = false;
}
//下同
if(snakelocal2[0].x == food.get_food_x() && snakelocal2[0].y == \
food.get_food_y() && flag1)
{
score2++;
flag2 = false;
}
//吃到食物就没有必要减少蛇的长度了,没吃到才有必要执行这个函数
if(flag1)
{
gotoxy(snakelocal1.back().x,snakelocal1.back().y);
printf(" ");
snakelocal1.pop_back();
}
//下同
if(flag2)
{
gotoxy(snakelocal2.back().x,snakelocal2.back().y);
printf(" ");
snakelocal2.pop_back();
}
//重新打印蛇的picture:图案
//蛇一
for(int i = 0;i < snakelocal1.size();i++)
{
gotoxy(snakelocal1[i].x,snakelocal1[i].y);
if(i == 0) printf("★");
else printf("■");
}
//蛇二
for(int i = 0;i < snakelocal2.size();i++)
{
gotoxy(snakelocal2[i].x,snakelocal2[i].y);
if(i == 0) printf("●");
else printf("■");
}
//判断食物又没有被吃掉,吃掉就要重新打印新的食物
if(flag1 == false || flag2 == false)
{
while(flag1 || flag2)
{
flag1 = false; flag2 = false;
food.srandfood();
//食物不可以跟两条蛇相重合
for(int i = 0;i < snakelocal1.size();i++)
{
if(food.get_food_x() == snakelocal1[i].x && food.get_food_y() \
== snakelocal1[i].y)
flag1 = true;
}
for(int i = 0;i < snakelocal2.size();i++)
{
if(food.get_food_x() == snakelocal2[i].x && food.get_food_y() \
== snakelocal2[i].y)
flag2 = true;
}
}
}
}
};
int main()
{
system("mode con cols=88 lines=28");//规定游戏的界面大小
system("title 双人小游戏之贪吃蛇");//显示标题
hidecursor();//隐藏光标:为了游戏体验更佳
L2:
//下面是游戏介绍(请叫我整活的 坏guy :求求了,别打我脸)
printf("双人小游戏之贪吃蛇游戏介绍:\n");
printf("注意这是一个推塔游戏。\n");
printf("LOL玩多了???\n");
printf("搞错了,再来!\n");
printf("这其实是一个你死我活的游戏!\n");
printf("1:请先摁shift键\n");
printf("2: 有两条蛇,如果一条蛇触壁或碰到另一条蛇的蛇身,该蛇将会死亡!\n");
printf("3: 下面有三个游戏的血腥程度:\n");
printf("和平发育请摁 j\n");
printf("有点上头请摁 k\n");
printf("残忍嗜杀请摁 l\n");
char op = _getch();
int i = -1;
switch(op)
{
case 'j':i = 2;break;
case 'k':i = 1;break;
case 'l':i = 0;break;
default: system("cls");goto L2;break;
}
system("cls");
int score1 = 0,score2 = 0;//得分初始化
int flag[3] = {100,200,300};//来个难度的selection 数组
Snake snake;
Food food;
food.srandfood();
while(true)
{
snake.move(food,score1,score2);
Sleep(flag[i]);
}
return 0;
} //凑个整数吧!我想就到这里吧!See you again!
希望大家没网的时候也有游戏玩。
上面的注释应该还有很多问题,
因为(我是在舍友玩CSGO,外放的情况下,敲的注释,人没了)
希望大家多提意见,我会及时改正error的。
希望大家有一个舒适的游戏体验^ _ ^,See you again !
对了,我这个代码其他编译器还没有试过:只知道DEVC++可以。