由于代码技术得提升,注解基本就没有写了,(其中还用了cv大法(部分代码有重复利用的地方),哈哈,仅供参考,如有不足,望指出。也可以加我QQ:2862841130讨论)
wasd玩家一控制,上下左右方向键玩家二控制
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<Windows.h>
#include<time.h>
#include <mmsystem.h>//播放音乐
#pragma comment(lib,"winmm.lib")
#define wideth 96
#define hghit 24
#define MaxLen 50
typedef struct {
int x;
int y;
}coor;
typedef struct
{
int speed;
char ch;
int len;
int flag;
coor body[MaxLen];
}snak;
struct foodcoord {
int x;
int y;
int flag;//定义食物的状态
}food;
enum
{
left = 1,
up = 2,
right = 3,
down=4,
};
snak snk1, snk2;
void SetWindowSize();
void gotoxy(int x,int y);
void InitWindow();
void initImag();
void FlushSnk(snak *sn);
void changeCh1(snak *sn);
void changeCh2(snak *sn);
void drawSnak1(snak *sn);
void drawSnak2(snak *sn);
void playVoiceBg();
void creatfood(snak *sn, snak *sn2);
void eatfood(snak *sn);
void SnakeState(snak *sn1, snak *sn2);
void SetSnk1Color();
void SetSnk2Color();
void SetFoodClor();
void recoverColor();
void gameOver(int i);
void main()
{
SetWindowSize();
InitWindow();
initImag();
playVoiceBg();
while (1)
{
Sleep(snk1.speed);
FlushSnk(&snk1);
changeCh1(&snk1);
drawSnak1(&snk1);
FlushSnk(&snk2);
changeCh2(&snk2);
drawSnak2(&snk2);
creatfood(&snk1, &snk2);
eatfood(&snk1);
drawSnak1(&snk1);
creatfood(&snk1, &snk2);
SnakeState(&snk1, &snk2);
if (!snk1.flag) { gameOver(2); break; }
creatfood(&snk1, &snk2);
eatfood(&snk2);
drawSnak2(&snk2);
creatfood(&snk1, &snk2);
SnakeState(&snk2, &snk1);
if (!snk2.flag) { gameOver(1); break; }
}
getchar();
}
void SetWindowSize()
{
system("mode con cols=96 lines=24"); //cols 代表列 //lines 代表行
SetConsoleTitleA("双人贪吃蛇"); //设置标题
}
void gotoxy(int x, int y)
{
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void InitWindow()
{
system("cls");
for (int i = 0; i < wideth; i += 2)
{
gotoxy(i, 0);
printf("■");
gotoxy(i, hghit-1);
printf("■");
}
for (int i = 0; i < hghit; i ++)
{
gotoxy(0, i);
printf("■");
gotoxy(wideth-2, i);
printf("■");
}
recoverColor();
}
void initImag()
{
snk1.len = snk2.len = 3;
snk1.ch = right;
snk2.ch = up;
snk2.body[0].x = wideth / 4;
snk2.body[0].y = hghit / 4;
snk1.body[0].x = wideth / 4*3;
snk1.body[0].y = hghit / 4*3;
snk1.speed = snk2.speed = 500;
snk1.flag = snk2.flag = 1;
food.flag = 1;
snk1.flag = snk2.flag = 1;
}
void FlushSnk(snak *sn)
{
//反向遍历
for (int i = sn->len-1; i >0; i--)
{
sn->body[i].x = sn->body[i - 1].x;
sn->body[i].y = sn->body[i - 1].y;
}
}
void changeCh1(snak *sn)
{
//判断是否有按键操作
if (GetAsyncKeyState(VK_UP))
{
if (sn->ch != down)sn->ch = up;
}
else if (GetAsyncKeyState(VK_DOWN))
{
if (sn->ch != up)sn->ch = down;
}
else if (GetAsyncKeyState(VK_RIGHT))
{
if (sn->ch != left)sn->ch = right;
}
else if (GetAsyncKeyState(VK_LEFT))
{
if (sn->ch != right)sn->ch = left;
}
else if (GetAsyncKeyState(VK_F1))
{
if (sn->speed >= 100)sn->speed -= 50;
}
else if (GetAsyncKeyState(VK_F2))
{
if (sn->speed <= 3000)sn->speed += 100;
}
//根据检测到的方向改变蛇头的位置
switch (sn->ch)
{
case right:sn->body[0].x += 2; break;
case left:sn->body[0].x -= 2; break;
case up:sn->body[0].y -= 1; break;
case down:sn->body[0].y += 1; break;
}
}
void changeCh2(snak *sn)
{
if (GetAsyncKeyState('W'))
{
if (sn->ch != down)sn->ch = up;
}
else if (GetAsyncKeyState('S'))
{
if (sn->ch != up)sn->ch = down;
}
else if (GetAsyncKeyState('D'))
{
if (sn->ch != left)sn->ch = right;
}
else if (GetAsyncKeyState('A'))
{
if (sn->ch != right)sn->ch = left;
}
//根据检测到的方向改变蛇头的位置
switch (sn->ch)
{
case right:sn->body[0].x += 2; break;
case left:sn->body[0].x -= 2; break;
case up:sn->body[0].y -= 1; break;
case down:sn->body[0].y += 1; break;
}
}
void drawSnak1(snak *sn)
{
SetSnk1Color();
for (int i = 0; i < sn->len; i++)
{
gotoxy(sn->body[i].x, sn->body[i].y);
printf("■");
}
recoverColor();
//擦掉蛇的尾部
gotoxy(sn->body[sn->len - 1].x, sn->body[sn->len - 1].y);
printf(" ");
gotoxy(0, 0);
printf("■");
gotoxy(wideth - 2,hghit-1);
}
void drawSnak2(snak *sn)
{
SetSnk2Color();
for (int i = 0; i < sn->len; i++)
{
gotoxy(sn->body[i].x, sn->body[i].y);
printf("■");
}
recoverColor();
//擦掉蛇的尾部
gotoxy(sn->body[sn->len - 1].x, sn->body[sn->len - 1].y);
printf(" ");
gotoxy(0, 0);
printf("■");
gotoxy(wideth - 2, hghit - 1);
}
void playVoiceBg()
{
mciSendString(TEXT("open bg.mp3 alias mysong"), NULL, 0, NULL);
mciSendString(TEXT("play MySong"), NULL, 0, NULL);
}
void creatfood(snak *sn1, snak *sn2)
{
//随机种子生成
srand((unsigned)time(NULL));
if (food.flag)
while (1)
{
food.x = rand() % 96;
food.y = rand() % 24;
if (food.x % 2 == 0 && food.x >= 2 && food.x <= 92 && food.y > 1 && food.y < 23)
{
int flag1 = 0, flag2 = 0;
//判断产生的食物可不可能在蛇的身体上
for (int i = 0; i < sn1->len; i++)
{
if (sn1->body[i].x == food.x&&sn1->body[i].y == food.y)
{
flag1 = 1;
break;
}
}
for (int i = 0; i < sn2->len; i++)
{
if (sn2->body[i].x == food.x&&sn2->body[i].y == food.y)
{
flag2 = 1;
break;
}
}
if (flag1 == 1&&flag2 == 1)continue;
//绘制食物
else
{
SetFoodClor();
gotoxy(food.x, food.y);
printf("⊙");
food.flag = 0;
recoverColor();
break;
}
}
}
food.flag = 0;
gotoxy(wideth - 2, hghit - 1);
}
void eatfood(snak *sn)
{
//只需要判断蛇头是否与食物重合
if (food.x == sn->body[0].x&&food.y == sn->body[0].y)
{
sn->len+= 1;
food.flag = 1;
}
}
void SnakeState(snak *sn1, snak *sn2)
{
if (sn1->body[0].x < 2 || sn1->body[0].x>94 || sn1->body[0].y < 1 || sn1->body[0].y>23)
sn1->flag = 0;
for (int i = 1; i < sn1->len; i++)
{
if (sn1->body[0].x == sn1->body[i].x&&sn1->body[0].y == sn1->body[i].y)
sn1->flag = 0;
}
for(int i=0;i<sn1->len;i++)
for (int j = 0; j < sn2->len-1; j++)
{
if (sn1->body[i].x == sn2->body[j].x&&sn1->body[i].y == sn2->body[j].y)
sn1->flag = 0;
}
}
void SetSnk1Color()
{
//控制台也是一个窗口,首先拿到控制台这个窗口
//得到一个窗口句柄,唯一的,每一个窗口都有一个
//独有的句柄
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//拿到标准输出的句柄
//然后他会返回一个句柄值HANDLE hConsole
//MSDN微软官方提供的一个手册,里面介绍了每一个函数的用法
//F1在线版
//有了这个句柄后就可以设置窗口的字体颜色(文本前景颜色)
SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
//带入参数就可以了
}
void SetSnk2Color()
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_INTENSITY );
}
void SetFoodClor()
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_RED);
}
void recoverColor()
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
void gameOver(int i)
{
system("cls");
system("color F0");
if (i == 1)
{
gotoxy(wideth / 2, 2);
printf("绿蛇输了");
}
if (i == 2)
{
gotoxy(wideth / 2, 2);
printf("蓝蛇输了");
}
gotoxy(wideth/3, 4);
printf("贪吃蛇");
gotoxy(wideth / 3, 6);
printf("2019//1//15");
gotoxy(wideth / 3, 8);
printf("作者:小豆芽");
gotoxy(wideth / 3, 10);
printf("F1:加速\tF2:减速");
gotoxy(wideth / 3, 12);
printf("CTRL:继续\t空格:暂停");
gotoxy(wideth / 3, 14);
printf("ESC:退出游戏");
gotoxy(wideth / 3, 16);
printf("建议:QQ:2862841130:::");
Sleep(3000);
}
所需音乐文件自己可以自定义添加