贪吃蛇小游戏

贪吃蛇游戏通常由以下几个要素组成:

  1. 蛇头:玩家控制的蛇的头部,用来移动和吃食物。
  2. 蛇身:蛇头后面连接的一系列方块,长度会随着吃到食物而增加。
  3. 食物:随机出现在游戏区域内的食物,蛇需要吃掉它来增长身体长度。
  4. 边界:游戏区域的边界,蛇不能穿过边界。
  5. 游戏得分:吃到食物后,玩家的得分会增加。

玩家通过控制蛇头的移动方向来操纵整条蛇的移动。通常可以使用键盘上的方向键或者滑动屏幕来改变蛇头的移动方向。当蛇头碰到食物时,蛇的长度会增加,并且在新的位置上生成一个新的食物。如果蛇头碰到自己的身体或者撞到边界,游戏结束。

首先是要打印游戏界面。

        这里我们就要使用Windows库函数,包含头文件#include<windows.h>,使用GetStdHandle(STD_OUTPUT_HANDLE)函数来获取标准输出的句柄的位置信息,使用SetConsoleCursorPosition(handle, pos)函数来设置标准输出的光标的位置。

获取到我们想要的位置后就可以打印我们想要的信息了,然后使用system("pause")和system("cls")函数分别为屏幕暂停和清除屏幕,组合使用可以实现多页信息打印。

其次,就要设计游戏的空间范围和游戏规则。

第一,规划好蛇的移动范围,横坐标为58,纵坐标为27。

第二,用宽字符来充当墙,包含头文件#include<locale.h>#define wall L'□'。#define body L'●'。 #define food L'★'。

第三,规则设计:蛇撞墙寄,吃到自己寄,空格游戏暂停,esc键退出游戏,F3游戏加速,F4游戏减速,使用↑↓← → 来控制蛇的移动。

接下来开始对游戏进行一步步地设计

1、初始化蛇

void InitSnake(pSnake pc)
{
	pSnakeNode nod = NULL;
	//创建蛇节点
	int i = 0;
	for (i = 0; i < 5; i++) 
	{
		nod = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (nod == NULL) 
		{
			perror("InitSnake():()malloc");
			return;
		}
		nod->next = NULL;
		nod->x = POS_X + i * 2;
		nod->y = POS_Y;

		//头插
		if (pc->_pSnake == NULL) 
		{
			pc->_pSnake = nod;
		}
		else 
		{
			nod->next = pc->_pSnake;
			pc->_pSnake = nod;
		}
	}
	//打印蛇身
	nod = pc->_pSnake;
	while (nod) 
	{
		SetPos(nod->x, nod->y);
		wprintf(L"%lc", body);
		nod = nod->next;
	}

	//初始化蛇的其他数据
	pc->_Score=0;
	pc->_Add=10;
	pc->_SleepTime=200;
	pc->_Status = OK;
	pc->_Dri = RIGHT;
	
}

2、打印地图

void CreatMap()
{
	int i = 0;
	SetPos(0, 0);
	for (i = 0; i < 58; i += 2) 
	{
		wprintf(L"%lc", wall);
	}
	SetPos(0, 26);
	for (i = 0; i < 58; i += 2) 
	{
		wprintf(L"%lc", wall);
	}
	for (i = 1; i < 26; i++) 
	{
		SetPos(0, i);
		wprintf(L"%lc", wall);
	}
	for (i = 1; i < 26; i++) 
	{
		SetPos(56, i);
		wprintf(L"%lc", wall);
	}
	
}

3、打印提示信息

void PrintHelpInfo()
{
	//打印提⽰信息
	SetPos(64, 15);
	printf("不能穿墙,不能咬到自己");
	SetPos(64, 16);
	printf("用↑.↓.←.→分别控制蛇的移动.");
	SetPos(64, 17);
	printf("F3 为加速,F4 为减速");
	SetPos(64, 18);
	printf("ESC :退出游戏.space:暂停游戏.");
	SetPos(64, 20);
	printf("江氏@版权");
	
}

4、食物的设计

void CreatFood(pSnake pc)
{
	int x = 0;
	int y = 0;

again:
	do 
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);

	pSnakeNode nod = pc->_pSnake;
	while (nod) 
	{
		if (nod->x == x && nod->y == y) 
		{
			goto again;
		}
		nod = nod->next;
	}
	pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (Food == NULL) 
	{
		perror("CreatFood():()malloc");
		return;
	}
	else 
	{
		Food->x = x;
		Food->y = y;
		SetPos(Food->x, Food->y);
		wprintf(L"%lc", food);
		pc->_pFood = Food;
	}
	
}

以上是为游戏的运行做准备。

游戏的运行

1、打印游戏的相关信息

//打印有用信息
    PrintHelpInfo();

2、使用do-while函数,以蛇的状态为条件维持运行。这里我们使用了一个键盘按键的使用情况获取函数KEY_PRESS(),某一个按键未按下时,该按键使用情况用0表示,已经按过用1表示。

do {
		SetPos(64, 10);
		printf("得分:%d", pc->_Score);
		SetPos(64, 11);
		printf("每个食物得分:%2d", pc->_Add);

		if (KEY_PRESS(VK_UP) && pc->_Dri != DOWN) 
		{
			pc->_Dri = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && pc->_Dri != UP) 
		{
			pc->_Dri = DOWN;
		}
		else if (KEY_PRESS(VK_RIGHT) && pc->_Dri != LEFT) 
		{
			pc->_Dri = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) && pc->_Dri != RIGHT) 
		{
			pc->_Dri = LEFT;
		}
		else if (KEY_PRESS(VK_ESCAPE)) 
		{
			pc->_Status = ESC_NOMAL;
			break;
		}
		else if (KEY_PRESS(VK_SPACE)) 
		{
			puse();
		}
		else if (KEY_PRESS(VK_F3)) 
		{
			if (pc->_SleepTime >= 50) 
			{
				pc->_SleepTime -= 30;
				pc->_Add += 2;
			}
		}
		else if (KEY_PRESS(VK_F4)) 
		{
			if (pc->_SleepTime <= 350) 
			{
				pc->_SleepTime += 30;
				pc->_Add -= 2;
				if (pc->_SleepTime == 350) 
				{
					pc->_Add = 1;
				}
			}
		}
		Sleep(pc->_SleepTime);
		SnakeMove(pc);

	} while (pc->_Status==OK);

最后就是游戏的结束

上一环节蛇的状态为条件跳出do-while循环后,便进入游戏结束环节。

pSnakeNode nod = pc->_pSnake;
	SetPos(24, 12);
	switch (pc->_Status)
	{
	case KILL_BY_WALL:
		printf("您撞墙了,游戏结束!\n");
		break;
	case KILL_BY_SELF:
		printf("您吃到自己了,游戏结束!\n");
		break;
	case ESC_NOMAL:
		printf("您主动退出游戏!\n");
		break;
	}

游戏结束后需要把游戏中的有关信息释放

//释放蛇身
	while (nod) 
	{
		pSnakeNode cur = nod;
		nod = nod->next;
		free(cur);
	}

以上内容是该游戏的设计思路与主题结构设计

下面是贪吃蛇游戏的全部代码

//Snake.h文件代码

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<locale.h>


#define wall L'□'
#define body L'●'
#define food L'★'

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1:0)


enum DERECTION
{
	UP=1,
	DOWN,
	LEFT,
	RIGHT
};

enum GAME_STATUS
{
	OK,
	KILL_BY_WALL,
	KILL_BY_SELF,
	ESC_NOMAL
};

//蛇节点定义
typedef struct SnakeNode
{
	int x;
	int y;
	struct SnakeNode* next;

}SnakeNode,* pSnakeNode;


typedef struct Snake
{
	pSnakeNode _pSnake;//维护蛇的指针
	pSnakeNode _pFood;//维护食物的指针
	int _Score;//当前分数
	int _Add;//每个食物默认分数
	enum DERECTION _Dri;//蛇头方向
	enum GAME_STATUS _Status;//游戏状态
	int _SleepTime;//默认睡眠时间
}Snake,* pSnake;


//蛇的初始位置
#define POS_X 24
#define POS_Y 5


void SetPos(short x, short y);

void InitSnake(pSnake pc);

void Welcome();

void CreatMap();

void CreatFood(pSnake pc);

void PrintHelpInfo();

void puse();

int NextIsFood(pSnakeNode node, pSnake pc);

void EatFood(pSnakeNode nod, pSnake pc);

void NoFood(pSnakeNode nod, pSnake pc);

int KillByWall(pSnake pc);

int KillBySelf(pSnake pc);

void SnakeMove(pSnake pc);



//游戏开始
void GameStart(pSnake pc);
//游戏运行
void GameRun(pSnake pc);
//游戏结束
void GameOver(pSnake pc);


//Snake.c文件代码
#define _CRT_SECURE_NO_WARNINGS 1

#include"Snake.h"

void SetPos(short x, short y)
{
	COORD pos = { x,y };
	//获取标准输出的句柄
	HANDLE handle = NULL;
	handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置标准输出光标的位置为pos
	SetConsoleCursorPosition(handle, pos);
}

void InitSnake(pSnake pc)
{
	pSnakeNode nod = NULL;
	//创建蛇节点
	int i = 0;
	for (i = 0; i < 5; i++) 
	{
		nod = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (nod == NULL) 
		{
			perror("InitSnake():()malloc");
			return;
		}
		nod->next = NULL;
		nod->x = POS_X + i * 2;
		nod->y = POS_Y;

		//头插
		if (pc->_pSnake == NULL) 
		{
			pc->_pSnake = nod;
		}
		else 
		{
			nod->next = pc->_pSnake;
			pc->_pSnake = nod;
		}
	}
	//打印蛇身
	nod = pc->_pSnake;
	while (nod) 
	{
		SetPos(nod->x, nod->y);
		wprintf(L"%lc", body);
		nod = nod->next;
	}

	//初始化蛇的其他数据
	pc->_Score=0;
	pc->_Add=10;
	pc->_SleepTime=200;
	pc->_Status = OK;
	pc->_Dri = RIGHT;
	
}

void Welcome() 
{
	SetPos(40, 15);
	printf("欢迎来到贪吃蛇小游戏");
	SetPos(40, 25);
	system("pause");
   	system("cls");

	SetPos(25,12);
	printf("使用 ↑↓← → 来控制蛇的移动,F3为加速,F4为减速\n");

	SetPos(25, 13);
	printf("加速可以获取更高分\n");
	SetPos(40, 25);
	system("pause");

	system("cls");
	
}


void CreatMap()
{
	int i = 0;
	SetPos(0, 0);
	for (i = 0; i < 58; i += 2) 
	{
		wprintf(L"%lc", wall);
	}
	SetPos(0, 26);
	for (i = 0; i < 58; i += 2) 
	{
		wprintf(L"%lc", wall);
	}
	for (i = 1; i < 26; i++) 
	{
		SetPos(0, i);
		wprintf(L"%lc", wall);
	}
	for (i = 1; i < 26; i++) 
	{
		SetPos(56, i);
		wprintf(L"%lc", wall);
	}
	
}

void CreatFood(pSnake pc)
{
	int x = 0;
	int y = 0;

again:
	do 
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2 != 0);

	pSnakeNode nod = pc->_pSnake;
	while (nod) 
	{
		if (nod->x == x && nod->y == y) 
		{
			goto again;
		}
		nod = nod->next;
	}
	pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (Food == NULL) 
	{
		perror("CreatFood():()malloc");
		return;
	}
	else 
	{
		Food->x = x;
		Food->y = y;
		SetPos(Food->x, Food->y);
		wprintf(L"%lc", food);
		pc->_pFood = Food;
	}
	
}

void PrintHelpInfo()
{
	//打印提⽰信息
	SetPos(64, 15);
	printf("不能穿墙,不能咬到自己");
	SetPos(64, 16);
	printf("用↑.↓.←.→分别控制蛇的移动.");
	SetPos(64, 17);
	printf("F3 为加速,F4 为减速");
	SetPos(64, 18);
	printf("ESC :退出游戏.space:暂停游戏.");
	SetPos(64, 20);
	printf("江氏@版权");
	
}

void puse()
{
	while (1) 
	{
		Sleep(300);
		if (KEY_PRESS(VK_SPACE)) 
		{
			break;
		}
	}
}

int NextIsFood(pSnakeNode node, pSnake pc)
{
	return node->x == pc->_pFood->x && node->y == pc->_pFood->y;
}

void EatFood(pSnakeNode nod, pSnake pc) 
{
	nod->next = pc->_pSnake;
	pc->_pSnake = nod;
	pSnakeNode cur = pc->_pSnake;
	while (cur) 
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", body);
		cur = cur->next;
	}
	pc->_Score += pc->_Add;
	free(pc->_pFood);
	CreatFood(pc);
	
}

void NoFood(pSnakeNode nod, pSnake pc)
{
	nod->next = pc->_pSnake;
	pc->_pSnake = nod;
	pSnakeNode cur = pc->_pSnake;
	while (nod->next->next) 
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", body);
		nod = nod->next;
	}
	SetPos(nod->next->x, nod->next->y);
	printf("  ");
	free(nod->next);
	nod->next = NULL;
}


int KillByWall(pSnake pc) 
{
	if (pc->_pSnake->x == 0 ||
		pc->_pSnake->x == 56 ||
		pc->_pSnake->y == 0 ||
		pc->_pSnake->y == 26) {
		pc->_Status = KILL_BY_WALL;
		return 1;
	}
	return 0;
}
int KillBySelf(pSnake pc)
{
	pSnakeNode nod = pc->_pSnake->next;
	while (nod) 
	{
		if (pc->_pSnake->x == nod->x &&
			pc->_pSnake->y == nod->y) 
		{
			pc->_Status = KILL_BY_SELF;
			return 1;
		}
		nod = nod->next;
	}
	return 0;
}

void SnakeMove(pSnake pc)
{
	pSnakeNode nod = NULL;
	nod = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (nod == NULL) {
		perror("SnakeNode():malloc");
		return;
	}
	switch (pc->_Dri) 
	{
	case UP:
	{
		nod->x = pc->_pSnake->x;
		nod->y = pc->_pSnake->y - 1;
	}
		break;
	case DOWN:
	{
		nod->x = pc->_pSnake->x;
		nod->y = pc->_pSnake->y +1;
	}
		break;
	case LEFT:
	{
		nod->x = pc->_pSnake->x-2;
		nod->y = pc->_pSnake->y ;
	}
		break;
	case RIGHT:
	{
		nod->x = pc->_pSnake->x+2;
		nod->y = pc->_pSnake->y ;
	}
		break;
	}
	//判断下一个节点是不是食物
	if (NextIsFood(nod,pc))
	{
		EatFood(nod, pc);
	}
	else 
	{
		NoFood(nod, pc);
	}

	KillByWall(pc);
	KillBySelf(pc);

}

void GameStart(pSnake pc)
{
	//设置控制台窗口的大小
	system("mode con cols=100 lines=30");
	//设置窗口名字
	system("title 贪吃蛇");

	//获取句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

	//隐藏光标
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台窗口光标信息
	//影藏控制台光标信息
	CursorInfo.bVisible = false;
	SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态

	//打印欢迎界面
	Welcome();

	//打印地图
	CreatMap();
	
	//初始化蛇
	InitSnake(pc);

	//创造食物
	CreatFood(pc);

}

void GameRun(pSnake pc)
{
	//打印有用信息
	PrintHelpInfo();
	do {
		SetPos(64, 10);
		printf("得分:%d", pc->_Score);
		SetPos(64, 11);
		printf("每个食物得分:%2d", pc->_Add);

		if (KEY_PRESS(VK_UP) && pc->_Dri != DOWN) 
		{
			pc->_Dri = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && pc->_Dri != UP) 
		{
			pc->_Dri = DOWN;
		}
		else if (KEY_PRESS(VK_RIGHT) && pc->_Dri != LEFT) 
		{
			pc->_Dri = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) && pc->_Dri != RIGHT) 
		{
			pc->_Dri = LEFT;
		}
		else if (KEY_PRESS(VK_ESCAPE)) 
		{
			pc->_Status = ESC_NOMAL;
			break;
		}
		else if (KEY_PRESS(VK_SPACE)) 
		{
			puse();
		}
		else if (KEY_PRESS(VK_F3)) 
		{
			if (pc->_SleepTime >= 50) 
			{
				pc->_SleepTime -= 30;
				pc->_Add += 2;
			}
		}
		else if (KEY_PRESS(VK_F4)) 
		{
			if (pc->_SleepTime <= 350) 
			{
				pc->_SleepTime += 30;
				pc->_Add -= 2;
				if (pc->_SleepTime == 350) 
				{
					pc->_Add = 1;
				}
			}
		}
		Sleep(pc->_SleepTime);
		SnakeMove(pc);

	} while (pc->_Status==OK);

}

void GameOver(pSnake pc)
{
	pSnakeNode nod = pc->_pSnake;
	SetPos(24, 12);
	switch (pc->_Status)
	{
	case KILL_BY_WALL:
		printf("您撞墙了,游戏结束!\n");
		break;
	case KILL_BY_SELF:
		printf("您吃到自己了,游戏结束!\n");
		break;
	case ESC_NOMAL:
		printf("您主动退出游戏!\n");
		break;
	}

	//释放蛇身
	while (nod) 
	{
		pSnakeNode cur = nod;
		nod = nod->next;
		free(cur);
	}
}


//text.c文件代码
#define _CRT_SECURE_NO_WARNINGS 1

#include"Snake.h"



void text() 
{
	char ch;
	Snake snake = { 0 };
	do {
		GameStart(&snake);
		GameRun(&snake);
		GameOver(&snake);
		SetPos(24, 15);
		printf("再来一局吗(Y/N)>:");
		scanf("%c", &ch);
	} while (ch == 'Y' || ch == 'y');
	SetPos(0, 27);
}


int main()
{
	srand((unsigned int)time(NULL));

	setlocale(LC_ALL, "");
	text();
	return 0;
}

        以上内容是有关贪吃蛇游戏的全部内容,如果我的思路或者代码有问题,欢迎您指出相应问题,我会去及时修改,这是对你和对我的一种提升,或者说您认为有更好的代码和思路,欢迎您的分享。请给小生一个一键三连,诚心感谢,创作不易!!!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值