OpenGL实现俄罗斯方块
一、设计思路
本程序采用以C++为基础并利用OpenGl库函数的方式实现俄罗斯方块程序,实现俄罗斯方块中正方形,T形,L形,反L形,直线型,Z字形,反Z字形七种形状的变换操作,七种形状的坐标被存储在一个三维数组中,每次随机选择一个形状生成并下落,在下落过程中监听键盘事件。
二、详细设计说明
本程序中主要的函数及其作用说明如下:
down:定时下落函数,由glutTimerFunc(1000,down,1);函数设置每隔1000毫秒即调用一次该函数,在函数中将方块的所有纵坐标减一个单位。
key:键盘事件监听函数,当键盘上有按键被触发的时候即调用该函数,函数内部支持w,a,s,d四个键的响应,依次代表方向键上,左,右,下,其中w键是用来
控制图形变换的,每次按w键时,图形在现有基础上顺时针变换一次。
CheckConflict:冲突检测函数,检测方块下一次将要移动的位置是否会碰到已有的方块或者左右两边的墙壁。
CheckDelete:每一次方块落到底部之后,调用该函数检查是否有满行,如果有则调用Delete函数删除该行。
myDisplay1:作图函数。
Change:变换函数,主要是通过计算变换后的图形与之前图形的坐标关系来实现。
三、源代码
#include
#include
#include
#include
#include
using namespace std;
#define LEFT 'a'
#define RIGHT 'd'
#define UP 'w'
#define DOWN 's'
#define START 0//定义图形的范围
#define END 19
#define SIZE 25
/*
*初始化七个二维数组,即七个块刚开始产生时出现的位置
*这里需要考虑的情况是:刚开始产生时有的方块还只露出来一部分,
*如果这个时候按了UP键进行变换应该怎么处理
*本程序最初设计并不考虑这个问题,一开始即画出方块的各个部分,以后再考虑完善的事情
*另外,记录坐标的顺序为从左至右,从上至下
*/
GLfloat b[][5][3]={
{{0.0f,0.9f},{0.0f,0.8f},{0.0f,0.7f},{0.0f,0.6f}},//1、记录长条四个坐标
{{-0.1f,0.9f},{0.0f,0.9f},{-0.1f,0.8f},{0.0f,0.8f}},//2、记录正方形
{{-0.1f,0.9f},{-0.2f,0.8f},{-0.1f,0.8f},{0.0f,0.8f}},//3、T字形
{{-0.1f,0.9f},{0.0f,0.9f},{0.0f,0.8f},{0.1f,0.8f}},//4、记录Z字形
{{-0.1f,0.9f},{0.0f,0.9f},{-0.2f,0.8f},{-0.1f,0.8f}},//5、记录倒Z字形
{{-0.1f,0.9f},{-0.1f,0.8f},{-0.1f,0.7f},{0.0f,0.7f}},//6、记录L字形
{{0.0f,0.9f},{0.0f,0.8f},{-0.1f,0.7f},{0.0f,0.7f}},//7、记录倒L字形};
GLfloat curLoc[5][3];
GLint currentBlock=2;//记录当前正在下落的是第几种方块,顺序如上面所示
GLint turn[7]={0};//应该变换成第几种形态了
GLfloat xd=0.0f,yd=0.0f;
/*
这里定义的over是用来判断方块是否到达了不能再往下降的地方,到了则置
其为true,否则就修改为false。
其中有这样几种情况需要修改over:
1、重新生成了一个方块,修改over=false
2、方块到大底部,修改over=true
*/
bool over=false;
//记录游戏是否结束
bool end=false;
int score=0;
//设置一个锁,在下降操作时不允许变换,在变换时不允许下降操作,否则将会产生资源竞争
//int lock=1;
/*
定义一个20*20的矩阵来记录当前整个画面中各个小格子的情况,可用来消除满格行
矩阵的存储顺序为从左到右,从下到上,包含下标0
BLOCK[i][j]中i对应的是纵坐标,j对应的是横坐标(这个有点痛苦),但是在消去满
格
的时候还是不变,只是在用b数组给其赋值时需要反过来
*/
GLint BLOCK[SIZE][SIZE];
void down(int id);
void InitBLOCK();
void Change();
void CheckDelete();
int CheckConflict(int lef_rig=0);
void CreateBlocks();
void myDisplay1();
void key(unsigned char k,int x,int y);
void Delete(bool *empty);
void show();
void show()
{
int i,j;
for(i=0;i<4;i++) //函数调用的顺序对错误有一定的影响
for(j=0;j<2;j++)
{
cout< } cout< } /* 初始化方块矩阵,方块是一个上端开口的长方形 */ void InitBLOCK() { int i,j; for(i=0;i for(j=0;j BLOCK[i][j]=0; for(i=0;i BLOCK[0][i]=1; for(i=0;i<4;i++) for(j=0;j<2;j++) curLoc[i][j]=b[currentBlock][i][j]; } void Change()//将图形做变换,采用顺时针旋转的规律(下面的工作即是填入坐标) { GLfloat temp00=curLoc[0][0]; GLfloat temp01=curLoc[0][1]; GLfloat temp10=curLoc[1][0]; GLfloat temp11=curLoc[1][1]; GLfloat temp20=curLoc[2][0]; GLfloat temp21=curLoc[2][1]; GLfloat temp30=curLoc[3][0]; GLfloat temp31=curLoc[3][1]; switch(currentBlock) { case 0://长条 switch(turn[0]) { case 0: curLoc[0][0]=temp10-0.1f; curLoc[0][1]=temp11; curLoc[2][0]=temp10+0.1f; curLoc[2][1]=temp11; curLoc[3][0]=temp10+0.2f; curLoc[3][1]=temp11; break; case 1: curLoc[0][0]=temp10; curLoc[0][1]=temp11+0.1f; curLoc[2][0]=temp10; curLoc[2][1]=temp11-0.1f; curLoc[3][0]=temp10; curLoc[3][1]=temp11-0.2f; break; } turn[0]=(turn[0]+1)%2; break; case 1://正方形 break; case 2://T字形 //cout<<"turn[2]="< switch(turn[2]) { case 0: curLoc[1][0]=temp20; curLoc[1][1]=temp21; curLoc[2][0]=temp30; curLoc[2][1]=temp31; curLoc[3][0]=temp20; curLoc[3][1]=temp21-0.1f; break; case 1: curLoc[0][0]=temp10-0.1f; curLoc[0][1]=temp11; break; case 2: curLoc[0][0]=temp10; curLoc[0][1]=temp11+0.1f; curLoc[1][0]=temp00; curLoc[1][1]=temp01; curLoc[2][0]=temp10; curLoc[2][1]=temp11; break; case 3: curLoc[3][0]=temp20+0.1f; curLoc[3][1]=temp21; break; } turn[2]=(turn[2]+1)%4; break; case 3://Z字形 switch(turn[3]) { case 0: curLoc[0][0]=temp10+0.1f; curLoc[0][1]=temp11+0.1f; curLoc[2][0]=temp10+0.1f; curLoc[2][1]=temp11; curLoc[3][0]=temp20; curLoc[3][1]=temp21; break; case 1: curLoc[0][0]=temp10-0.1f; curLoc[0][1]=temp11; curLoc[2][0]=temp30; curLoc[2][1]=temp31; curLoc[3][0]=temp30+0.1f; curLoc[3][1]=temp31; break; } turn[3]=(turn[3]+1)%2; break; case 4://反Z字形 switch(turn[4]) { case 0: curLoc[0][0]=temp00-0.1f; curLoc[0][1]=temp01+0.1f; curLoc[1][0]=temp00-0.1f; curLoc[1][1]=temp01; curLoc[2][0]=temp00; curLoc[2][1]=temp01; curLoc[3][0]=temp00; curLoc[3][1]=temp01-0.1f; break; case 1: curLoc[0][0]=temp20; curLoc[0][1]=temp21; curLoc[1][0]=temp20+0.1f; curLoc[1][1]=temp21; curLoc[2][0]=temp10; curLoc[2][1]=temp11-0.1f; break; } turn[4]=(turn[4]+1)%2; break; case 5://L字形 switch(turn[5]) { case 0: curLoc[0][0]=temp10; curLoc[0][1]=temp11; curLoc[1][0]=temp10+0.1f; curLoc[1][1]=temp11; curLoc[2][0]=temp10+0.2f; curLoc[2][1]=temp11; curLoc[3][0]=temp20; curLoc[3][1]=temp21; break; case 1: curLoc[0][0]=temp00; curLoc[0][1]=temp01+0.1f; curLoc[1][0]=temp10; curLoc[1][1]=temp11+0.1f; curLoc[2][0]=temp10; curLoc[2][1]=temp11; curLoc[3][0]=temp10; curLoc[3][1]=temp11-0.1f; break; case 2: curLoc[0][0]=temp20+0.1f; curLoc[0][1]=temp21; curLoc[1][0]=temp20-0.1f; curLoc[1][1]=temp21-0.1f; curLoc[2][0]=temp20; curLoc[2][1]=temp21-0.1f; curLoc[3][0]=temp20+0.1f; curLoc[3][1]=temp21-0.1f; break; case 3: curLoc[0][0]=temp10; curLoc[0][1]=temp11+0.2f; curLoc[1][0]=temp10; curLoc[1][1]=temp11+0.1f; curLoc[2][0]=temp10; curLoc[2][1]=temp11; curLoc[3][0]=temp20; curLoc[3][1]=temp21; break; } turn[5]=(turn[5]+1)%4; break; case 6://反L字形 switch(turn[6]) { case 0: curLoc[0][0]=temp20-0.1f; curLoc[0][1]=temp21+0.1f; curLoc[1][0]=temp20-0.1f; curLoc[1][1]=temp21; break; case 1: curLoc[0][0]=temp00+0.1f; curLoc[0][1]=temp01+0.1f; curLoc[1][0]=temp30; curLoc[1][1]=temp31+0.2f; curLoc[2][0]=temp00+0.1f; curLoc[2][1]=temp01; curLoc[3][0]=temp20; curLoc[3][1]=temp21; break; case 2: curLoc[0][0]=temp00-0.1f; curLoc[0][1]=temp01-0.1f; curLoc[1][0]=temp20; curLoc[1][1]=temp21; curLoc[2][0]=temp20+0.1f; curLoc[2][1]=temp21; curLoc[3][0]=temp30+0.1f; curLoc[3][1]=temp31; break; case 3: curLoc[0][0]=temp20; curLoc[0][1]=temp21+0.1f; curLoc[1][0]=temp20; curLoc[1][1]=temp21; curLoc[2][0]=temp30-0.1f; curLoc[2][1]=temp31; curLoc[3][0]=temp30; curLoc[3][1]=temp31; break; } turn[6]=(turn[6]+1)%4; break; } //如果旋转非法(即旋转时碰到墙壁了),则要恢复原来的状态 int ret; ret=CheckConflict(); if(ret == 1) { curLoc[0][0]=temp00; curLoc[0][1]=temp01; curLoc[1][0]=temp10; curLoc[1][1]=temp11; curLoc[2][0]=temp20; curLoc[2][1]=temp21; curLoc[3][0]=temp30; curLoc[3][1]=temp31; } } /* 消除满格的一行,在每次over被修改为true的时候都要检查一遍 算法思想是从第0行开始依次判断,如果empty为true则将下面的向上,并不是判断一次就移动所有的,而是只移动最近的,将空出来的 那一行的empty标记为true void Delete(int *empty) { int i,j; int pos; while(1) //将上面非空的行填补到下面的空行中 { i=1; while(i < 20&&empty[i] == 0) //为空或者满,都需要将上面的行移下来填充 { i++; } if(i >= 20) break; j=i+1; while(j < 20&&empty[j] == -1) j++; if(j >= 20) break; if(j < 20&&empty[j] != -1) { for(pos=0;pos<20;pos++) BLOCK[i][pos]=BLOCK[j][pos]; empty[i]=empty[j]; empty[j]=-1; } } for(i=1;i<20;i++) if(empty[i] != 0) { for(j=0;j<20;j++) BLOCK[i][j]=0; } } /* *1、判断新生成的图形是否和原来的图形有冲突,有则不能更改,这个地方比较不好实现 *2、判断是否有满格的行,有则调用Delete函数去掉 *3、这里似乎还要加上判断是否到大顶部,如果到达顶部则游戏结束(可采用监视方框最上 *面一行之上那行里面有没有方格,如果有的话则游戏结束) *结束之后就可以把当前方块存入BLOCK中 *empty表示一行中方块的数目,-1表示为空行,0表示部分为空,1表示满行 */ void CheckDelete()//目前这个函数还只是实现了一个方块到达终点之后是否有能够被删除的行 int i,j; int empty[SIZE]; bool is_needed=false; int count; for(i=0;i empty[i]=-1; for(i=0;i<4;i++) { double x=(curLoc[i][0]+1)*10+0.5; //此处无需注意取值,因为checkConflict已经解决 double y=(curLoc[i][1]+1)*10+0.5; BLOCK[(int)y][(int)x]=1;//融合 } for(i=1;i<20;i++) { count=0; for(j=0;j<20;j++) if(BLOCK[i][j]==1) count++; if(count==20) { empty[i]=1; //若满格,则可以删除,置为true score++; //此处计分 is_needed=true; } else if(count > 0&&count < 20) { empty[i]=0; } } if(is_needed==true)//如果有满行则去删除,否则免之 Delete(empty); } int CheckConflict(int lef_rig) { int i; for(i=0;i<4;i++) { double x=(curLoc[i][0]+1)*10; //注意取值!!! double y=(curLoc[i][1]+1)*10+0.5; //y方向无需注意 x=x>0?(x+0.5):(x-0.5); if(lef_rig == 1) { int tmpx=(int)x; if(tmpx > 19||tmpx < 0) break; } if(BLOCK[(int)y][(int)x]==1) //判断是否发生冲突 { break; } } if(i < 4) return 1; return 0; } /* 关键部分在这里,主要是要判断方块下一次的移动是否合法, 本程序通过对b数组所存储的下标是否在BLOCK数组中已经为1 来判断,这样,只需要在BLOCK的最外层加一圈1,就不用通过 原来的方式来判断方块是否越界 */ void key(unsigned char k,int x,int y) { int i,ret; if(over == false) { if(k==UP)//此处需要改成调用变换图形样式的函数 { Change(); } else if(k==DOWN)//后续还要修改,移动到底部过了一段时间之后就不能左右移动了 { for(i=0;i<4;i++)//需继续添加以1和-1作为哨兵 { curLoc[i][1]-=0.1f; } ret=CheckConflict(); if(ret == 1)//发生冲突,则将修改复原 { for(i=0;i<4;i++) curLoc[i][1]+=0.1f; over=true;//并且可以生成下一个方块了 } } else if(k==RIGHT) { for(i=0;i<4;i++) curLoc[i][0]+=0.1f; ret=CheckConflict(1); if(ret == 1)//发生冲突,则将修改复原 { for(i=0;i<4;i++) curLoc[i][0]-=0.1f; } } else if(k==LEFT) { for(i=0;i<4;i++) curLoc[i][0]-=0.1f; ret=CheckConflict(1); if(ret == 1)//发生冲突,则将修改复原 { for(i=0;i<4;i++) curLoc[i][0]+=0.1f; } } } if(over==true) CheckDelete(); glutPostRedisplay();//调用这个函数可以重新绘图,每次相应消息之后,所有全部重绘} /* 让方块定时下降 */ void down(int id) { int i,ret; if(over!=true) { for(i=0;i<4;i++)//需继续添加以1和-1作为哨兵 { curLoc[i][1]-=0.1f; } ret=CheckConflict(); if(ret == 1)//发生冲突,则将修改复原 { for(i=0;i<4;i++) curLoc[i][1]+=0.1f; if(curLoc[0][1] >= b[currentBlock][0][1]) { cout<<"Game over,your score is:"< exit(1); } over=true;//并且可以生成下一个方块了 } } if(over==true) CheckDelete(); glutPostRedisplay(); glutTimerFunc(1000,down,1); } //作图函数,要修改,利用BLOCK数组绘图 void myDisplay1() { int i,j; glClear(GL_COLOR_BUFFER_BIT); //不能使用深度测试,否则画出来的图形很乱 for(i=0;i<20;i++) { for(j=0;j<20;j++) { if(BLOCK[i][j]==1) { glColor3f(0.0f,1.0f,0.0f); //用蓝色画图 glRectf(j/10.0f-1.0f,i/10.0f-1.0f,j/10.0f-1.0f+0.1f,i/10.0f-1.0f+0.1f); glLineWidth(2.0f); glBegin(GL_LINE_LOOP); glColor3f(0.0f,0.0f,0.0f); glVertex2f(j/10.0f-1.0f,i/10.0f-1.0f); glVertex2f(j/10.0f-1.0f+0.1f,i/10.0f-1.0f); glVertex2f(j/10.0f-1.0f+0.1f,i/10.0f-1.0f+0.1f); glVertex2f(j/10.0f-1.0f,i/10.0f-1.0f+0.1f); glEnd(); glFlush(); } } } if(over == false) { for(i=0;i<4;i++) { glColor3f(0.0f,1.0f,0.0f); //用蓝色画图 glRectf(curLoc[i][0],curLoc[i][1],curLoc[i][0]+0.1f,curLoc[i][1]+0.1f); glLineWidth(2.0f); glBegin(GL_LINE_LOOP); glColor3f(0.0f,0.0f,0.0f); glVertex2f(curLoc[i][0],curLoc[i][1]); glVertex2f(curLoc[i][0]+0.1f,curLoc[i][1]); glVertex2f(curLoc[i][0]+0.1f,curLoc[i][1]+0.1f); glVertex2f(curLoc[i][0],curLoc[i][1]+0.1f); glEnd(); glFlush(); } } glutSwapBuffers(); } /* * 随机生成方块,原理即生成一个7以内的随机数, * 对应的二维数组即为下一个产生的方块 */ void CreateBlocks() { int i,j; myDisplay1(); if(over) { srand(time(NULL)); currentBlock=rand()%7; for(i=0;i<7;i++) //关键之处,每次创建一个新的方块后要将变形的记录清空 turn[i]=0; for(i=0;i<4;i++) for(j=0;j<2;j++) { curLoc[i][j]=b[currentBlock][i][j]; } over=false; glutPostRedisplay(); } } void main(int argc ,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE); glutInitWindowPosition(400,100); glutInitWindowSize(600,600); InitBLOCK(); glutCreateWindow("俄罗斯方块author:parkfang"); glutDisplayFunc(&CreateBlocks); glutTimerFunc(1000,down,1); glutKeyboardFunc(key); glClearColor(1.0f,1.0f,1.0f,1.0f);//用白色清除屏幕glutMainLoop(); } /*学无止境*/ #include void Init(); void Down(); void GoOn(); void ksdown(); void Display(int color); void Give(); int Touch(int x,int y,int dx,int dy); int GeyKey(); void Select(); void DetectFill(); void GetScores(); void Fail(); void Help(); void Quit(); void DrawBox(int x,int y,int Color); void OutTextXY(int x,int y,char *String); void DispScore(int x,int y,char Ch); void DrawNext(int Color); int Heng=12,Shu=20; /*横竖*/ int Position[MAX][MAX]; int middle[MAX][MAX]; int ActH,ActS; 《软件工程与开发实践1》 软件设计报告 题目俄罗斯方块 学院计算机学院 专业计算机科学与技术 班级 学号 10109345 学生姓名 其他成员 组长 指导教师孙志海 完成日期2012年6月 一、软件设计概述(目的、任务、开发环境、参考资料) 俄罗斯方块游戏属于经典小游戏,游戏规则简单,但又不乏趣味。而计算的一大领域也是游戏,所以,成为游戏开发者,几乎是每个编程者的梦想。经过大一和大二的学习,我们已经掌握了编程基础。为了提高我们的编程能力,我们就要不断积累编程经验。 1、目的:复习和巩固C/C++编程的基本思想;掌握数据结构的核心思想;掌握C/C++中多文件的编写;初步对了解界面的设计。 2、任务:完成一个可以运行的游戏。 3、开发环境:C/C++控制台。 4、参考资料: [1] 谭浩强.C语言程序设计[M].北京:清华大学出版社.2004.6 [2] 孙鑫\余安萍.VC++深入详解[M].北京:电子工业出版社.2006.6 二、可行性研究、需求分析及分工 这是一个游戏软件,程序与用户的交流只在游戏界面上,方块的产生是随机的。 三、软件设计的基本原理和采用的主要方法与技术 1、方块类型以下7大类 ██████████ ██████ ███ █████████ 每一种方块都能够变形,所以在游戏中如何正确打印出方块的类型是重点,也是难点。我采用的是“相对坐标法”,具体实现参照“实现的过程与步骤”部分。 2、此游戏是简单的二维游戏,而且区域恒定不变,所以在存储游戏的信息时,二维数组是首选。用数组元素值模拟当前位置有无方块。 3、流程图如下 4、采用的方法 在控制台下,光标是左到右,自上而下的,所以要要调用系统函数来控制光标。同理,为了界面的美观,也要调用系统函数进行颜色控制。 5界面设置 游戏的最大特点就是界面的美观,由此才能吸引玩家的兴趣,因此如何让界面尽最大限度美观,是每个游戏程序员努力的目标。这个程序是在VC环境下基于C/C++控制台的,由于VC下没有像TC下那样丰富的图形库,画图就要调用windows API函数。但由于我对windowsAPI理解不深,所以画起图来还是比较困难。 游戏不仅要求界面美观,而且还要音乐来衬托,所以在整个程序中,尽量让方块的每一个动作与特殊的音乐像对应,此外,最好加上背景音乐。 四、实现的过程与步骤 数据结构: 1、方块的存储 如下图所示,每一种方块都由四个小方块组成,可以按顺序编号①、②、③、④,在方块旋转、输出、擦出时,可以由第一个方块位置加上(减去)第二个与第一个的偏移量,从而找到第二个方块,如此可以方便遍历四个方块。 由于方块属于宽字符,故在占两个字节,输出的时候占两位。设①号块的坐标为(x,y),那么第二块与它的偏移量的△x=2,△y=0,相对坐标即为(2,0)。 同理,③号方块的相对坐标为(2,1),④号方块的坐标为(4,1),特别的,①号方块的相对坐标为(0,0),这样一来,只要知道每一种(7大类,19种)方块的①号方块的坐标,就可以通过②、③、④方块与①号方块的偏移量而逐个输出整个方块。 明白了方块的输出,就要用一个数据结构存储方块了。19种方块都由4个 #include 【转载】88行代码实现俄罗斯方块游戏(含讲解) 来源:https://www.wendangku.net/doc/ce7766407.html,/p/8 在正式阅读本文之前,请你记得你应该用娱乐的心态来看, 本代码所使用到的技巧,在工作了的人眼里会觉得很纠结,很蛋疼,很不可理喻,很丑, 注意,是你蛋疼,不关我的事 通常,写一个俄罗斯方块,往往动不动就几百行,甚至上千行,而这里只有88行 正所谓头脑风暴,打破常规。这里将使用很多不平常的手段来减少代码 以下是Win-TC可以成功编译并执行的代码(代码保证单行长度不超过80字符,如果你是Win7系统,那请看后文): 程序代码: #include"graphics.h" #include 软件需求规格说明书 1306401-35 王正 一、引言 1.1编写目的 通过本游戏的设计,综合自己在校期间所学的理论知识,设计开发俄罗斯广场游戏,使自己熟应用系统的开发过程,培养独立思考能力,检验学习效果和动手能力,初步掌握软件工程的系统理论,进一步巩固和加强自身对编程语言知识的理解,提高自己的编程水平,从而达到理论与实践相结合的目的。 1.2项目背景 游戏是人们活动中一项非常重要的内容,有人认为如果哪一天人类对所有的游戏都失去兴趣,恐怕世界的末日就要到了。电脑对游戏的贡献有目共睹,现在摸索电脑的人很少没玩过电脑游戏的,喜欢游戏的人也很少不玩电脑的。 俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,它曾经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。俄罗斯方块最早还是出现在PC机上,而我国的用户都是通过红白机了解、喜欢上它的。随着计算机的发展而发展,俄罗斯方块不断推陈出新,深爱广大玩家喜爱。这个游戏有的简单,有的复杂,但其根本原理是一样的都是对运动的方块进行组合, 来训练玩家的反应能力。因此开发此游戏软件可满足人们的一些娱乐的需求。 此俄罗斯方块游戏可以为用户提供一个可在普通个人电脑上运行的,界面美观的,易于控制的俄罗斯方块游戏。 此次需要开发一项软件,在通过认真的考虑之后,决定做一个“俄罗斯方块”,对于我个人来说,这是一个相当具有挑战性的任务,也是一次不错的锻炼机会。 1.3定义 (1)游戏区:玩家可以在游戏区中堆积方块,并能够在游戏过程中随时了解得分情况。 (2)游戏控制:玩家可以通过游戏控制功能来选择开始新的一局游戏,暂停或退出游戏。 (3)级别设置:玩家可以根据自己的需要自行设定游戏的开始级别,级别越高,游戏的速度越快,难度越大。 1.4参考资料 [1]朱福喜著,JAVA程序设计技巧与开发实例[M] 北京:人民邮电出版社,2004.2 [2] 张海藩软件工程(第五版) 北京:清华大学出版社,2008 为你解惑之WPF经典9问详解 第0问:能否简单介绍一下本文的结构? 本文解答了关于WPF的9个最常见的问题。从某种意义上讲,这两种技术是相互关联的:它们都是关于界面表现的技术,更进一步的,Silverlight是基于WPF的,是它的一个子集。不仅从理论上介绍了这两种技术,同时还提供了一些小的例子供大家参考。 第1问:我们已经有了GDI、GDI+和DirectX,为什么我们还需要WPF呢? 图1从User32到WPF的发展历程 首先,让我们来回顾一下微软的各种界面显示技术: User32:它提供了最基本的Windows界面,包括按钮,编辑框和其他UI元素。但是,User32缺乏的是图形图像的绘制功能,无法对屏幕实现自定义的绘制。 GDI(Graphics device interface):-为了提供图形图像的绘制功能,微软在User32的基础上引入了GDI。GDI不仅提供了图形图像的绘制功能,同时还对硬件显示进行了更高层次的抽象。换句话说,它将硬件的复杂性封装在了GDI API 中,用户使用起来更加方便。 GDI+:顾名思义,GDI+是作为GDI的扩展而被引入到Windows中的。它提供了很多GDI所没有的扩展功能,例如对JPG和PNG图像格式支持,渐变阴影和抗锯齿等。无论是GDI还是GDI+,它们最大的局限就是不支持硬件加速,同时无法展现动画和3D图像。 提示:所谓硬件加速,就是使用硬件来执行某些功能,以替代使用软件在CPU 中执行的某些功能,因为直接使用硬件,这样可以显著地加快图形图像处理的速度。 DirectX:正如我们在上面所分析的那样,GDI及其扩展GDI+的一个最大问题就是不支持硬件加速和动画。这对于游戏开发者来说,是无法接受的。为了解决这个问题,微软开发了DirectX。DirectX能够很好的利用硬件加速,能够支持3D,全彩图像,流媒体等等,非常适合游戏工业等对图形图像处理要求比较高的领域。 WPF:微软已经有了这么多套关于显示技术的API,为什么还要多此一举,创建另外一套显示技术的API呢?通过对硬件加速的支持,DirectX已经有了很多非常棒的特性。微软想利用支持硬件加速的DirectX技术来开发UI元素,比如文本框,按钮,网格等等,所以他们又在DirectX的基础上开发了WPF。因为WPF 是在DirectX的基础上实现的,所以你不仅可以利用WPF创建简单的UI元素,还可以更进一步,开发特殊的UI元素,例如网格(Grid),流文档(FlowDocument)和椭圆(Ellipse)等。 更进一步地,你还可以利用WPF创建动画。如果你在寻找用于创建轻量级动画(不是游戏中所使用的那种复杂三维动画)的技术方案,WPF将是一个不错的选择。你可以使用被称为XAML的XML文件来表现WPF。 图2WPF和DirectX的关系 简单的讲,WPF就是DirectX之上的一层包装。所以,我们可以这样定义WPF: WPF是一套用于简便地构建动态用户界面的类的集合。这些类包括了一套新的界面控件。其中有些控件跟旧有的UI元素是相似的,例如标签,文本框和按钮等,而另外一些控件则是全新的,例如,网格(Grid),流文档(FlowDocument)和椭圆(Ellipse)等。 1、新建“.h”头文件,将“头文件” 代码粘贴至其中, 2、新建“.c”源文件,将“源代码” 代码粘贴到其中。 3、新建空白工程,将头文件和源代码 添加进去,调试使用。 //头文件 //1.自定义枚举类型,定义7种形态的游戏方块 typedef enum tetris_shape { ZShape=0, SShape, LineShape, TShape, SquareShape, LShape, MirroredLShape }shape; //2.函数声明 //(1)操作方块函数 int maxX();//取得当前方块的最大x坐标 int minX();//取得当前方块的最小x坐标 void turn_left();//当前方块逆时针旋转90度 void turn_right(); int out_of_table(); void transform(); int leftable(); int rightable(); int downable(); void move_left(); void move_right(); //(2)操作游戏桌面的函数 int add_to_table(); void remove_full(); //(3)控制游戏函数 void new_game(); void run_game(); void next_shape(); int random(int seed); //(4)绘图函数 void paint(); void draw_table(); //(5)其他功能函数 void key_down(WPARAM wParam); void resize(); void initialize(); void finalize(); //(6)回调函数,用来处理Windows消息 LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM); //源代码 //1.文件包含 #include 注意:本源代码包含 课程设计说明书 课程名称:高级语言程序设计 设计题目:俄罗斯方块游戏 院部:计算机科学与信息工程学院 学生姓名: 学号: 专业班级:物联网工程 指导教师: 2015年6月 课程设计任务书 目录 一前言 (4) 二需求分析 (4) 三概要设计 (5) 四详细设计 (7) 五改进或增加功能模块说明 (8) 六程序测试 (8) 七课程设计总结 (11) 八致谢 (11) 九参考文献 (12) 十源程序 (12) 俄罗斯方块游戏 一前言 C++程序设计牵涉到面向对象程序设计的理论、C++语言的语法以及算法等3个方面的内容,其中每一方面都包含十分丰富的内容,都可以分别单独成论。显然在一个程序中深入、详细地介绍以上3个方面的知识是不可能的,必须把它们有机地结合起来,综合应用。不同的书对此采取不同的写法,侧重点有所不同,各有道理,也各有优缺点,适合于不同的读者。需要在教学实践中检验,取长补短,不断完善。 作者认为:要进行C++程序设计当然需要了解面向对象程序设计的有关概念,但是本课程毕竟不是一门面向对象程序设计的理论课程,在本书中不是抽象地介绍面向对象程序设计的理论,而是在介绍C++语言的特点和应用过程中自然地引出面向对象程序设计的有关概念,通过C++的编程过程理解面向对象程序设计方法。在介绍程序设计过程中,介绍有关的算法,引导读者思考怎样构造一个算法。编写程序的过程就是设计算法的过程。 要用C++编程序,最基本的要求是正确掌握和运用C++。由于C++语法复杂,内容又多,如果对它缺乏系统的了解,将难以真正应用,编出来的程序将会错误百出,编译出错,事倍功半。本书的做法是全面而系统地介绍C++的主要特点和功能,引导读者由简而繁地学会编写C++程序。有了C++编程的初步基础后,再进一步提高,掌握更多更深入的算法。这样的方法可能符合大多数学习者的情况,降低了学习难度。 程序设计是一门实践性很强的课程,只靠听课和看书是学不好的。衡量学习好坏的标准不是“懂不懂”,而是“会不会干”。因此必须强调多编程,多上机实践。考虑到不同学校、不同专业、不同读者对学习C++有不同的要求。 二需求分析 1 要求 (1)用C语言实现程序设计; 1. using System; using System.Collections.Generic; using System.Text; using System.Drawing;//add namespace俄罗斯方块 { public class Block { private short width; private short height; private short top; private short left; private int ID; //方块部件的ID public int[,] shape;//存储方块部件的形状,0为空白,1为有砖块 public Block()//构造函数 { Random randomGenerator = new Random(); int randomBlock = randomGenerator.Next(1, 6);//产生1—4的数 this.ID = randomBlock; switch (this.ID) { case 1: //横条形 this.Width = 4; this.Height = 1; this.Top = 0; this.Left = 3; shape = new int[this.Width, this.Height]; shape[0, 0] = 1; shape[1, 0] = 1; shape[2, 0] = 1; shape[3, 0] = 1; break; case 2://正方形 this.Width = 2; this.Height = 2; this.Top = 0; this.Left = 4; // Creates the new shape for this block. shape = new int[this.Width, this.Height]; shape[0, 0] = 1; shape[0, 1] = 1; shape[1, 0] = 1;shape[1, 1] = 1; break; case 3://T形 this.Width = 3; this.Height = 3; this.Top = 0; this.Left = 4; // Creates the new shape for this block. shape = new int[this.Width, this.Height]; shape[0, 0] = 1; shape[1, 0] = 1; shape[2, 0] = 1; shape[1, 1] = 1; shape[1, 2] = 1; break; case 4://L形 this.Width = 2; this.Height = 3; this.Top = 0; this.Left = 4; 2018年甘肃省平凉市中考化学试题 可能用到的相对原子质量:H:l C:12 O:16 Na:23 Cl:35.5 一、选择(本题包括10小題,每小题2分,共20分。每小题只有一个选项符合题意) 1. 分类是学习化学的重要方法。下列物质属于氧化物的是() A. O2 B. H 2 O C. KCl D. H2SO4 【答案】B 【解析】O2是由一种元素组成,属于单质,氧化物属于化合物;H2 O是由氧元素和氢元素组成的化合物,属于氧化物; KCl中没有氧元素,不属于氧化物;H2SO4是由三种元素组成,不属于氧化物。故选B。 2. 膳食中营养搭配有利于人体。下列食品含维生素相对较多的是() A.奶油蛋糕 B.碱面馒头C.凉拌黄瓜 D.清蒸鲈鱼 【答案】C 【解析】奶油蛋糕中富含油脂、蛋白质、糖类;碱面馒头中富含糖类;凉拌黄瓜中富含维生 素;清蒸鲈鱼中富含蛋白质。故选C。 3. 党的十九大提出要加快生态文明体制改革,建设美丽中国。下列做法正确的是() A. 为保护环境,把废旧电池深埋处理 B. 为增加粮食产量,大量使用农药、化肥 C. 为节约水资源,用工业废水直接灌溉农田 D. 为节约资源,大力开发新能源替代化石然料 【答案】D 【解析】将废旧电池深埋处理会污染土壤和地下水;适量使用农药、化肥可以增加粮食产量,大量使用农药、化肥,会污染环境;不用工业废水直接灌溉农田,会对农作物造成伤害;大 力开发新能源替代化石然料,可以节约资源,保护环境。故选D。 4. 下列生用品使用的材料属于有机合成材料的是() 【答案】A 【解析】塑料保鲜膜属于有机合成材料;纯棉毛巾是用棉线制成的,属于天然材料;真丝围 巾是用蚕丝制成的,属于天然材料;不锈钢锅是用不锈钢制成的,属于金属材料。故选A。 5. 化学实验操作的规范性、安全性是实验成败的关継,同时也反映了实验者的化学素养。 下列如图所示的实验操作正确的是() 【答案】D 【解析】过滤液体时,要用玻璃棒引流、漏斗下端没有紧靠在烧杯内壁上;木炭燃烧生成物是二氧化碳气体,集气瓶中的气压不减小,不能形成气压差,水不会进入集气瓶中,不能测 定出氧气的含量;用pH试纸测定溶液的pH时,不能将试纸直接伸入待测液中,要用玻璃棒蘸取待测液或胶头滴管滴加在试纸上,然后将试纸显示的颜色与标准比色卡对照;稀释浓硫酸时,要将浓硫酸沿器壁慢慢倒入水中,要用玻璃棒不断搅拌,以防液体沸腾溅出伤人。故 选D。 6. 元素观、微粒观是化学的重要观念。下列有关元素和微粒的说法不正确的是() A. 分子、原子和离子都是成物质的粒子 B. 同种元素的原子核内质子数与中子数一定相等 C. 元素的原子序数与该元素原子核电荷数在数值上相同 D. 在物质发生化学变化时,原子的种类不变,元素的种类也不会改变 【答案】B 【解析】分子、原子和离子都是成物质的粒子;质子数决定元素的种类,即同种元素的质子 数一定相等,中子数不一定相等;元素周期表是按照原子序数依次增多的顺序排列起来的, 原子序数即原子核电荷数=质子数=核外电子数;在物质发生化学变化时,原子的种类不变, 元素的种类也不会改变。故选B。 //不多说,直接可以拷贝下面的东西,就可以运行。 package day04; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.applet.*; import https://www.wendangku.net/doc/ce7766407.html,ng.String.*; import https://www.wendangku.net/doc/ce7766407.html,ng.*; import java.io.*; public class ERSBlock extends JPanel implements ActionListener,KeyListener//应该是继承JPanel { static Button but[] = new Button[6]; static Button noStop = new Button("取消暂停"); static Label scoreLab = new Label("分数:"); static Label infoLab = new Label("提示:"); static Label speedLab = new Label("级数:"); static Label scoreTex = new Label("0"); static Label infoTex = new Label(" "); static Label speedTex = new Label("1"); static JFrame jf = new JFrame(); static MyTimer timer; static ImageIcon icon=new ImageIcon("resource/Block.jpg"); static JMenuBar mb = new JMenuBar(); static JMenu menu0 = new JMenu("游戏 "); static JMenu menu1 = new JMenu("帮助 "); static JMenuItem mi0 = new JMenuItem("新游戏"); static JMenuItem mi1 = new JMenuItem("退出"); static JMenuItem mi1_0 = new JMenuItem("关于"); static JDialog dlg_1; static JTextArea dlg_1_text = new JTextArea(); static int startSign= 0;//游戏开始标志 0 未开始 1 开始 2 暂停 static String butLab[] = {"开始游戏","重新开始","降低级数","提高级数","游戏暂停","退出游戏"}; static int game_body[][] = new int[19][10]; static int game_sign_x[] = new int[4];//用于记录4个方格的水平位置 static int game_sign_y[] = new int[4];//用于记录4个方格的垂直位置 C语言课程设计报告 俄罗斯方块程序设计报告 一、问题描述 俄罗斯方块(Tetris,俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏,它由俄罗斯人阿列克谢·帕基特诺夫发明,故得此名。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。 在本次设计中,要求支持键盘操作和若干种不同类型方块的旋转变换,并且界面上显示下一个方块的提示以及当前的玩家的得分,随着游戏的进行,等级越高,游戏难度越大,即方块的下落速度越快,相应的等级,等级越高,为玩家提供了不同的选择。 二、功能分析 I、俄罗斯方块游戏需要解决的问题包括: ⑴、随机产生方块并自动下移 ⑵、用Esc键退出游戏 ⑶、用键变体 ⑷、用键和键左右移动方块 ⑸、用空格键使游戏暂停 ⑹、能正确判断满行并消行、计分、定级别 ⑺、设定游戏为不同级别,级别越高难度越大 II、俄罗斯方块游戏需要设计的功能函数包括: ⑴、声明俄罗斯方块的结构体 ⑵、函数原型声明 ⑶、制作游戏窗口 ⑷、制作俄罗斯方块 ⑸、判断是否可动 ⑹、随机产生俄罗斯方块类型的序号 ⑺、打印俄罗斯方块 ⑻、清除俄罗斯方块的痕迹 ⑼、判断是否满行并删除满行的俄罗斯方块 三、程序设计 1、程序总体结构设计 (1)、游戏方块预览功能。在游戏过程中,游戏界面右侧会有预览区。由于在此游戏中存在多种不同的游戏方块,所以在游戏方块预览区域中显示随机生成的游戏方块有利于游戏玩家控制游戏的策略。 (2)、游戏方块控制功能。通过各种条件的判断,实现对游戏方块的左移、右移、自由下落、旋转功能,以及行满消除行的功能。 (3)、游戏数据显示功能。在游戏玩家进行游戏过程中,需要按照一定的游戏规则给玩家计算游戏分数。例如,消除一行加100分,游戏分数达到一定数量 //包含头文件 #include 口口口口口口口口 口口口口口口口口 */ {0x0660, 0x0660, 0x0660, 0x0660, BLUE}, /* 口 口口口口口口口 口口口口口口口 口*/ {0x4460, 0x02E0, 0x0622, 0x0740, MAGENTA}, /* 口 口口口口口口口 口口口口口口口 口*/ {0x2260, 0x0E20, 0x0644, 0x0470, YELLOW}, /* 口口 口口口口口口口口 口口口口口口 */ {0x0C60, 0x2640, 0x0C60, 0x2640, CYAN}, /* 口口 口口口口口口口口 口口口口口口 */ {0x0360, 0x4620, 0x0360, 0x4620, GREEN}, /* 口口口 口口口口口口口口口口 口口口 */ {0x4E00, 0x4C40, 0x0E40, 0x4640, BROWN}}; /* //定义俄罗斯方块的信息的结构体 struct blockinfo { int id; //7中方块中的哪一种 byte dir:2; //1种方块中四个方向中的哪个 char x,y; //方块的坐标(不是屏幕中的而是自己设置的游戏区域中的)} curblock,nextblock; */ // 定义游戏区 //unsigned char area[width][high] = {0}; //函数声明 其中的主要逻辑有: (1)由于c的随机性函数不好,所以每次游戏开始根据bios时间设置种子。 (2)得分越高,方块下降速度越快(每200分为单位)。 (3)每下落一个方块加1分,每消除一行加10分,两行加30分,三行加70分,四行加150分。初试分数为100分。 游戏控制: up-旋转;空格-下落到底;左右下方向键-控制方向。P-开始或暂停游戏。ESC-退出。 特点: (1)由于tc不支持中文,所以基本都是英文注释。 (2)函数命名尽可能规范的表达其内部处理目的和过程。 (3)代码加上注释仅有577行。(我下载过的两个俄罗斯方块代码一个在1087行,一个在993行,我的比它们代码少)。 (4)除了消除空格时算法比较复杂,其他算法都比较简单易读。 (5)绘图效率和局部代码效率扔有待提高。 (6)FrameTime参数可能依据不同硬件环境进行具体设置,InitGame需要正确的TC路径。 俄罗斯方块源于大约9年前上大一时的一个梦,我们在学习c语言时,我的同寝室友邀请我合作一起完成俄罗斯方块(课外作业性质),但是当时限于我们的水平比较菜和学习状态比较懒散,我们没有完成。大一的时候我在机房里无意发现别人留下的俄罗斯方块程序,运行,老师发现后激动的问我是我写的吗,我惭愧的摇摇头。那时看到别人做c的大程序深感羡慕(自己只是写几十行的程序)。数年后我仍然看到有不同样式的实现,但是我一直没有实现它,知道今天忽然有这个想法去做,算是弥补多年前的遗憾和心愿吧。 --------------------------------------------- Q&A: ---------------------------------------------- Q:我编译时出现错误:fatal error C1083: Cannot open include file: 'bios.h': Nosuch file or directory,该如何解决? A:正文中的代码,是使用Borland公司的TC2.0编译的,编译结果运行在Windows的16位虚拟机上。bi os.h是属于TC的头文件,在VC或者其他编译器中可能没有这个头文件。因此会产生这个错误。 解决办法: (1)可以下载附件中的压缩包,是使用VC6.0进行编译的版本,编译结果是Windows程序,运行在wind ows 32系统上。两者之间的算法完全一致,区别仅仅是绘图时采用的接口不同,TC下采用BGI(进入图形模式),VC下采用的是GDI(使用DC进行绘图)。 (2)下载TC2.0进行编译。 Q:使用TC3.0进行编译时,提示未能初始化图形模式,请使用initgraph函数。 A:这是因为TC3.0的BGI文件的路径和TC2.0有所不同。TC2.0的BGI文件位于TC路径下。而TC3.0的BGI文件位于BGI文件夹中。请把initgame函数中的initgraph函数中的第三个参数设置为正确的路径。例如:initgraph(&..,&..,"C:\\TC\\BGI"); Q:编译后运行时,弹出错误对话框报告16位虚拟机遇到不可执行的指令,点击确定后退出。 A:该问题在某些环境中出现,可能是基于软件或者硬件环境造成,具体原因暂时未知。为避免该问题,请加载附件中的压缩包VC6.0版本。 #include 不多说,,直接可以拷贝下面的东西,然后记得把那个BLOCK的名字改成你自己的类名,这个很关键哦,不然是错的可别怪我,呵呵~~ import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.applet.*; import https://www.wendangku.net/doc/ce7766407.html,ng.String.*; import https://www.wendangku.net/doc/ce7766407.html,ng.*; import java.io.*; public class Block extends JPanel implements ActionListener,KeyListener//应该是继承JPanel { static Button but[] = new Button[6]; static Button noStop = new Button("取消暂停"); static Label scoreLab = new Label("分数:"); static Label infoLab = new Label("提示:"); static Label speedLab = new Label("级数:"); static Label scoreTex = new Label("0"); static Label infoTex = new Label(" "); static Label speedTex = new Label("1"); static JFrame jf = new JFrame(); static MyTimer timer; static ImageIcon icon=new ImageIcon("resource/Block.jpg"); static JMenuBar mb = new JMenuBar(); static JMenu menu0 = new JMenu("游戏 "); static JMenu menu1 = new JMenu("帮助 "); static JMenuItem mi0 = new JMenuItem("新游戏"); static JMenuItem mi1 = new JMenuItem("退出"); static JMenuItem mi1_0 = new JMenuItem("关于"); static JDialog dlg_1; static JTextArea dlg_1_text = new JTextArea(); static int startSign = 0;//游戏开始标志 0 未开始 1 开始 2 暂停 static String butLab[] = {"开始游戏","重新开始","降低级数","提高级数","游戏暂停","退出游戏"}; static int game_body[][] = new int[19][10]; static int game_sign_x[] = new int[4];//用于记录4个方格的水平位置 static int game_sign_y[] = new int[4];//用于记录4个方格的垂直位置 static boolean downSign = false;//是否落下 static int blockNumber = 1;//砖块的编号 static int gameScore = 0;//游戏分数 static int speedMark = 1;C语言俄罗斯方块游戏源代码
俄罗斯方块实验报告
C++俄罗斯方块代码(北邮版)
俄罗斯方块C语言代码
俄罗斯方块软件需求规格说明书
为你解惑之WPF经典9问详解
C语言课程设计俄罗斯方块源代码
C.C++语言-俄罗斯方块源码
俄罗斯方块游戏
俄罗斯方块源代码
易错题库-精选题2021年平凉市中考化学试题(解析版)
俄罗斯方块完整源代码
俄罗斯方块C语言程序设计报告
俄罗斯方块程序代码
C语言程序设计-俄罗斯方块源程序
C语言俄罗斯方块(详解..)
JAVA俄罗斯方块源代码