OpenGL實現(xiàn)俄羅斯方塊源代碼.doc
《OpenGL實現(xiàn)俄羅斯方塊源代碼.doc》由會員分享,可在線閱讀,更多相關(guān)《OpenGL實現(xiàn)俄羅斯方塊源代碼.doc(15頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1、 OpenGL實現(xiàn)俄羅斯方塊 一、 設(shè)計思路 本程序采用以C++為基礎(chǔ)并利用OpenGl庫函數(shù)的方式實現(xiàn)俄羅斯方塊程序,實現(xiàn)俄羅斯方塊中正方形,T形,L形,反L形,直線型,Z字形,反Z字形七種形狀的變換操作,七種形狀的坐標被存儲在一個三維數(shù)組中,每次隨機選擇一個形狀生成并下落,在下落過程中監(jiān)聽鍵盤事件。 二、 詳細設(shè)計說明 本程序中主要的函數(shù)及其作用說明如下: down:定時下落函數(shù),由glutTimerFunc(1000,down,1);函數(shù)設(shè)置每隔1000毫秒即調(diào)用一次該函數(shù),在函數(shù)中將方塊的所有縱坐標減一個單位。 key: 鍵盤事件監(jiān)聽函數(shù),當鍵盤上有按鍵被觸發(fā)的
2、時候即調(diào)用該函數(shù),函數(shù)內(nèi)部支持w,a,s,d四個鍵的響應,依次代表方向鍵上,左,右,下,其中w鍵是用來控制圖形變換的,每次按w鍵時,圖形在現(xiàn)有基礎(chǔ)上順時針變換一次。
CheckConflict:沖突檢測函數(shù),檢測方塊下一次將要移動的位置是否會碰到已有的方塊或者左右兩邊的墻壁。
CheckDelete:每一次方塊落到底部之后,調(diào)用該函數(shù)檢查是否有滿行,如果有則調(diào)用Delete函數(shù)刪除該行。
myDisplay1:作圖函數(shù)。
Change:變換函數(shù),主要是通過計算變換后的圖形與之前圖形的坐標關(guān)系來實現(xiàn)。
三、 源代碼
#include 3、dlib.h>
#include 4、P鍵進行變換應該怎么處理
*本程序最初設(shè)計并不考慮這個問題,一開始即畫出方塊的各個部分,以后再考慮完善的事情
*另外,記錄坐標的順序為從左至右,從上至下
*/
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 5、}},//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字形
};
GLfloa 6、t curLoc[5][3];
GLint currentBlock=2;//記錄當前正在下落的是第幾種方塊,順序如上面所示
GLint turn[7]={0};//應該變換成第幾種形態(tài)了
GLfloat xd=0.0f,yd=0.0f;
/*
這里定義的over是用來判斷方塊是否到達了不能再往下降的地方,到了則置
其為true,否則就修改為false。
其中有這樣幾種情況需要修改over:
1、重新生成了一個方塊,修改over=false
2、方塊到大底部,修改over=true
*/
bool over=false;
//記錄游戲是否結(jié)束
bool end 7、=false;
int score=0;
//設(shè)置一個鎖,在下降操作時不允許變換,在變換時不允許下降操作,否則將會產(chǎn)生資源競爭
//int lock=1;
/*
定義一個20*20的矩陣來記錄當前整個畫面中各個小格子的情況,可用來消除滿格行
矩陣的存儲順序為從左到右,從下到上,包含下標0
BLOCK[i][j]中i對應的是縱坐標,j對應的是橫坐標(這個有點痛苦),但是在消去滿格
的時候還是不變,只是在用b數(shù)組給其賦值時需要反過來
*/
GLint BLOCK[SIZE][SIZE];
void down(int id);
void InitBLOCK() 8、;
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++) //函數(shù)調(diào)用的順序?qū)﹀e誤有一定的影響
for(j=0;j<2;j++)
{
cout<< 9、curLoc[i][j]<<" ";
}
cout< 10、hange()//將圖形做變換,采用順時針旋轉(zhuǎn)的規(guī)律(下面的工作即是填入坐標)
{
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( 11、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]=temp 12、11+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]="< 13、[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;
14、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]=te 15、mp10+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.1 16、f;
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;
17、 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 18、字形
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;
19、 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;
20、 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;
21、 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;
b 22、reak;
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[ 23、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]=te 24、mp21;
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;
}
//如果旋轉(zhuǎn)非法(即旋轉(zhuǎn)時碰到墻壁了),則要恢復原來的狀態(tài)
int ret;
ret=CheckConflict();
if(ret == 1)
{
curLoc[0][0]=temp00;
curLoc[0][1]=temp01;
25、
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 *emp 26、ty)
{
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++)
27、 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、判斷新生成的圖形是否和原來的圖形有沖突,有則不能更改,這個地方比較不好實現(xiàn)
*2、判斷是否有滿格的行,有則調(diào)用Delete函數(shù)去掉
*3、這里似乎還要加上判斷是否到大頂部,如果到達頂部則游戲結(jié)束(可采用監(jiān)視方框最上
* 28、面一行之上那行里面有沒有方格,如果有的話則游戲結(jié)束)
*結(jié)束之后就可以把當前方塊存入BLOCK中
*empty表示一行中方塊的數(shù)目,-1表示為空行,0表示部分為空,1表示滿行
*/
void CheckDelete()//目前這個函數(shù)還只是實現(xiàn)了一個方塊到達終點之后是否有能夠被刪除的行
{
int i,j;
int empty[SIZE];
bool is_needed=false;
int count;
for(i=0;i 29、][0]+1)*10+0.5; //此處無需注意取值,因為checkConflict已經(jīng)解決
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_n 30、eeded=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方向無需注意
31、 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) //判斷是否發(fā)生沖突
{
break;
}
}
if(i < 4)
return 1;
return 0;
}
/*
關(guān)鍵部分在這里,主要是要判斷方塊下一次的移動是否合法,
本程序通過對b數(shù)組所存儲的下標是否在BLOCK數(shù)組中已經(jīng)為1
來判斷,這樣,只需要在BLOCK 32、的最外層加一圈1,就不用通過
原來的方式來判斷方塊是否越界
*/
void key(unsigned char k,int x,int y)
{
int i,ret;
if(over == false)
{
if(k==UP)//此處需要改成調(diào)用變換圖形樣式的函數(shù)
{
Change();
}
else if(k==DOWN)//后續(xù)還要修改,移動到底部過了一段時間之后就不能左右移動了
{
for(i=0;i<4;i++)//需繼續(xù)添加以1和-1作為哨兵
{
curLoc[i][1]-=0.1f;
} 33、
ret=CheckConflict();
if(ret == 1)//發(fā)生沖突,則將修改復原
{
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)//發(fā)生沖突,則將修改復原
{
for(i=0;i 34、<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)//發(fā)生沖突,則將修改復原
{
for(i=0;i<4;i++)
curLoc[i][0]+=0.1f;
}
}
}
if(over==true) CheckDelete();
glutPostRedisplay();//調(diào)用這 35、個函數(shù)可以重新繪圖,每次相應消息之后,所有全部重繪
}
/*
讓方塊定時下降
*/
void down(int id)
{
int i,ret;
if(over!=true)
{
for(i=0;i<4;i++)//需繼續(xù)添加以1和-1作為哨兵
{
curLoc[i][1]-=0.1f;
}
ret=CheckConflict();
if(ret == 1)//發(fā)生沖突,則將修改復原
{
for(i=0;i<4;i++)
curLoc[i][1]+=0.1f;
if(curLoc[0][1] > 36、= b[currentBlock][0][1])
{
cout<<"Game over,your score is:"< 37、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);
g 38、lColor3f(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= 39、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 40、]);
glVertex2f(curLoc[i][0]+0.1f,curLoc[i][1]+0.1f);
glVertex2f(curLoc[i][0],curLoc[i][1]+0.1f);
glEnd();
glFlush();
}
}
glutSwapBuffers();
}
/*
* 隨機生成方塊,原理即生成一個7以內(nèi)的隨機數(shù),
* 對應的二維數(shù)組即為下一個產(chǎn)生的方塊
*/
void CreateBlocks()
{
int i,j;
myDisplay1();
if(over)
{
srand(t 41、ime(NULL));
currentBlock=rand()%7;
for(i=0;i<7;i++) //關(guān)鍵之處,每次創(chuàng)建一個新的方塊后要將變形的記錄清空
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 42、);
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();
}
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 6.煤礦安全生產(chǎn)科普知識競賽題含答案
- 2.煤礦爆破工技能鑒定試題含答案
- 3.爆破工培訓考試試題含答案
- 2.煤礦安全監(jiān)察人員模擬考試題庫試卷含答案
- 3.金屬非金屬礦山安全管理人員(地下礦山)安全生產(chǎn)模擬考試題庫試卷含答案
- 4.煤礦特種作業(yè)人員井下電鉗工模擬考試題庫試卷含答案
- 1 煤礦安全生產(chǎn)及管理知識測試題庫及答案
- 2 各種煤礦安全考試試題含答案
- 1 煤礦安全檢查考試題
- 1 井下放炮員練習題含答案
- 2煤礦安全監(jiān)測工種技術(shù)比武題庫含解析
- 1 礦山應急救援安全知識競賽試題
- 1 礦井泵工考試練習題含答案
- 2煤礦爆破工考試復習題含答案
- 1 各種煤礦安全考試試題含答案