最近在看俄羅斯方塊的游戲,看到一個大神寫的俄羅斯方塊代碼,非常非常優秀,拿出來決議給大家看看,也希望大家自己嘗試運行試試,從中能得到一些啟發,
#先了解下俄羅斯方塊的幾個形狀
一共分成 7 形狀,有的形狀有 4種狀態,有的形狀有1種狀態,
不管是多少種狀態,一個方塊需要一個2個位元組來存盤,也就是16bit來保存一個方塊的資訊,
基于上面的理論,我們可以使用4x4的陣列來保存方塊的資訊,
注意,下面代碼中的 "■" 占用的是2個位元組,
#寫代碼來顯示這個方塊
方塊資料,這兩個陣列其實是兩種游戲模式的方塊資訊,我們只需要分析一種就可以了,
int TGM[7][4]={{0x159D,0x89AB,0x159D,0x89AB},{0x126A,0x4856,0x159A,0x4526},{0x926A,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x5926,0x0156,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x156A,0x4152,0x156A,0x4152}};
int SRS[7][4]={{0x159D,0x89AB,0x26AE,0x4567},{0x0159,0x4856,0x159A,0x4526},{0x8159,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x4815,0x459A,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x0459,0x8596,0x156A,0x4152}};
我們分析這段代碼
/***********擦除顯示*************/
int Display(int x, int y, int CAC, int Mode)
{
for(j=0;j<=3;j++){
P[j]=CAC&0xF, CAC>>=4;
if (Mode==1){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf("■");}
else if(Mode==0){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf(" ");}
}
return 0;
}
P[j]=CAC&0xF 取到的是 4個bit,然后通過判斷這 4個bit決定輸出方塊的位置,
我們拿 0這個方塊的資料0x4859 對應的二進制 0B0100100001011001來做個例子,
0100 ----> 對應坐標(1,0)
1000 ----> 對應坐標(2,0)
0101 ----> 對應坐標(1,1)
1001 ----> 對應坐標(2,1)
通過這個坐標,我們會輸出這樣一個方塊
再舉個例子
我們拿 Z這個方塊的資料0x0156 對應的二進制 0B0000000101010110來做個例子,
0000 ----> 對應坐標(0,0)
0001 ----> 對應坐標(0,1)
0101 ----> 對應坐標(1,1)
0110 ----> 對應坐標(1,2)
顯示方塊沒有問題了
上面的代碼中,如果mode等于0的話,也就是把某個方塊從顯示中擦除掉,
我們用devc++寫的程式,需要知道幾個細節,
#構建固定行列的視窗
正常情況,我們顯示cmd是一個默認值的黑框「如下圖」,
實際上,我們可以用代碼來固定cmd的框框大小,
默認代碼輸出
示例代碼:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
/**********Main主函式***********/
int main()
{
system("color F1&mode con cols=35 lines=25");
getchar();
return 0;
}
程式輸出:
#延遲函式的設計
跟其他不同的是,這個程式的延遲沒有使用usleep,我覺得這也是非常值得稱贊的地方,不過空跑cpu,哈哈,是有那么一點調皮,
把延遲放到鍵值獲取的函式中,
/**********按鍵獲取**************/
int Getkey(int N,int T)
{
int start=clock();
if(KEY_V==115){return 115;}
do{
if(kbhit()){
KEY_V=(int)(getch());
if(KEY_V<97){KEY_V+=32;}
return KEY_V;
}
for(i=0;i<=N;i++);
}while((clock()-start)<T);
dy=1;
return -1;
}
就先簡單講解下這些,至于得分機制,碰撞檢測,消除的代碼,還沒有想好怎么講明白,需要再花時間剖析剖析,
#試玩一下
#原始碼
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
/**********初始化引數************/
int i,j,N,T,F,J,X,Y,dx,dy, KEY_V, Cache1,Cache2,NU,NI,RU,RI, P_X,P_Y,POS_H_MAX, LEVEL=1,SCORE=0, P[4], POINT_V[12][22], MARK[21], FLAG[5]={0,0,0,1,0};
int TGM[7][4]={{0x159D,0x89AB,0x159D,0x89AB},{0x126A,0x4856,0x159A,0x4526},{0x926A,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x5926,0x0156,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x156A,0x4152,0x156A,0x4152}};
int SRS[7][4]={{0x159D,0x89AB,0x26AE,0x4567},{0x0159,0x4856,0x159A,0x4526},{0x8159,0x456A,0x1592,0x0456},{0x4859,0x4859,0x4859,0x4859},{0x4815,0x459A,0x5926,0x0156},{0x4159,0x4596,0x1596,0x4156},{0x0459,0x8596,0x156A,0x4152}};
/**********游標位置函式**********/
void Pos(int x,int y)
{
COORD pos;
HANDLE hOutput;
pos.X=2*x;
pos.Y=y;
hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput,pos);
}
void HideCursor()
{
CONSOLE_CURSOR_INFO cursor_info={1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
/**********初始化界面************/
void CreatUI()
{
int i,j,BOUNDARY;
printf("┏━━━━━━━━━━┓\n");
for(j=1;j<=20;j++) {
if (j==3){printf("┃ ┃LEVEL:1\n");}
else if(j==5){printf("┃ ┃SCORE:0\n");}
else if(j==7){printf("┃ ┃NEXT \n");}
else {printf("┃ ┃\n");}
}
printf("┗━━━━━━━━━━┛\n");
printf(" CopyRight@2016~2018 BY HAPPY\n");
for(j=1;j<=21;j++){
for(i=0;i<=11;i++){
BOUNDARY=i*(i-11)*(j-21);
if(BOUNDARY==0){
POINT_V[i][j]=1;
}else{
POINT_V[i][j]=0;
}
}
}
}
/**********按鍵獲取**************/
int Getkey(int N,int T)
{
int start=clock();
if(KEY_V==115){return 115;}
do{
if(kbhit()){
KEY_V=(int)(getch());
if(KEY_V<97){KEY_V+=32;}
return KEY_V;
}
for(i=0;i<=N;i++);
printf("%d\n",clock()-start);
}while((clock()-start)<T);
dy=1;
return -1;
}
/***********塊體轉置*************/
int Rote(int S, int I)
{
return (F==0)?TGM[S][(I+4)%4]:SRS[S][(I+4)%4];
}
/***********擦除顯示*************/
int Display(int x, int y, int CAC, int Mode)
{
for(j=0;j<=3;j++){
P[j]=CAC&0xF, CAC>>=4;
if (Mode==1){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf("■");}
else if(Mode==0){Pos((P[j]>>2)+x,(P[j]&0x3)+y);printf(" ");}
}
return 0;
}
/***********固化塊體*************/
int DoBlocks()
{
//~~~游戲結束
if(Y<2){
Pos(1,22);printf("GAME OVER!");
exit(0);
}
//~~~固化塊體
POS_H_MAX=0, FLAG[3]=1;
for(j=0;j<=3;j++){
P_X=(P[j]>>2)+X,P_Y=(P[j]&0x3)+Y;
if(POS_H_MAX<P_Y){POS_H_MAX=P_Y;}
POINT_V[P_X][P_Y]=1;
}
//~~~關卡得分
for(j=Y;j<=POS_H_MAX;j++){
FLAG[2]=1;
for(i=1;i<=10;i++){
if(POINT_V[i][j]==0){FLAG[2]=0;}
}
if(FLAG[2]){
SCORE+=10,MARK[j]=1;
if(SCORE==400){
SCORE=0,LEVEL+=1,T-=100;
FLAG[4]=1;
}
}
}
//~~~極品消行
for(j=20;j>=5;j--){
if(FLAG[4]){
for(i=1;i<=10;i++){
POINT_V[i][j]=0;
Pos(i,j);printf(" ");
}
}
else if(MARK[j])
{
MARK[j]=0,J=j-1;
for(N=1;N<=3;N++){
if(MARK[J]){J--;}
}
MARK[J]=1;
for(i=1;i<=10;i++){
Pos(i,j);
if(POINT_V[i][j]=POINT_V[i][J]){
printf("■");
}else{
printf(" ");
}
}
}
}
FLAG[4]=0;
return 0;
}
/***********碰撞檢測*************/
int CheckCollision()
{
for(j=0;j<=3;j++){
P_X=(P[j]>>2)+X+dx,P_Y=(P[j]&0x3)+Y+dy;
if(POINT_V[P_X][P_Y]){
if(dx!=0){return 1;}
if(dy){
DoBlocks();
Pos(12,3);printf("LEVEL:%-3d",LEVEL);
Pos(12,5);printf("SCORE:%-3d",SCORE);
return 2;
}
if(KEY_V==119){FLAG[0]=1;}
}
}
return 0;
}
unsigned
/***********回圈核心*************/
int GameCycle(int N, int T, int F)
{
srand((unsigned)time(NULL));RU=rand()%7,RI=(rand()%4);
while(1){
if(FLAG[3]){
Display(12,8,Rote(RU,RI),0);
X=4,Y=1, NU=RU,NI=RI, RU=rand()%7,RI=(rand()%4), FLAG[3]=0,KEY_V=0;
Display(12,8,Rote(RU,RI),1);
Display(X, Y,Rote(NU,NI),1);
}
dx=0,dy=0;
KEY_V=Getkey(N,T);
if(KEY_V==119){
NI++;
Display(X,Y,Rote(NU,NI),2);
}//旋W
else if(KEY_V==115){dy= 1;}//下S
else if(KEY_V==97 ){dx=-1;}//左A
else if(KEY_V==100){dx= 1;}//右D
else if(KEY_V==112){getch(); }//暫停P
else if(KEY_V==113){return 0;}//退出Q
if(dx!=0 || dy!=0 || KEY_V==119){
if(!CheckCollision()){
if(FLAG[0]){
NI--,FLAG[0]=0;
Display(X,Y,Rote(NU,NI),0);
}
else if(KEY_V==119){
Display(X,Y,Rote(NU,NI-1),0);
}else{
Display(X,Y,Rote(NU,NI),0);
}
Display(X+dx,Y+dy,Rote(NU,NI),1);
X+=dx,Y+=dy;
}
}
}
return 0;
}
/**********Main主函式***********/
int main()
{
system("color F0&mode con cols=35 lines=25");
HideCursor();
CreatUI();
GameCycle(10,800,1);
return 0;
}
#后記
里面涉及的很多東西,我都沒有完全總結出來,作者的巧妙非常令我佩服,后面應該還會有文章分析,
大家有什么想法或者自己的解讀,可以留言,歡迎一起討論,共同進步,探索代碼里面的奧秘和樂趣,
方塊消除
準備下一個方塊
得分機制
Game Over 判斷
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/255448.html
標籤:C

