自学内容网 自学内容网

双人贪吃蛇代码分享

一. snake.h

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<stdbool.h>
#include<locale.h>
#include<time.h>
#define Pos_x1 24
#define Pos_y1 5

#define Pos_x2 24
#define Pos_y2 15
#define WALL L'□'

#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)//判断按键是按过还是没按过
//蛇的方向
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT
};

//蛇的状态
//正常,撞墙,撞到自己,正常退出
enum STATUS
{
OK,//正常,继续游戏
KILL_BY_WALL,//撞墙
KILL_BY_SELF,//撞到自己
KILL_BY_OTHER,//撞到别的蛇
END_NORMAL//正常退出
};

//蛇身的节点类型
typedef struct SnakeNode
{
//坐标
int x;
int y;
//指向下一个节点的指针
struct SnakeNode* next;
}SnakeNode, * pSnakeNode;

//贪吃蛇
typedef struct Snake
{
pSnakeNode _pSnake;//指向蛇头的指针
pSnakeNode _pFood;//指向食物节点的指针
enum DIRECTION _dir;//蛇的方向
enum STATUS _status;//游戏的状态

int _food_weight;//一个食物的分数
int _score;//总成绩
int _sleep_time;//休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * pSnake;

//函数的声明

//定位光标位置

void SetPos(short x, short y);

//双人游戏的初始化
void GameStart2(pSnake snake1,pSnake snake2);

//欢迎界面的打印
void Welcome2();

//创建地图
void CreateMap();

//双人初始化蛇身
void InitSnake2(pSnake ps1, pSnake ps2);

//创建食物
void CreateFood2(pSnake ps1,pSnake ps2);

//打印帮助信息
void PrintHelpInfo();

//查看节点是否是食物
int JubgeNextIsFood(pSnakeNode pn, pSnake ps);

//双人游戏运行时的逻辑
void GameRun2(pSnake ps1, pSnake ps2);

//游戏结束的处理
void GameEnd2(pSnake ps1, pSnake ps2);

//检测蛇是否撞到墙
void KillWall(pSnake ps1,pSnake ps2);

//检测蛇是否撞到自己
void KillSelf(pSnake ps1,pSnake ps2);

//检测是否撞到别的蛇
void KillOther(pSnake ps1, pSnake ps2);

二. test.c

#include"snake.h"

void test()
{
int f = 1;
srand((unsigned int)time(NULL));
SetPos(35, 14);
do
{
system("cls");
//创建贪吃蛇
Snake  snake1 = { 0 };
Snake  snake2 = { 0 };
//初始化游戏

GameStart2(&snake1, &snake2);
//玩游戏
GameRun2(&snake1, &snake2);
//结束游戏
GameEnd2(&snake1,&snake2);
SetPos(35, 14);
printf("是否再来一局(Y/N):");
while (1)
{
if (KEY_PRESS(78))
{
f = 0;
break;
}
if (KEY_PRESS(89))
{
break;
}
}
} while (f);
}

int main()
{
setlocale(LC_ALL, "");
test();
return 0;
}

三. snake.c

#include"snake.h"
void SetPos(short x, short y)
{
//获得标准输出设备的句柄
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
//定位光标的位置
COORD pos = { x,y };

SetConsoleCursorPosition(houtput, pos);
//设置指定控制台屏幕缓冲区中光标的位置
//参数:1. 控制台屏幕缓冲区的句柄
//2. 指定新光标的位置的 COORD结构
}
int JubgeNextIsFood(pSnakeNode pn, pSnake ps)//判断下个节点是否是食物
{
if (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y)
return 1;
else
return 0;
}
void EatFood(pSnakeNode pn, pSnake ps,pSnake ps2)
{
//头插法
ps->_pFood->next = ps->_pSnake;//将食物的下一个变为头
ps->_pSnake = ps->_pFood;//将食物定义为头

free(pn);//不需要pn记录头的位置了,就销毁
pn = NULL;

//打印蛇身
pSnakeNode cur = ps->_pSnake;
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'◆');
cur = cur->next;
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'●');
cur = cur->next;
}
ps->_score += ps->_food_weight;
//重新创建食物
CreateFood2(ps,ps2);//因为从thc.h里已经声明了,所以不用再上面声明
}
void NoFood(pSnakeNode pn, pSnake ps)
{
pn->next = ps->_pSnake;//下一步的位置之后链接上头结点
ps->_pSnake = pn;//将头变为下一步的位置

pSnakeNode cur = pn->next, qrev = pn;

while (cur->next)
{
cur = cur->next;
qrev = qrev->next;
}
SetPos(cur->x, cur->y);
printf("  ");
free(cur);
cur = NULL;
qrev->next = NULL;

//打印蛇身
cur = ps->_pSnake;
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'◆');
cur = cur->next;
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'●');
cur = cur->next;
}
}
void EatFood2(pSnakeNode pn, pSnake ps,pSnake ps1)
{
//头插法
ps->_pFood->next = ps->_pSnake;//将食物的下一个变为头
ps->_pSnake = ps->_pFood;//将食物定义为头

free(pn);//不需要pn记录头的位置了,就销毁
pn = NULL;

//打印蛇身
pSnakeNode cur = ps->_pSnake;
cur = ps->_pSnake;
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'◇');
cur = cur->next;
int tmp = 0;

while (cur)
{
tmp++;
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'●');
cur = cur->next;
}
ps->_score += ps->_food_weight;

//重新创建食物
CreateFood2(ps,ps1);//因为从snake.h里已经声明了,所以不用再上面声明
}
void NoFood2(pSnakeNode pn, pSnake ps)
{
pn->next = ps->_pSnake;//下一步的位置之后链接上头结点
ps->_pSnake = pn;//将头变为下一步的位置

pSnakeNode cur = pn->next, qrev = pn;

while (cur->next)
{
cur = cur->next;
qrev = qrev->next;
}
SetPos(cur->x, cur->y);
printf("  ");
free(cur);
cur = NULL;
qrev->next = NULL;

//打印蛇身
cur = ps->_pSnake;
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'◇');
cur = cur->next;
int tmp = 0;

while (cur)
{
tmp++;
SetPos(cur->x, cur->y);
wprintf(L"%lc", L'●');
cur = cur->next;
}
}
void Pause()//暂停函数
{
while (1)//无限暂停直到再按一次空格键
{
Sleep(200);
if (KEY_PRESS(VK_SPACE))
{
break;
}
}
}
void KillWall(pSnake ps1,pSnake ps2)
{
if (ps1->_pSnake->x == 0 || ps1->_pSnake->x == 56 || ps1->_pSnake->y == 0 || ps1->_pSnake->y == 26)
{
ps1->_status = KILL_BY_WALL;
}
if (ps2->_pSnake->x == 0 || ps2->_pSnake->x == 56 || ps2->_pSnake->y == 0 || ps2->_pSnake->y == 26)
{
ps2->_status = KILL_BY_WALL;
}

}
void KillSelf(pSnake ps)
{
pSnakeNode cur = ps->_pSnake->next;
while (cur)
{
if (cur->x == ps->_pSnake->x && cur->y == ps->_pSnake->y)
{
ps->_status = KILL_BY_SELF;
break;
}
cur = cur->next;
}
}

void KillOther(pSnake ps1,pSnake ps2)
{
pSnakeNode cur1 = ps1->_pSnake->next;
pSnakeNode cur2 = ps2->_pSnake->next;

while (cur1)
{
if (cur1->x == ps2->_pSnake->x && cur1->y == ps2->_pSnake->y)
{
ps2->_status = KILL_BY_OTHER;
break;
}
cur1 = cur1->next;
}
while (cur2)
{
if (cur2->x == ps1->_pSnake->x && cur2->y == ps1->_pSnake->y)
{
ps1->_status = KILL_BY_OTHER;
break;
}
cur2 = cur2->next;
}

}

void Welcome2()
{
SetPos(40, 14);
wprintf(L"欢迎来到贪吃蛇小游戏\n");

SetPos(42, 20);
system("pause");//暂停

system("cls");//清空屏幕
SetPos(36, 14);
wprintf(L"用↑↓←→来操控一号蛇的移动方向\n");
SetPos(40, 16);
system("pause");//暂停

system("cls");
SetPos(36, 14);
wprintf(L"用W S A D来操控二号蛇的移动方向\n");
SetPos(40, 16);
system("pause");//暂停

system("cls");//清空屏幕
SetPos(40, 14);
wprintf(L"F7加速,F8减速\n");
SetPos(40, 16);
system("pause");//暂停

system("cls");
SetPos(38, 14);
wprintf(L"加速能得到更高的分数\n");
SetPos(40, 16);
system("pause");
system("cls");
}

//双人模式蛇的移动
void SnakeMove2(pSnake ps1, pSnake ps2)
{
SnakeNode* pNextNode1 = (SnakeNode*)malloc(sizeof(SnakeNode));
SnakeNode* pNextNode2 = (SnakeNode*)malloc(sizeof(SnakeNode));
if (pNextNode1 == NULL||pNextNode2==NULL)
{
perror("SnakeMove()::malloc()");
return;
}
switch (ps1->_dir)
{
case UP:
pNextNode1->x = ps1->_pSnake->x;
pNextNode1->y = ps1->_pSnake->y - 1;
break;
case DOWN:
pNextNode1->x = ps1->_pSnake->x;
pNextNode1->y = ps1->_pSnake->y + 1;
break;

case RIGHT:
pNextNode1->x = ps1->_pSnake->x + 2;
pNextNode1->y = ps1->_pSnake->y;
break;
case LEFT:

pNextNode1->x = ps1->_pSnake->x - 2;
pNextNode1->y = ps1->_pSnake->y;
break;
}
switch (ps2->_dir)
{
case UP:
pNextNode2->x = ps2->_pSnake->x;
pNextNode2->y = ps2->_pSnake->y - 1;
break;
case DOWN:
pNextNode2->x = ps2->_pSnake->x;
pNextNode2->y = ps2->_pSnake->y + 1;
break;

case RIGHT:
pNextNode2->x = ps2->_pSnake->x + 2;
pNextNode2->y = ps2->_pSnake->y;
break;
case LEFT:

pNextNode2->x = ps2->_pSnake->x - 2;
pNextNode2->y = ps2->_pSnake->y;
break;
}
if (JubgeNextIsFood(pNextNode1, ps1))//检测一号蛇下一个坐标是否是食物
{
EatFood(pNextNode1, ps1,ps2);//第一个参数记录头的位置,要在函数里销毁
}
else
{
NoFood(pNextNode1, ps1);
}
if (JubgeNextIsFood(pNextNode2, ps2))//检测二号蛇下一个坐标是否是食物
{
EatFood2(pNextNode2, ps2,ps1);//第一个参数记录头的位置,要在函数里销毁
}
else
{
NoFood2(pNextNode2, ps2);
}
//撞墙死亡
KillWall(ps1,ps2);
//撞到自己死亡
KillSelf(ps1);
KillSelf(ps2);
//撞到其它蛇死亡
KillOther(ps1,ps2);
}

void CreateMap()//创造墙
{
//上
for (int i = 0; i < 29; i++)
wprintf(L"%lc", L'□');
//下
SetPos(0, 26);
for (int i = 0; i < 29; i++)
wprintf(L"%lc", L'□');
//左

for (int i = 1; i <= 25; i++)
{
SetPos(0, i);
wprintf(L"%lc", L'□');
}
//右
for (int i = 1; i <= 25; i++)
{
SetPos(56, i);
wprintf(L"%lc", L'□');
}
}

void InitSnake2(pSnake ps1, pSnake ps2)//初始化双人模式蛇
{
pSnakeNode cur1 = NULL;
pSnakeNode cur2 = NULL;
//一号蛇初始化身体
for (int i = 0; i < 5; i++)
{
cur1 = (pSnakeNode)malloc(sizeof(SnakeNode));
if (cur1 == NULL)
{
perror("InitSnake()::malloc()");
return;
}
cur1->next = NULL;
cur1->x = Pos_x1 + 2 * i;
cur1->y = Pos_y1;

//头插法插入链表
if (ps1->_pSnake == NULL)//空链表
{
ps1->_pSnake = cur1;
}
else //非空
{
cur1->next = ps1->_pSnake;
ps1->_pSnake = cur1;
}
}
//二号蛇初始化身体
for (int i = 0; i < 5; i++)
{
cur2 = (pSnakeNode)malloc(sizeof(SnakeNode));
if (cur2 == NULL)
{
perror("InitSnake()::malloc()");
return;
}
cur2->next = NULL;
cur2->x = Pos_x2 + 2 * i;
cur2->y = Pos_y2;

//头插法插入链表
if (ps2->_pSnake == NULL)//空链表
{
ps2->_pSnake = cur2;
}
else //非空
{
cur2->next = ps2->_pSnake;
ps2->_pSnake = cur2;
}
}
//一号蛇身体打印
cur1 = ps1->_pSnake;
SetPos(cur1->x, cur1->y);
wprintf(L"%lc", L'◆');
cur1 = cur1->next;
while (cur1)
{
SetPos(cur1->x, cur1->y);
wprintf(L"%lc", L'●');
cur1 = cur1->next;
}
//二号蛇身体打印
cur2 = ps2->_pSnake;
SetPos(cur2->x, cur2->y);
wprintf(L"%lc", L'◇');
cur2 = cur2->next;

while (cur2)
{
SetPos(cur2->x, cur2->y);
wprintf(L"%lc", L'●');
cur2 = cur2->next;
}


//设置贪吃蛇1的属性
ps1->_dir = RIGHT;//默认向右
ps1->_score = 0;//总成绩初始为0
ps1->_food_weight = 10;//食物的奖励分数
ps1->_sleep_time = 200;//蛇多久动一次,单位是毫秒
ps1->_status = OK;//蛇的状态是正常的

//设置贪吃蛇2的属性
ps2->_dir = RIGHT;//默认向右
ps2->_score = 0;//总成绩初始为0
ps2->_food_weight = 10;//食物的奖励分数
ps2->_sleep_time = 200;//蛇多久动一次,单位是毫秒
ps2->_status = OK;//蛇的状态是正常的
}

void CreateFood2(pSnake ps1,pSnake ps2)//随机生成食物
{
int x = 0;
int y = 0;

//生成x是2的倍数
//x: 2至54
//y: 1至25
again:
do
{
x = rand() % 53 + 2;
y = rand() % 25 + 1;

} while (x % 2 != 0);
//x和y的坐标不能和两条蛇的身体坐标冲突
pSnakeNode cur1 = ps1->_pSnake;
pSnakeNode cur2 = ps2->_pSnake;
while (cur1)
{
if (x == cur1->x && y == cur1->y)
{
goto again;//如果食物和1蛇身重叠就返回重新生成食物
}
cur1 = cur1->next;
}
while (cur2)
{
if (x == cur2->x && y == cur2->y)
{
goto again;//如果食物和2蛇身重叠就返回重新生成食物
}
cur2 = cur2->next;
}
//创建食物的节点
pSnakeNode pfood = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pfood == NULL)
{
perror("CreateFood()::malloc()");
return;
}

pfood->x = x;
pfood->y = y;
pfood->next = NULL;
SetPos(x, y);//定位食物位置
wprintf(L"%lc", L'★');

ps1->_pFood = pfood;
ps2->_pFood = pfood;
}

void PrintHelpInfo()
{
SetPos(64, 12);
wprintf(L"%ls", L"不能穿墙,不能咬到自己和别人");
SetPos(64, 16);
wprintf(L"%ls", L"用↑↓←→来控制一号蛇");
SetPos(64, 17);
wprintf(L"%ls", L"用 W A S D 来控制二号蛇");
SetPos(64, 19);
wprintf(L"%ls", L"按F7加速,按F8减速");
SetPos(64, 20);
wprintf(L"%ls", L"按ESC退出游戏,空格暂停游戏");
}

//双人模式运行
void GameRun2(pSnake ps1, pSnake ps2)
{
//打印帮助信息
PrintHelpInfo();
do
{
//打印总分数和食物的分值
SetPos(64, 10);
printf("一号蛇总分数:%d\n", ps1->_score);//总分数
SetPos(64, 11);
printf("一号蛇食物的分值:%2d\n", ps1->_food_weight);//食物的分值,%2d防止分数减少后面的0不去除
SetPos(64, 13);
printf("二号蛇总分数:%d\n", ps2->_score);//总分数
SetPos(64, 14);
printf("二号蛇食物的分值:%2d\n", ps2->_food_weight);
//蛇只能向当前方向的左右转向,不能朝后转向
if (KEY_PRESS(VK_UP) && ps1->_dir != DOWN)//
{
ps1->_dir = UP;
}
else if (KEY_PRESS(87) && ps2->_dir != DOWN)
{
ps2->_dir = UP;
}
else if (KEY_PRESS(VK_DOWN) && ps1->_dir != UP)
{
ps1->_dir = DOWN;
}
else if (KEY_PRESS(83) && ps2->_dir != UP)
{
ps2->_dir = DOWN;
}
else if (KEY_PRESS(VK_LEFT) && ps1->_dir != RIGHT)
{
ps1->_dir = LEFT;
}
else if (KEY_PRESS(65) && ps2->_dir != RIGHT)
{
ps2->_dir = LEFT;
}
else if (KEY_PRESS(VK_RIGHT) && ps1->_dir != LEFT)
{
ps1->_dir = RIGHT;
}
else if (KEY_PRESS(68) && ps2->_dir != LEFT)
{
ps2->_dir = RIGHT;
}
else if (KEY_PRESS(VK_SPACE))
{
Pause();
}
else if (KEY_PRESS(VK_ESCAPE))
{
ps1->_status = END_NORMAL;//游戏状态设置为退出
ps2->_status = END_NORMAL;//游戏状态设置为退出
}
else if (KEY_PRESS(VK_F7))//加速
{
if (ps2->_sleep_time > 80)
{
ps1->_sleep_time -= 30;
ps1->_food_weight += 2;//速度增加食物分数增加
ps2->_sleep_time -= 30;
ps2->_food_weight += 2;//速度增加食物分数增加
}
}
else if (KEY_PRESS(VK_F8))//减速
{
if (ps2->_sleep_time < 320)
{
ps1->_sleep_time += 30;
ps1->_food_weight -= 2;
ps2->_sleep_time += 30;
ps2->_food_weight -= 2;
}
}

SnakeMove2(ps1, ps2);//蛇的移动

Sleep(ps1->_sleep_time);
} while (ps1->_status == OK && ps2->_status == OK);

}
void GameEnd2(pSnake ps1,pSnake ps2)
{
SetPos(60, 5);

if (ps1->_status == END_NORMAL)
printf("退出游戏\n");
else if (ps1->_status != OK && ps2->_status != OK)
printf("同归于尽啦\n");

else if (ps1->_status == KILL_BY_WALL && ps2->_status == OK)
printf("二号蛇胜利^_^\n");
else if (ps1->_status == KILL_BY_SELF && ps2->_status == OK)
printf("二号蛇胜利^_^\n");
else if (ps1->_status == KILL_BY_OTHER && ps2->_status == OK)
printf("二号蛇胜利^_^\n");

else if (ps2->_status == KILL_BY_WALL && ps1->_status == OK)
printf("一号蛇胜利^_^\n");
else if (ps2->_status == KILL_BY_SELF && ps1->_status == OK)
printf("一号蛇胜利^_^\n");
else if (ps2->_status == KILL_BY_OTHER && ps1->_status == OK)
printf("一号蛇胜利^_^\n");

//释放蛇身的链表
pSnakeNode cur1 = ps1->_pSnake;
while (cur1)
{
pSnakeNode tmp = cur1;
cur1 = cur1->next;
free(tmp);
tmp = NULL;
}
pSnakeNode cur2 = ps2->_pSnake;
while (cur2)
{
pSnakeNode tmp = cur2;
cur2 = cur2->next;
free(tmp);
tmp = NULL;
}

}

void GameStart2(pSnake ps1, pSnake ps2)
{
//0. 设置窗口大小,隐藏光标
system("mode con cols=100 lines=30");
system("title 贪吃蛇");
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
//隐藏光标操作 
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标状态
CursorInfo.bVisible = false;//隐藏控制台光标
SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态


//1. 打印环境界面
Welcome2();
//2. 绘制地图 
CreateMap();
//3. 创建蛇
InitSnake2(ps1, ps2);
//4. 创建食物
CreateFood2(ps1,ps2);
}

氵氵氵


原文地址:https://blog.csdn.net/m0_68142120/article/details/140228374

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!