基于C#开发一款益智类一笔画小游戏

资源下载地址:https://download.csdn.net/download/sheziqiong/85947757
资源下载地址:https://download.csdn.net/download/sheziqiong/85947757

高级语言程序设计项目报告

一、 作业题目

一笔画小游戏。

二、 开发软件

Visual Studio 2019 with easyX.

三、 课题设计

  1. 面向对象。
  2. 游戏流程。
  3. 编程中遇到的困难。
  4. 最终的解决与实现。

四、 主要流程

4.1游戏设计思路

这是一款益智类一笔画小游戏,玩家通过 WASD 或方向键移动,使用空格键重置, 当图中的方格填满即算过关。游戏的可玩度和自由度较高,通关的路径可能不止一条,有些关卡玩家需要巧妙的运用特殊方块才能找到唯一路径。

4.2游戏大体框架的构建

首先利用结构体

struct Role
{
		int cols;
		int row;
		int flag; 
}role;

来记录方格的 row(纵坐标),cols(横坐标)以及 flag(位移方向)

对于上下左右移动的 4 个方向,采取枚举类型来涵盖;

enum directioin {
				left, right, up, down 
};

而每一个关卡的地图采用数字化的思想,将墙设置为 0,路设置为 1,初始位置设置为 2,以此类推,将数字化地图存入数组 map[n][10][10]当中。

为了实现如下图所示的整体版面与布局,利用 easyX 的函数

setfillcolor(RGB(…, …, …)); 
solidrectangle(x, y, x + 50, y + 50);

等绘图工具来实现方块的绘画。
基于C#开发一款益智类一笔画小游戏_第1张图片

各种类型方块也采用 enum 类型来进行存储

enumTools {
		BLANK = 0, //墙
		WALL = 1, //路
		ROLE = 2, //当前初始位置
		BOARD = 3, //已经走过的方块
		WALL\_SIZE=50, //方格大小

};

对于玩家的键盘的读取与响应采用 GetAsyncKeyState 函数,并将它封装在

keyDown()函数体中。

void keyDown()

{

if (GetAsyncKeyState('W') || GetAsyncKeyState(VK\_UP)) 
		role.flag = up;

if (GetAsyncKeyState('S') || GetAsyncKeyState(VK\_DOWN)) 
		role.flag = down;

if (GetAsyncKeyState('A') || GetAsyncKeyState(VK\_LEFT)) 
		role.flag = left;

if (GetAsyncKeyState('D') || GetAsyncKeyState(VK\_RIGHT)) 
		role.flag = right;

}

游戏的刷新率为 50ms,并且利用 while(1)不断更新绘制当前盘面。当游戏开始时,首先需要找到每一个地图的初始坐标,利用函数实现。

void searchRolePos**()

{

for (int i = 0; i < 10; i++)
		for (int j = 0; j < 10; j++)
				if(map[cas][i][j] == ROLE)
				{					role.row = i; 
									role.cols = j;
				}
}


当玩家按键之后作出相应的响应。

if (roleStop(role.flag) == 1) //可以移动

{

		moveRole(role.flag); //移动并更改坐标
		readFlag = 1; //标记为正在移动状态
}

void moveRole(int flag) //移动函数

{
					switch (flag)
					{
					case up:
									map[cas][role.row][role.cols] = BOARD;
									//当前位置修改为已经走过
									if (map[cas][role.row - 1][role.cols] == 1) 
									role.row--;//把纵坐标向上移动 1 个单位
									break;
              case……//其他方向同理
							}
							map[cas][role.row][role.cols] = ROLE;
						//移动后位置为下一步的起始位置
}


利用结构体记录每次移动的起始位置与终点位置

struct Point

{
				int i, j;
}begin[100];

移动结束后(碰到墙或特殊方块),对行走过的路径进行画线。

for (i = 0; i < cnt - 1; i++)
{
			drawLine(begin[i], begin[i + 1]);
}
void drawLine(Point begin, Point end)
{
			line(begin.j \* WALL\_SIZE + 25, begin.i \* WALL\_SIZE + 25, end.j \* WALL\_SIZE + 25, end.i \* WALL\_SIZE + 25);
}

基于C#开发一款益智类一笔画小游戏_第2张图片

过关状态

最后,当整个方格都被填充时就算过关,过关的判定为:

bool gameOver()
{
		for (int i = 0; i < 10; i++)
				for (int j = 0; j < 10; j++)
							if (map[cas][i][j] == WALL)return 0;
		return 1; //没有空着的路就算 win
}

那么游戏的大体框架就算完成了。

4.3亿些细节与遇到的困难

由于本游戏为开放类小游戏,游戏原理虽不难,但玩家的操作自由性较大,更注重细节的优化与版面的绘制和布局。

首先是在玩法上,增加了 7 中新方块。

  1. 对于“穿过”方块,在玩家遇到这个方块后会穿过,并且“穿过”方块的位置将不会经过。基本思路是:遇到“穿过”方块就将当前坐标多移动一格。如下所示。

基于C#开发一款益智类一笔画小游戏_第3张图片

而在实际运行中,还需要判定其是否撞到墙或其他方块。本着“穿过”方块自身不会被经过的设定,这种情况需要在下一次移动时才能将原来位置设定为“未经过状态。而对于连续的多个“穿过”方块,采用循环递归的思想,一直跳过,直到下一个方块不是“穿过”方块或者下一个方块是墙。如下图所示:

基于C#开发一款益智类一笔画小游戏_第4张图片

​ 连续经过“穿过”方块示意图

  1. 对于“停止”方块,将会暂停当前方块的移动,并且可以通过键盘来再次改变方向。实现较为简单:
if (flag == left && map[cas][role.row][role.cols - 1] == STOP)
{ map[cas][role.row][role.cols - 1] = 1; canmove = 1; Sleep(200);
return 0; }

并在 main 函数中增加

if(canmove){
		canmove = 0;
		role.flag = 4;
}

这里将 role.flag 设置为 4 的原因是 flag 本身是 enum 类型,从 0-3 表示上下左右,所以 role.flag = 4 代表当前不移动。

  1. 对于“转向”方块,实现也较为简单,唯一的难点是如何画线。由于画线的函数只检测初始位置和末位置,导致方块“转向”后,会画出斜线。而解决办法就是多记录一次,让其碰到转向方块便画图,并把转向方块的位置计入 begin[i]。
if (flag == left && map[cas][role.row][role.cols - 1] == RIGHT\_TURN) { …//省略部分代码 turn++; Sleep(30); return 2; }

之后在 main 函数中

if (turn == 1) readFlag = 1, turn = 0;
if (readFlag)
{
		begin[cnt].i = role.row; 
		begin[cnt].j = role.cols; 
		cnt++; //cnt 代表记录的位置个数
		readFlag = 0;
}

基于C#开发一款益智类一笔画小游戏_第5张图片

​ 关 卡 图 修 改 前 修 改 后

其次是游戏过程中可以“空格”键重置盘面,enter 键暂停/播放音乐。

if (GetAsyncKeyState(VK\_SPACE))
{
		for (int i = 0; i < 22; i++)
				for (int j = 0; j < 10; j++)
						for (int k = 0; k < 10; k++)
								map[i][j][k] = mapcopy[i][j][k]; //重置盘面
		searchRolePos();//重新搜索路径
		begin[0].i = role.row; 
		begin[0].j = role.cols; 
		role.flag = 4; //重置方向
		cnt = 1; //重置数组个数
}
if (GetAsyncKeyState(VK\_RETURN))
{
		if (music) { mciSendString("pause EverEternity.mp3", 0, 0, 0); music = !music; }//pause 暂停
		else { mciSendString("resume EverEternity.mp3", 0, 0, 0); music = !music; }//resume 继续

}

第三是增加了开始界面、游戏介绍与结束界面。

其中开始界面增加了七彩的游戏加载进度条,使用了随机函数和绘图函数。

基于C#开发一款益智类一笔画小游戏_第6张图片

而文字的显示采用了 outtextxy 函数并结合 Sleep 函数。进度条显示的部分代码如下所示:

while (i <= 300)

{
		int j = 1 + (int)(100.0 * rand() / (RAND\_MAX + 1.0));
		//生成 1-100 的随机数
		i += 5;
		fillrectangle(100, 350, 100 + i, 375);
		if (i <= 60)setfillcolor(RED);
		else if (i <= 120)setfillcolor(RGB(200, 106, 55));
		else if ……//设置颜色
		if (j <= 50)Sleep(20);
    else if ……//随机加载时间
}

基于C#开发一款益智类一笔画小游戏_第7张图片

游戏介绍画面两个画面之间用 cleardevice()来清屏

按任意键继续使用 system(“pause”);

结束界面与计分系统,其中计分系统为扣分制,初始每一个关卡为 50 分,每次

空格重置扣 3 分,并最终折算为百分制。使用数组实现,较为简单。

基于C#开发一款益智类一笔画小游戏_第8张图片

评价部分使用 while 函数实现字体的从大到小动态显示。

while (k >= 55){
		settextstyle(k, 0, \_T("楷体"));
		if (goal >= 99)outtextxy(200 - k, 200, "举世无双!");
		else if …… k--;
		Sleep(8);
}

基于C#开发一款益智类一笔画小游戏_第9张图片

字体的动态显示

实际上,游戏的背景会慢慢的随着关卡的进度增加而改变(小彩蛋)

setbkcolor(RGB(35 + 2 \* colori, 53 + colori, 115 + colori));

基于C#开发一款益智类一笔画小游戏_第10张图片

​ Fianl 关

Final 关会缓慢绘制一个爱心,其中心形线的绘制如下:

for (i = 0; i <= 6.5; i = i + 0.005){
				m = i;
				n = -size * (((sin(i) * sqrt(fabs(cos(i)))) /
				(sin(i) + 1.4142)) - 2 * sin(i) + 2); x = n * cos(m) + x0;
				y = n * sin(m) + y0; 
				putpixel(x, y,  C); 
				q = 1;	
				Sleep(8);
}

实际上优化的细节还有很多,比如游戏的手感,可预见的 bug 处理等等,在此不再一一列举。

五、单元测试

在经过 n(n>1e2)次试验后,本程序暂时没有明显 bug。唯一已知的“不足” 是在按压按键未及时松开时,可能会造成连续的判定。这是因为游戏的刷新率为50 ms,当按键时间略长时就会判定为下一次输入,这是为了平衡游戏画面感作出的取舍,实际试验中这个 bug 也极少触发。

测试结果展示(部分展示见上一部分)

基于C#开发一款益智类一笔画小游戏_第11张图片
基于C#开发一款益智类一笔画小游戏_第12张图片

个人认为这款小游戏从无论是完成度还是画面、音乐、操作、可玩性都达到了很好的效果。

资源下载地址:https://download.csdn.net/download/sheziqiong/85947757
资源下载地址:https://download.csdn.net/download/sheziqiong/85947757

你可能感兴趣的:(c#,益智类游戏,一笔画小游戏,源码,高级语言开发课程设计)