我罗斯方块汇报(1)
这个作业属于哪个课程 | 2020年面向对象程序设计 (福州大学 - 数学与计算机科学学院) |
---|---|
这个作业要求在哪里 | 我罗斯方块汇报(1) |
这个作业的目标 | 1. 汇报自己这个阶段的开发进度。(完成了哪几个模块); |
2.讲述自己遇到的问题和尝试解决的方法和最后的结果(解决与否); | |
3.制作一篇开发日记,例子如此,描述自己开发某一个模块的过程。 | |
4.发布博客。 | |
小组成员 | 031902209 赖展业 |
031902239 林雨欣 | |
031902213 林志锋 | |
GitHub地址 | https://github.com/1355158565/- |
其它参考文献 | srand和rank函数的区别与用法,控制台操作字体颜色 |
开发进度
方块类:已经完成了方块的初始化,以及方块随机产生原理,但对于画方块和方块的旋转以及移动问题还有待研究。
渲染类:对于画界面有了基本概念,通过了解控制台改变字体颜色方法后也懂了更改字体颜色,其他的还尚未学会。
玩家类:还没弄懂如何双线操作。
游戏类:暂时没想法。
开发日志
由简入奢,首先先对比较简单的方块类进行研究,先对方块进行初始化。
方块的初始化
class Block
{
public:
int block[4][4]; // 格子大小
int blocks[8][4][4];
int x; // 横坐标,以左上角为标志位
int y; // 纵坐标,以左上角为标志位
int type; // 方块类型
int director; // 旋转方向 0向左,1向右
/* 设置方块属性 */
void set(int a, int b, int c) //a,b,c分别代表x,y坐标以及获得的方块类型
{
x = a;
y = b;
if(c != -1)
{
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
block[i][j] = blocks[c][i][j];
type = c;
director = 0;
}
}
void initial()
{
for(int i = 0; i < 7; i++)
for(int j = 0; j < 4; j++)
for(int k = 0; k < 4; k++)
blocks[i][j][k] = 0;
blocks[0][1][0] = blocks[1][1][1] = blocks[1][1][2] = blocks[1][1][3] = 1; //长条
blocks[1][0][0] = blocks[2][0][1] = blocks[2][1][1] = blocks[2][2][1] = 1; //七左
blocks[2][0][1] = blocks[3][0][2] = blocks[3][1][1] = blocks[3][2][1] = 1; //七右
blocks[3][0][1] = blocks[4][1][0] = blocks[4][1][1] = blocks[4][2][1] = 1; //土字形
blocks[4][1][1] = blocks[5][1][2] = blocks[5][2][1] = blocks[5][2][2] = 1; //田字
blocks[5][0][0] = blocks[6][0][1] = blocks[6][1][1] = blocks[6][1][2] = 1; //Z左
blocks[6][0][2] = blocks[7][0][1] = blocks[7][1][1] = blocks[7][1][0] = 1; //Z右
}
};
我们的想法是采用4*4的网格存放一个俄罗斯方块,并且统一一个初始方向。基础方块类型中田字形无论是否旋转,结果都是相同的。blocks三维数组的第一维是方块基础类型编号,二维和三维共同组成方块的形状,由此可以很方便地定义出其中基础类型的方块。使用二维网格可以对block矩阵和map矩阵进行运算。x,y作为矩阵的偏移量。因此可以由此得出block的方阵处在地图中的什么位置,这为后续的计算做好铺垫。
关于画方块的一些想法
在考虑方块绘制位置的问题时,通过网络查阅资料得到以下信息:4*4网格中,标记为1的位置打出正方形实心方块,标记为0的位置则为空白。这样就可以绘制出对应不同类型的方块。因此该block类中的initial函数先使用三层的for循环初始化三维数组。一维为方块类型,在需要绘制方块的地方赋值为1作为标记,用于判断方块打印位置。
随机生成方块的问题
这里随机产生方块的问题可以和使对手产生一行随机的方块是一起的,我们上网查阅了资料明白随机数的产生要靠随机数函数rank(),后来通过资料发现:因为rand的内部实现是用线性同余法做的,他不是真的随机数,只不过是因为其周期特别长,所以有一定的范围里可看成是随机的,rand()会返回一随机数值,范围在0至RAND_MAX 间。在调用此函数产生随机数前,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。rand()产生的是假随机数字,每次执行时是相同的。若要不同,以不同的值来初始化它.初始化的函数就是srand()。
因此我们可以设置RAND_MAX为6,即可随机生成06的数字,并传递到方块初始化类中,生成相对应的方块类型,即利用函数```srand((int)time(0));```和```rank()%6。同理可得将范围设置成01,即可使对方的方块增加随机的一行。但具体还未实施。
界面的显示
#define FACE_X 29
#define FACE_Y 20 //界面尺寸
void inter_face()//界面
{ int i,j;
for(i=0;i<FACE_X;i++)
{ for(j=0;j<FACE_Y+10;j++)
{ if(j==0 || j==FACE_Y-1 || j==FACE_Y+9)
{ face.data[i][j]=Wall;
gotoxy(i,2*j);
printf("■");
}
else if(i==FACE_X-1)
{ face.data[i][j]=Box;
gotoxy(i,2*j);
printf("■");
}
else
face.data[i][j]=Kong;
}
}
gotoxy(FACE_X-18,2*FACE_Y+2);
printf("左移:←");
gotoxy(FACE_X-16,2*FACE_Y+2);
printf("右移:→");
gotoxy(FACE_X-14,2*FACE_Y+2);
printf("旋转:space");
gotoxy(FACE_X-12,2*FACE_Y+2);
printf("暂停: S");
gotoxy(FACE_X-10,2*FACE_Y+2);
printf("退出: ESC");
gotoxy(FACE_X-8,2*FACE_Y+2);
printf("重新开始:R");
gotoxy(FACE_X-6,2*FACE_Y+2);
printf("分数:%d",grade);
}
void gotoxy(int x,int y) //移动坐标
{
COORD coord;
coord.X=y;
coord.Y=x;
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), coord );
}
界面调整问题:想将单人界面改为双人界面,通过更改几个函数的值总有一些错误的产生,要不是界面发生变形就是缺少了部分,通过一些分析后还是没能够解决这个问题,但是已经初有头绪,再经过一段时间应该能够成功。
提出疑问
1.在定义Block类时,为了方便类外部获取该类中的成员数据,将所有数据都设置为公有的,但面向对象程序设计讲求程序的封装性,信息的隐蔽性,这样的定义虽然能够方便程序的完成,但是似乎又违背了封装性的原则,但这个问题又该如何解决?
2.对于方块的移动问题,假如我们向左移动一列,那么我们应该删除右边那一列的俄罗斯方块本身,然后将整个俄罗斯方块一列一列地不断地向左替换。新到达的左边一列复制右边一列的俄罗斯方块,这里我们复制的是俄罗斯方块本身的块,也就是说我们还要检查每个点是否是俄罗斯方块本身,这样的操作在这种地图与方块融合的方式实现起来极其复杂,不知道有没有简便的实现方法。
3.如何处理俄罗斯方块的边界问题?
针对这个问题目前的想法即在当前操作的方块在进行按键操作的时候加以判断下面执行的动作是否会使当前方块超出边界。另外还要考虑到底部边界还要解决方块自动下落的情况。
4.如何将障碍物在满行后进行消除?
这个问题在考虑时要考虑到位于更下面的行在消除后,怎样使上面的行向下移动以填充下面消除的行。
5.如何在方块下降到底部边界后让其成为障碍物?
制作这个游戏要注意到该游戏方块操作时边界不单单是左右边界以及底部,方块落底后怎样判断方块是障碍物?没有方块存在时,直接落到底部,而有方块阻挡时,要让方块停在方块上面。所以这个问题的核心是如何记录已有方块的位置?
6.按下键方块下落速度加快,如何实现?
通过查阅资料,方块下落速度即setInterval的运行间隔。但setInterval要怎么实现?此外,网络资料提到,无论在这个函数内部还是外部修改speed的值都只能在清空时间间隔后才能生效,无法满足需求。资料的内容大致意思还未揣测明白,还需要进一步的讨论。
7.按键后,是否会发生重复触发按键功能的问题?
举个例子当按住下键时,下落速度会不会持续变大?当前查阅资料得到的一个做法是设置一个标记变量,增加if条件句。按键后标记变量的值发生改变,当keyup事件触发时,标记变量才会变成原值。