简单小游戏——贪吃蛇

软件使用

EasyX、VS2013

效果图

在这里插入图片描述
在这里插入图片描述

具体实现

地图用数组实现,效果图中每个小方格其实都是数组中的一个元素。当然这里用的是二维数组,初始化为0,而刚开始的蛇就是数组中的一串数字12345,1是蛇头,5是蛇尾。除蛇以外的所有元素都是0。而蛇的移动由不停改变这串数字的位置实现,具体实现为令每个数字都自增1,由此变成为23456,在2前面的元素变为1,再将6变成0,这就实现了蛇往前走一步的动作,不停的重复这个操作就实现了蛇的移动。

源代码version1.0

增加了随着蛇长度增长,移动速度变快的设定
修复了食物会出现在蛇身上的bug(增添一个散列表isSnake,蛇身都映射为true,而食物只会出现在false的位置)
修复了蛇往反方向运动时导致游戏失败的bug(每次按一个键都判断这个方向蛇头的前方是否为蛇身)

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define HEIGHT 30
#define WIDTH 40
#define BLOCK_SIZE 20
char moveDirection;
int snakeLen = 5, velocity = 35, nowHead_i, nowHead_j;
int food_i, food_j;
bool isFailure = false, flag;
int Blocks[HEIGHT][WIDTH] = { 0 };
bool isSnake[HEIGHT][WIDTH];
void start();
void draw_map();
void move_snake();
void updateWithInput();
void updateWithoutInput();
int main()
{
	start();
	while (1)
	{
		draw_map();
		updateWithoutInput();
		updateWithInput();
	}
	return 0;
}
void start()
{
	//food
	food_i = rand() % (HEIGHT - 5) + 2;
	food_j = rand() % (WIDTH - 5) + 2;
	//snake
	Blocks[HEIGHT / 2][WIDTH / 2] = 1; //初始蛇头的位置
	isSnake[HEIGHT / 2][WIDTH / 2] = true;
	for (int i = 1; i < snakeLen; i++)
	{
		Blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1; //初始蛇身
		isSnake[HEIGHT / 2][WIDTH / 2 - i] = true;
	}
	moveDirection = 'd'; //初始方向是右
	initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE);
	setlinecolor(RGB(200, 200, 200));
	BeginBatchDraw();
}
void draw_map()
{
	cleardevice();
	//snake
	for (int i = 0; i < HEIGHT; i++)
	{
		for (int j = 0; j < WIDTH; j++)
		{
			if (Blocks[i][j] > 0)
				setfillcolor(BLACK); //蛇用黑色表示
			else
				setfillcolor(RGB(150, 150, 150)); //除蛇以外的方块都是灰色
			fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); //绘制地图
		}
	}
	//绘制食物
	setfillcolor(GREEN);
	fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);
	if (isFailure) //如果游戏结束,输出文字
	{
		setbkmode(TRANSPARENT);
		settextcolor(RGB(250, 0, 0));
		settextstyle(80, 0, _T("宋体"));
		outtextxy(350, 220, _T("菜"));
	}
	FlushBatchDraw();
}
void move_snake()
{
	//令每个数字自增1
	for (int i = 0; i < HEIGHT; i++)
		for (int j = 0; j < WIDTH; j++)
			if (Blocks[i][j] > 0)
				Blocks[i][j]++;
	int old_tail_i, old_tail_j, old_head_i, old_head_j;
	int maxn = 0;
	for (int i = 0; i < HEIGHT; i++)
	{
		for (int j = 0; j < WIDTH; j++)
		{
			if (Blocks[i][j] > maxn) //这个if用来找蛇尾
			{
				maxn = Blocks[i][j];
				old_tail_i = i;
				old_tail_j = j;
			}
			if (Blocks[i][j] == 2) //这个if用来找蛇头
			{
				old_head_i = i;
				old_head_j = j;
			}
		}
	}
	int new_head_i = old_head_i;
	int new_head_j = old_head_j;
	//改变方向
	if (moveDirection == 'w')
		new_head_i = old_head_i - 1;
	else if (moveDirection == 'a')
		new_head_j = old_head_j - 1;
	else if (moveDirection == 's')
		new_head_i = old_head_i + 1;
	else if (moveDirection == 'd')
		new_head_j = old_head_j + 1;
	if (new_head_i >= HEIGHT || new_head_i < 0 || new_head_j < 0 || new_head_j >= WIDTH || Blocks[new_head_i][new_head_j] > 0)
	{
	//碰到身子或者出界则游戏结束
		isFailure = true;
		return;
	}
	nowHead_i = new_head_i;
	nowHead_j = new_head_j;
	Blocks[new_head_i][new_head_j] = 1;
	isSnake[new_head_i][new_head_j] = true;
	if (new_head_i == food_i && new_head_j == food_j)
	{
	//如果蛇头在食物的位置,就代表吃到了
	//则重新生成食物,并且蛇身变成(蛇尾不用变成0)
		food_i = rand() % (HEIGHT - 5) + 2;
		food_j = rand() % (WIDTH - 5) + 2;
		while (isSnake[food_i][food_j])
		{
			food_i = rand() % (HEIGHT - 5) + 2;
			food_j = rand() % (WIDTH - 5) + 2;
		}
		snakeLen += 1;
		flag = true;
	}
	else
	{
		//如果没吃到食物,蛇尾变0
		Blocks[old_tail_i][old_tail_j] = 0;
		isSnake[old_tail_i][old_tail_j] = false;
	}
}
void updateWithInput()
{
	if (_kbhit() && !isFailure)
	{
		char input = _getch();
		if (input == 'w' && Blocks[nowHead_i - 1][nowHead_j] == 0)
		{
			moveDirection = input;
			move_snake();
		}
		else if (input == 'a' && Blocks[nowHead_i][nowHead_j - 1] == 0)
		{
			moveDirection = input;
			move_snake();
		}
		else if (input == 's' && Blocks[nowHead_i + 1][nowHead_j] == 0)
		{
			moveDirection = input;
			move_snake();
		}
		else if (input == 'd' && Blocks[nowHead_i][nowHead_j + 1] == 0)
		{
			moveDirection = input;
			move_snake();
		}
	}
}
void updateWithoutInput()
{
	if (isFailure)
		return;
	static int waitIndex = 1;
	waitIndex++;
	//控制蛇身移动速度,waitIndex每到达velocity则移动一次
	//所以velocity越小,移动频率越高,速度越快
	if (waitIndex == velocity)
	{
		move_snake();
		waitIndex = 1;
		if (flag && snakeLen >= 10 && snakeLen % 5 == 0)
		//蛇身超过10并且能被5整除,则速度增加
		{
			velocity -= 5;
			if (velocity <= 5)
				velocity = 5;
			flag = false;
		}
	}
}

源代码version2.0

蛇有了皮肤
去掉按住一个方向键会加速的设定
去掉原先随着蛇身变长,移动速度变快的设定,改为随机生成加速食物(红)、减速食物(蓝)和普通食物(绿)
修复了刚开始游戏按a会直接游戏结束的bug(因为nowHead_i和nowHead_j没有初始化为HEIGHT / 2和WIDTH / 2)

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define HEIGHT 30
#define WIDTH 40
#define BLOCKSIZE 20
char moveDirection;
bool fast_food, slow_food;
int food_i, food_j;
int nowHead_i, nowHead_j, velocity = 20, step;
bool isFailure;
int map[HEIGHT][WIDTH];
bool isSnake[HEIGHT][WIDTH];
void start();
void draw_map();
void move_snake();
void updateWithoutInput();
void updateWithInput();
void creatFood();
int main()
{
	start();
	while (1)
	{
		if (step == 30)
		{
		//去除食物给的加速\减速效果
			step = 0;
			velocity = 20;
		}
		draw_map();
		updateWithoutInput();
		updateWithInput();
	}
	_getch();
	closegraph();
	return 0;
}
void start()
{
	//snake
	map[HEIGHT / 2][WIDTH / 2] = 1;
	for (int i = 1; i < 5; i++)
	{
		map[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
		isSnake[HEIGHT / 2][WIDTH / 2 - i] = true;
	}
	moveDirection = 'd';
	//food
	creatFood();
	initgraph(WIDTH * BLOCKSIZE, HEIGHT * BLOCKSIZE);
	setlinecolor(RGB(200, 200, 200));
	BeginBatchDraw();
}
void draw_map()
{
	cleardevice();
	for (int i = 0; i < HEIGHT; i++)
	{
		for (int j = 0; j < WIDTH; j++)
		{
			if (map[i][j] > 0)
				setfillcolor(HSVtoRGB(map[i][j] * 10, 0.9, 1));
			else
				setfillcolor(RGB(125, 125, 125));
			fillrectangle(j * BLOCKSIZE, i * BLOCKSIZE, (j + 1) * BLOCKSIZE, (i + 1) * BLOCKSIZE);
		}
	}
	if (fast_food)
		setfillcolor(RED);
	else if (slow_food)
		setfillcolor(BLUE);
	else
		setfillcolor(GREEN);
	fillrectangle(food_j * BLOCKSIZE, food_i * BLOCKSIZE, (food_j + 1) * BLOCKSIZE, (food_i + 1) * BLOCKSIZE);
	if (isFailure)
	{
		setbkmode(TRANSPARENT);
		settextcolor(RGB(250, 0, 0));
		settextstyle(80, 0, _T("宋体"));
		outtextxy(350, 220, _T("菜"));
	}
	FlushBatchDraw();
}
void move_snake()
{
	for (int i = 0; i < HEIGHT; i++)
		for (int j = 0; j < WIDTH; j++)
			if (map[i][j] > 0)
				map[i][j]++;
	int old_head_i, old_head_j, old_tail_i, old_tail_j;
	int maxn = 0;
	for (int i = 0; i < HEIGHT; i++)
	{
		for (int j = 0; j < WIDTH; j++)
		{
			if (map[i][j] == 2)
			{
				old_head_i = i;
				old_head_j = j;
			}
			if (map[i][j] > maxn)
			{
				maxn = map[i][j];
				old_tail_i = i;
				old_tail_j = j;
			}
		}
	}
	int new_head_i = old_head_i, new_head_j = old_head_j;
	if (moveDirection == 'a')
		new_head_j = old_head_j - 1;
	else if (moveDirection == 'w')
		new_head_i = old_head_i - 1;
	else if (moveDirection == 's')
		new_head_i = old_head_i + 1;
	else if (moveDirection == 'd')
		new_head_j = old_head_j + 1;
	if (new_head_i >= HEIGHT || new_head_i < 0 || new_head_j >= WIDTH || new_head_j < 0 || map[new_head_i][new_head_j] > 0)
	{
		isFailure = true;
		return;
	}
	step++;
	nowHead_i = new_head_i;
	nowHead_j = new_head_j;
	map[new_head_i][new_head_j] = 1;
	if (new_head_i == food_i && new_head_j == food_j)
	{
		if (fast_food)
		{
		//如果是加速食物,速度变成原来的2倍
			velocity /= 2;
			fast_food = false;
		}
		else if (slow_food)
		{
		//减速食物反之
			velocity *= 2;
			slow_food = false;
		}
		else
			velocity = 20;
		creatFood();
	}
	else
		map[old_tail_i][old_tail_j] = 0;
}
void updateWithoutInput()
{
	if (isFailure)
		return;
	static int index = 1;
	index++;
	if (index == velocity)
	{
		move_snake();
		index = 1;
	}
}
void updateWithInput()
{
	if (_kbhit() && !isFailure)
	{
		char input = _getch();
		if (input == 'w' && map[nowHead_i - 1][nowHead_j] == 0 && moveDirection != 'w')
		{
			moveDirection = 'w';
			move_snake();
		}
		else if (input == 'a' && map[nowHead_i][nowHead_j - 1] == 0 && moveDirection != 'a')
		{
			moveDirection = 'a';
			move_snake();
		}
		else if (input == 's' && map[nowHead_i + 1][nowHead_j] == 0 && moveDirection != 's')
		{
			moveDirection = 's';
			move_snake();
		}
		else if (input == 'd' && map[nowHead_i][nowHead_j + 1] == 0 && moveDirection != 'd')
		{
			moveDirection = 'd';
			move_snake();
		}
	}
}
void creatFood()
{
	food_i = rand() % (HEIGHT - 5) + 2;
	food_j = rand() % (WIDTH - 5) + 2;
	while (isSnake[food_i][food_j] == true)
	{
		food_i = rand() % (HEIGHT - 5) + 2;
		food_j = rand() % (WIDTH - 5) + 2;
	}
	if (rand() % 5 == 0 && slow_food == false) //随机生成的数能被5整除,则是加速食物
		fast_food = true;
	else if (rand() % 7 == 0 && fast_food == false) //能被7整除则是减速食物
		slow_food = true;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值