贪吃蛇游戏实验报告

使用教材:C语言课程设计与游戏开发实践
一、实验目的

  1. 熟悉实验环境VC++(或Dev C++);
  2. 熟悉console的输入和输出;
  3. 通过游戏的需求,进一步掌握数组的使用。
    二、实验环境
    DEV C++/VC++
    三、实验记录
    实验思路:以实验教材P87至P91页的代码为基础,加入计分功能,计命功能,变速功能,游戏成功和失败出口,规则和选择蛇型的输入界面,道具,复活和暂停等功能。
    实验过程:由于一开始思路比较正确且有上次实验经验,问题都能得到较好解决。但由于缺乏如加入断点等调试经验,导致浪费较多时间。
    实验结果:代码量248行,分为front() startup() show() move() updateWithInput() back() 6个模块,基本实现上述功能。
    实验的代码和注释:
#include 
#include 
#include 
#include 
#define H  24 //画面尺寸
#define w  79
int dire;     // 小蛇移动位置,上下左右分别用1,2,3,4表示
int f_x, f_y; // 食物F
int S_x, S_y; // 道具S
int canvas[H][w] = { 0 };//数组画布
int a;        //用户输入变量
int life = 3, score = 0;
void gotoxy(int x, int y)
{
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos;
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition(handle, pos);
}
void front()
{
	printf("规则:1、游戏界面中,通过'W''A''S''D'操纵蛇移动,'p'键暂停,'ESC'键退出。\n");
	printf("      2、游戏过程中,用户通过吞食道具和食物得分,生命=3,初始分数=4,食物'F'分数+1,道具'S’生命-1且分数-20。\n");
	printf("      3、游戏过程中,误食道具“S”,碰墙和咬自己的尾巴生命-1,当生命=0时游戏结束,分数=100时游戏通关。\n");
	printf("      4、游戏过程中,分数到达一定程度后,蛇的速度会发生变化。\n");
	printf("                                    蛇的样式1,@**************\n");
	printf("                                    蛇的样式2,@$$$$$$$$$$$$$$\n");
	printf("                                    蛇的样式3,@&&&&&&&&&&&&&&\n");
	printf("了解规则后,将输入法切换成英文,输入数字1到3选择蛇的样式,按下回车,游戏开始。\n");
begin:scanf("%d", &a);
	if (a < 1 || a>3) {//检测非法输录
		printf("非法输入,清正确输入\n");
		goto begin;
	}
	system("cls");
}
void startup() // 初始化数据
{
	int i, j;
	for (i = 0; i < H; i++)
	{
		canvas[i][0] = -1;
		canvas[i][w - 1] = -1;
	}
	for (j = 0; j < w; j++)
	{
		canvas[0][j] = -1;
		canvas[H - 1][j] = -1;
	}
	canvas[H / 2][w / 2] = 1;//头
	for (i = 1; i <= 4; i++)//身
		canvas[H / 2][w / 2 - i] = i + 1;
	dire = 4;// 初始向右移
	for (i = 0; i < 6; i++) {
		f_x = rand() % (H - 5) + 2;
		f_y = rand() % (w - 5) + 2;
		S_x = rand() % (H - 5) + 2;
		S_y = rand() % (w - 5) + 2;
		canvas[f_x][f_y] = -2;
		canvas[S_x][S_y] = -3;
	}
}
void move()
{
	int i, j;
	for (i = 1; i < H - 1; i++)
		for (j = 1; j < w - 1; j++)
			if (canvas[i][j] > 0)
				canvas[i][j]++;
	int OT_i, OT_j, OH_i, OH_j, ST_i, ST_j;
	int max = 0, second;
	for (i = 1; i < H - 1; i++)
		for (j = 1; j < w - 1; j++)
			if (canvas[i][j] > 0)
			{
				if (max < canvas[i][j])//确定最大的数做尾
				{
					max = canvas[i][j];
					OT_i = i;
					OT_j = j;
				}
				if (max = canvas[i][j] + 1)//确定第二大数,配合道具S使用
				{
					ST_i = i;
					ST_j = j;
				}
				if (canvas[i][j] == 2)
				{
					OH_i = i;
					OH_j = j;
				}
			}
	int NH_i, NH_j;
	if (dire == 1) // 向上
	{
		NH_i = OH_i - 1;
		NH_j = OH_j;
	}
	if (dire == 2) // 向下
	{
		NH_i = OH_i + 1;
		NH_j = OH_j;
	}
	if (dire == 3) // 向左
	{
		NH_i = OH_i;
		NH_j = OH_j - 1;
	}
	if (dire == 4) // 向右
	{
		NH_i = OH_i;
		NH_j = OH_j + 1;
	}
	if (canvas[NH_i][NH_j] == -3)//道具S
	{
		canvas[S_x][S_y] = 0;
		score--;
		life--;
		S_x = rand() % (H - 5) + 2;
		S_y = rand() % (w - 5) + 2;
		canvas[S_x][S_y] = -3;
		canvas[OT_i][OT_j] = 0;
		canvas[ST_i][ST_j] = 0;
	}
	else if (canvas[NH_i][NH_j] == -2)//食物F
	{
		canvas[f_x][f_y] = 0;
		score++;
		f_x = rand() % (H - 5) + 2;
		f_y = rand() % (w - 5) + 2;
		canvas[f_x][f_y] = -2;
	}
	else
		canvas[OT_i][OT_j] = 0;
	if (canvas[NH_i][NH_j] > 0 || canvas[NH_i][NH_j] == -1||life==0)	//判断小蛇和自身撞或和边框撞
	{
		life--;
		if (life > 0)
		{
			memset(canvas, 0, sizeof(canvas));//清空数组并初始化,完成复活
			startup();
			score = 4;
		}
		else
		{
			system("cls");
			printf("GAME OVER!");
			exit(0);
		}
	}
	else
		canvas[NH_i][NH_j] = 1;
}
void show()  
{
	gotoxy(0, 0);  //清屏
	int i, j;
	for (i = 0; i < H; i++)
	{
		for (j = 0; j < w; j++)
		{
			if (canvas[i][j] == 0)
				printf(" ");   //   空格
			else if (canvas[i][j] == -1)
				printf("#");   //   边框
			else if (canvas[i][j] == 1)
				printf("@");   //   蛇头
			else if (canvas[i][j] > 1)
			{
				if (a == 1)
					printf("*");
				else if (a == 2)
					printf("$");
				else
					printf("&");
			}   //   输出蛇身*
			else if (canvas[i][j] == -2)
				printf("F");   //   输出食物F
			else if (canvas[i][j] == -3)
				printf("S");   //   输出道具S
		}
		printf("\n");
	}
	printf("分数为%d ", score);
	printf("生命为%d ", life);
	if(score<20)
	Sleep(100);//速度
	else if (score>=20)
	Sleep(70);
	else if (score >= 50)
		Sleep(50);
}
void updateWithInput() 
{
	char input;
	if (kbhit())
	{
		input = getch();  //无需回车
		if (input == 'a')
		{
			dire = 3;   //左移
			move();
		}
		else if (input == 'd')
		{
			dire = 4;  //右移
			move();
		}
		else if (input == 'w')
		{
			dire = 1;  //上移
			move();
		}
		else if (input == 'p')
		{
			system("pause");
			system("cls");
		}
		else if (input == 0x1b)
			exit(0);
		else if (input == 's')
		{
			dire = 2;   //下移
			move();
		}
	}
}
void back()
{
	system("cls");
	printf("GOOD GAME");
}
int main()
{
	front();
	startup(); 
	while (1)
	{
		show();
		move();
		updateWithInput();
		if (score == 100)
			break;
	}
	back();
	return 0;
}

四、问题记录
1.实验中,本来想用goto begin功能返回实现复活,但编译器会报错(原因未知)。解决办法:在142行的位置重新调用一次startup()模块。
2.实验中,本来想再增加一种道具,并在二维数组画布中以-4作为标记,增加后发现,边框上总会有2个#号发生1格位置的偏移,且在蛇经过与#号同一行位置,也会发生相同位置偏移。(原因未知,尚无解决办法)
3.蛇在向左和向上行进的过程中(向右和向下则不会),组成蛇的符号会出现周期性的消失和重现(原因未知,尚无解决办法)
五、小结体会
1.模块化编程可以更加方便的找到相关功能的代码和自变量。
2.即使在思路正确的情况下,如果缺乏足够的调试经验和手段,找BUG依旧很麻烦。

你可能感兴趣的:(贪吃蛇游戏实验报告)