来自童晶老师的游戏开发课程作业
此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2020Fall/homework/11577
作业要求
1.课程网址 [https://www.icourse163.org/course/HHU-1206797807]
2.项目名称及分值
游戏名称 | 满分分值 | 功能点提示 |
---|---|---|
生命游戏 | 20 | 随机初始化、生命算法、刷新显示 |
3.作业提交要求
除代码及git以外,要求 WBS、PSP,要求使用博客报告完成的功能和截图,讲解
关键技术和代码片断。其中WBS要求包括不限于每个子任务的工时估算时间和实
际耗时,精确到分钟。子任务可以包括分析、设计、代码、测试、调试、文档,
鼓励精确到二级子任务如功能点等。
项目coding地址: https://e.coding.net/jianghui2/lifegame/lib.git
项目PSP:
类型 | 任务 | 开始时间 | 结束时间 | 中断时间(分钟) | delta时间(分钟) |
---|---|---|---|---|---|
准备 | 问题了解及主要算法流程设计 | 12.18 19:28 | 12.18 20:12 | 0 | 44 |
编程 | 代码编写 | 12.19 9:04 | 12.19 12:33 | 5+6 | 198 |
编程 | 代码调试 | 12.19 18:06 | 12.19 19:50 | 2+5 | 97 |
文档 | 技术文档编写 | 12.20 10:34 | 12:20 11:30 | 0 | 56 |
项目WBS:
关键技术:
为了实现随机初始化,调用了stdlib.h头文件中的rand函数,在c语言中用来产生一个随机数的函数。srand函数是随机数发生器的初始化函数。
rand()函数每次调用前都会查询是否调用过srand(seed),是否给seed设定了一个值,如果有那么它会自动调用srand(seed)一次来初始化它的起始值。若之前没有调用srand(seed),那么系统会自动给seed赋初始值,即srand(1),自动调用它一次。
为了避免rand()产生随机数时,因srand(seed)相同产生而产生相同的的随机数数组。所以在这里采用时间作种子 srand((unsigned)time(NULL))。每次运行程序的时间肯定是不相同的,产生的随机数就也不一样了。rand()产生的随机数和2取余得到随机的0或1,然后将随机数循环赋值给每一个细胞,得到一个随机的细胞生命的初始化状态。
void randStart()// 数据随机初始化 { int i, j; srand((unsigned)time(NULL));//让rund函数在每次程序运行中产生不同的随机数 for ( i = 0; i < High; i++) { for ( j = 0; j < Width; j++) { cells[i][j] = rand() % 2;//随机数与2取余,得到随机的0或1 } } }
根据生命游戏演化的规则:
一个由N*M个放个组成的矩形中,每个方格可以包含一个细胞,不在边上的有机体有8个相邻方格。
1. 如果一个细胞周围有3个细胞为生,则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变)
2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变
3. 在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)
根据上述规则,用一个临时的二维数组nextCells,来记录Cells的下一个状态。每次对Cells中的点的周围情况neibourNumber进行统计,并据此更新nextCells的值,然后用nextCells更新cells的值。
void cellUpdate() { int nextCells[Width][High];// 下一帧的细胞生命状态 int neibourNumber;//细胞周围生存细胞数 int i, j; for ( i = 1; i <= High-1; i++) { for ( j = 1; j <= Width-1; j++) { neibourNumber = cells[i - 1][j - 1] + cells[i - 1][j] + cells[i - 1][j + 1] + cells[i][j - 1] + cells[i][j + 1] + cells[i + 1][j - 1] + cells[i + 1][j] + cells[i + 1][j + 1]; if (neibourNumber == 3) { nextCells[i][j] = 1; } else if (neibourNumber == 2) { nextCells[i][j] = cells[i][j]; } else nextCells[i][j] = 0; } } for (i = 1; i <= High - 1; i++) { for ( j = 1; j <= Width-1 ; j++) { cells[i][j] = nextCells[i][j]; } } }
在这里使用了控制台API函数SetConsoleCursorPosition,这个函数的功能是设置控制台光标坐标(Set--设置、Console--控制台、Cursor--光标、Position--坐标),使用这个函数需要两个参数:第一个参数类型为HANDLE,第二个参数类型为COORD。
HANDLE是用来定义任何类型的句柄。函数功能:获取指定的标准设备的句柄,使用GetStdHandle需要一个参数,参数的取值有三种
1.STDINPUTHANDLE----标准输入句柄,
2.STDOUTPUTHANDLE----标准输出句柄,
3.STDERRORHANDLE----标准错误句柄。
所以在此处赋值给handle的是标准输出句柄
COORD是Windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标
使用上述类型以及函数必须包含windows.h头文件
void gotoxy(int x, int y)//将光标移动到坐标(x,y) { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(handle, pos);//设置控制台光标坐标 }
void showCell()//从原点坐标刷新细胞状态 { gotoxy(0,0);//清理上一帧状态 int i, j; for ( i = 1; i <= High-1; i++) { for ( j = 1; j <= Width-1; j++) { if (cells[i][j]==1) { cout << "*"; } else { cout << " "; } } cout << endl; } }
int main() { char judge; int count=0; int L; randStart(); cout << "是否开始初始化细胞状态(Y/N)?" << endl; cin >> judge; while (judge!= 'Y' && judge!= 'y' && judge!= 'N' && judge!= 'n') { cout << "输入错误,请重新输入(Y/N)" << endl; cin >> judge; } while (judge== 'Y' || judge== 'y') { showCell(); cellUpdate(); count++; cout << "当前为第" << count <<"次繁衍后的细胞生命状态"<< endl ; cout << "请输入是否继续(Y/N)?" << endl; for(L=0;L<20;L++) cout << " " <<endl; gotoxy(0,31); cin >> judge; while (judge!= 'Y' && judge!= 'y' && judge!= 'N' && judge!= 'n') { cout << "输入错误,请重新输入(Y/N)" << endl; cin >> judge; } } cout << "感谢试玩!欢迎下次继续!" << endl; return 0; }