#include <windows.h> |
#include <stdio.h> |
#include <time.h> |
|
#define CELL 20 |
#define ROWS 25 |
#define COLS 15 |
//升级所需分数值 |
#define SCORE_LEVEL_INC 80 |
#define ID_TIMER 1 |
|
/////////////////全局变量///////////////////////////// |
HWND hwnd; //保存窗口句柄 |
|
int score= 0 ; //分数 |
int level= 0 ; //级数 |
int interval_unit= 25 ; //随级数递增的时间间隔增量 |
int interval_base= 300 ; //时间间隔基量 |
int old_interval; //保存当前的时间间隔,用于加速操作 |
|
int cur_left,cur_top; //记录方块当前的位置 |
int width_block,height_block; //方块的宽带和高度 |
|
bool isPause= false ; //暂停标识 |
UINT timer_id= 0 ; //保存计时器ID |
|
static byte *block=NULL; //方块,方块为随机大小,采用动态分配内存方式,所以这里是指针变量 |
byte g_panel[ROWS][COLS]={ 0 }; |
//////////////////////////////////////////////////// |
LRESULT CALLBACK WndProc ( HWND,UINT,WPARAM,LPARAM ); |
void DrawPanel ( HDC hdc ); //绘制表格 |
void RefreshPanel ( HDC hdc ); //刷新面板 |
void DoDownShift ( HDC hdc ); //下移 |
void DoLeftShift ( HDC hdc ); //左移 |
void DoRightShift ( HDC hdc ); //右移 |
void DoAccelerate ( HDC hdc ); //加速 |
void DoRedirection ( HDC hdc ); //改变方向 |
void ClearRow ( HDC hdc ); //消行 |
bool ExportBlock(); //输出方块, |
//该函数会直接修改全局变量block,width_block,height_block, |
//cur_left和cur_top |
bool IsTouchBottom ( HDC hdc ); //判断是否到达底部 |
|
int main() |
{ |
HINSTANCE hInstance=GetModuleHandle ( NULL ); |
TCHAR szAppName[]=TEXT ( "teris" ); |
MSG msg; |
WNDCLASS wc; |
|
wc.style=CS_HREDRAW|CS_VREDRAW; |
wc.lpfnWndProc=WndProc; |
wc.cbClsExtra= 0 ; |
wc.cbWndExtra= 0 ; |
wc.hInstance=hInstance; |
wc.hIcon=LoadIcon ( NULL,IDI_APPLICATION ); |
wc.hCursor=LoadCursor ( NULL,IDC_ARROW ); |
wc.hbrBackground= ( HBRUSH ) GetStockObject ( WHITE_BRUSH ); |
wc.lpszMenuName=NULL; |
wc.lpszClassName=szAppName; |
if ( !RegisterClass ( &wc ) ) |
{ |
printf ( "RegisterClass occur errors!" ); |
return 0 ; |
} |
hwnd=CreateWindow ( szAppName,TEXT ( "Teris Demo" ), |
WS_OVERLAPPEDWINDOW, |
0 , 0 , 0 , 0 , |
NULL, |
NULL, |
hInstance, |
NULL ); |
ShowWindow ( hwnd,SW_SHOW ); |
UpdateWindow ( hwnd ); |
while ( GetMessage ( &msg,NULL, 0 , 0 ) ) |
{ |
TranslateMessage ( &msg ); |
DispatchMessage ( &msg ); |
} |
return msg.wParam; |
} |
|
void DrawPanel ( HDC hdc ) //绘制游戏面板 |
{ |
int x,y; |
RECT rect; |
|
for ( y= 0 ; y<ROWS; y++ ) |
{ |
for ( x= 0 ; x<COLS; x++ ) |
{ |
//计算方块的边框范围 |
rect.top=y*CELL+ 1 ; |
rect.bottom= ( y+ 1 ) *CELL- 1 ; |
rect.left=x*CELL+ 1 ; |
rect.right= ( x+ 1 ) *CELL- 1 ; |
FrameRect ( hdc,&rect, ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ); |
} |
} |
} |
|
void DoDownShift ( HDC hdc ) //下移 |
{ |
if ( NULL==block ) return ; |
|
//判断是否到达底部 |
if ( IsTouchBottom ( hdc ) ) //到底部 |
{ |
//消行处理 |
ClearRow ( hdc ); |
ExportBlock(); //输出下一个方块 |
} |
|
cur_top++; |
RefreshPanel ( hdc ); |
} |
|
void DoLeftShift ( HDC hdc ) //左移 |
{ |
int x,y; |
if ( NULL==block ) return ; |
|
if ( 0 ==cur_left ) return ; |
if ( cur_top< 0 ) return ; //方块没有完整显示前,不能左移 |
for ( y= 0 ; y<height_block; y++ ) |
{ |
for ( x= 0 ; x<width_block; x++ ) //从左边开始扫描,获取该行最左边的实心方格块 |
{ |
if ( * ( block+y*width_block+x ) ) |
{ |
//判断当前方格在面板上面左边一个方格是否为实心,是就代表不能再左移 |
if ( g_panel[cur_top+y][cur_left+x- 1 ] ) return ; |
|
break ; //只判断最左边的一个实心方格,之后直接扫描下一行 |
} |
} |
} |
cur_left--; |
RefreshPanel ( hdc ); |
} |
|
void DoRightShift ( HDC hdc ) //右移 |
{ |
int x,y; |
if ( NULL==block ) return ; |
|
if ( COLS-width_block==cur_left ) return ; |
if ( cur_top< 0 ) return ; //方块完整显示前不能右移 |
for ( y= 0 ; y<height_block; y++ ) |
{ |
for ( x=width_block- 1 ; x>= 0 ; x-- ) //从右边开始扫描,获取该行最右边的实心方格块 |
{ |
if ( * ( block+y*width_block+x ) ) |
{ |
//判断当前方格在面板上右边一个方格是否为实心,是就代表不能再右移 |
if ( g_panel[cur_top+y][cur_left+x+ 1 ] ) return ; |
|
break ; //只判断最右边的一个实心方格 |
} |
} |
} |
cur_left++; |
RefreshPanel ( hdc ); |
} |
|
void DoRedirection ( HDC hdc ) //改变方向 |
{ |
int i,j; |
byte * temp=NULL; |
if ( NULL==block ) return ; |
if ( cur_top< 0 ) return ; //方块完整显示前不能转向 |
|
temp= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
for ( i= 0 ; i<width_block; i++ ) |
{ |
for ( j= 0 ; j<height_block; j++ ) |
{ |
//temp[i][j]=block[height_block-j-1][i]; |
* ( temp+i*height_block+j ) =* ( block+ ( height_block-j- 1 ) *width_block+i ); |
} |
} |
|
//给方块重新定位 |
int incHeight=width_block-height_block; |
int incWidth=height_block-width_block; |
int temp_cur_top=cur_top-incHeight/ 2 ; |
int temp_cur_left=cur_left-incWidth/ 2 ; |
|
//system("cls"); |
//printf("temp_top=%d, temp_left=%d",temp_cur_top,temp_cur_left); |
|
//判断当前空间是否足够让方块改变方向 |
int max_len=max ( width_block,height_block ); |
//防止下标访问越界 |
if ( temp_cur_top+max_len- 1 >=ROWS||temp_cur_left< 0 ||temp_cur_left+max_len- 1 >=COLS ) |
{ |
free ( temp ); //退出前必须先释放内存 |
return ; |
} |
for ( i= 0 ; i<max_len; i++ ) |
{ |
for ( j= 0 ; j<max_len; j++ ) |
{ |
//转向所需的空间内有已被占用的实心方格存在,即转向失败 |
if ( g_panel[temp_cur_top+i][temp_cur_left+j] ) |
{ |
free ( temp ); //退出前必须先释放内存 |
return ; |
} |
} |
} |
|
//把临时变量的值赋给block,只能赋值,而不能赋指针值 |
for ( i= 0 ; i<height_block; i++ ) |
{ |
for ( j= 0 ; j<width_block; j++ ) |
{ |
//block[i][j]=temp[i][j]; |
* ( block+i*width_block+j ) =* ( temp+i*width_block+j ); |
} |
} |
|
//全局变量重新被赋值 |
cur_top=temp_cur_top; |
cur_left=temp_cur_left; |
//交换 |
i=width_block; |
width_block=height_block; |
height_block=i; |
|
free ( temp ); //释放为临时变量分配的内存 |
RefreshPanel ( hdc ); |
} |
|
void DoAccelerate ( HDC hdc ) //加速 |
{ |
if ( NULL==block ) return ; |
|
if ( IsTouchBottom ( hdc ) ) |
{ |
//消行处理 |
ClearRow ( hdc ); |
ExportBlock(); |
} |
cur_top++; |
RefreshPanel ( hdc ); |
} |
|
bool IsTouchBottom ( HDC hdc ) |
{ |
int x,y; |
int i,j; |
|
if ( NULL==block ) return false ; |
if ( ROWS==cur_top+height_block ) |
{ |
//固定方块 |
for ( i= 0 ; i<height_block; i++ ) |
{ |
for ( j= 0 ; j<width_block; j++ ) |
{ |
if ( * ( block+i*width_block+j ) ) g_panel[cur_top+i][cur_left+j]= 1 ; |
} |
} |
return true ; |
} |
for ( y=height_block- 1 ; y>= 0 ; y-- ) //从底行开始扫描 |
{ |
//判断第一个实心方块在面板上邻接的下方方格是否为实心,是就代表已经到达底部 |
for ( x= 0 ; x<width_block; x++ ) |
{ |
if ( * ( block+y*width_block+x ) ) |
{ |
if ( cur_top+y+ 1 < 0 ) return false ; |
if ( g_panel[cur_top+y+ 1 ][cur_left+x] ) |
{ |
//判断是否gameover |
if ( cur_top<= 0 ) |
{ |
if ( timer_id ) |
{ |
KillTimer ( hwnd,ID_TIMER ); |
timer_id= 0 ; |
} |
MessageBox ( hwnd,TEXT ( "游戏结束" ),TEXT ( "MSG" ),MB_OK|MB_ICONEXCLAMATION ); |
SendMessage ( hwnd,WM_CLOSE, 0 , 0 ); |
} |
// |
//固定方块 |
for ( i= 0 ; i<height_block; i++ ) |
{ |
for ( j= 0 ; j<width_block; j++ ) |
{ |
if ( * ( block+i*width_block+j ) ) g_panel[cur_top+i][cur_left+j]= 1 ; |
} |
} |
return true ; |
} |
} |
} |
} |
return false ; |
} |
|
void ClearRow ( HDC hdc ) //消行 |
{ |
int i,j,k; |
int count= 0 ; //消行次数 |
bool isFilled; |
//消行处理 |
for ( i=ROWS- 1 ; i>= 0 ; i-- ) |
{ |
isFilled= true ; |
for ( j= 0 ; j<COLS; j++ ) |
{ |
if ( !g_panel[i][j] ) |
{ |
isFilled= false ; |
break ; |
} |
} |
if ( isFilled ) |
{ |
for ( j= 0 ; j<COLS; j++ ) |
{ |
g_panel[i][j]= 0 ; |
} |
//所有方块往下移 |
for ( k=i- 1 ; k>= 0 ; k-- ) |
{ |
for ( j= 0 ; j<COLS; j++ ) |
{ |
g_panel[k+ 1 ][j]=g_panel[k][j]; |
} |
} |
i=i+ 1 ; |
count++; |
} |
} |
|
//最高级别为9级,所以分数极限为(9+1)*SCORE_LEVEL_INC-1 |
if ( score>= 10 *SCORE_LEVEL_INC- 1 ) return ; |
|
//加分规则:消除行数,1行加10分,2行加15分,3行加20分,4行加30分 |
switch ( count ) |
{ |
case 1 : |
score+= 10 ; |
break ; |
case 2 : |
score+= 15 ; |
break ; |
case 3 : |
score+= 20 ; |
break ; |
case 4 : |
score+= 30 ; |
break ; |
} |
|
int temp_level=score/SCORE_LEVEL_INC; |
if ( temp_level>level ) |
{ |
level=temp_level; |
//撤销当前计时器,然后重设 |
if ( timer_id ) KillTimer ( hwnd,ID_TIMER ); |
timer_id=SetTimer ( hwnd,ID_TIMER,interval_base-level*interval_unit,NULL ); |
} |
|
system ( "cls" ); |
printf ( "score: %d, level: %d " ,score,level ); |
} |
|
void RefreshPanel ( HDC hdc ) //刷新面板 |
{ |
int x,y; |
RECT rect; |
HBRUSH h_bSolid= ( HBRUSH ) GetStockObject ( GRAY_BRUSH ), |
h_bEmpty= ( HBRUSH ) GetStockObject ( WHITE_BRUSH ); |
if ( NULL==block ) return ; |
|
//先刷屏 |
for ( y= 0 ; y<ROWS; y++ ) |
{ |
for ( x= 0 ; x<COLS; x++ ) |
{ |
//为避免刷掉方块的边框,rect范围必须比边框范围小1 |
rect.top=y*CELL+ 2 ; |
rect.bottom= ( y+ 1 ) *CELL- 2 ; |
rect.left=x*CELL+ 2 ; |
rect.right= ( x+ 1 ) *CELL- 2 ; |
if ( g_panel[y][x] ) |
FillRect ( hdc,&rect,h_bSolid ); |
else |
FillRect ( hdc,&rect,h_bEmpty ); |
} |
} |
//再定位方块 |
for ( y= 0 ; y<height_block; y++ ) |
{ |
for ( x= 0 ; x<width_block; x++ ) |
{ |
if ( * ( block+y*width_block+x ) ) //实心 |
{ |
rect.top= ( y+cur_top ) *CELL+ 2 ; |
rect.bottom= ( y+cur_top+ 1 ) *CELL- 2 ; |
rect.left= ( x+cur_left ) *CELL+ 2 ; |
rect.right= ( x+cur_left+ 1 ) *CELL- 2 ; |
FillRect ( hdc,&rect,h_bSolid ); |
} |
} |
} |
} |
|
bool ExportBlock() //输出方块 |
{ |
int sel; |
if ( block ) |
{ |
free ( block ); //释放之前分配的内存 |
block=NULL; |
} |
|
sel=rand() % 7 ; |
switch ( sel ) |
{ |
case 0 : //水平条 |
width_block= 4 ; |
height_block= 1 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 1 ; //可以理解为*(block+0*width_block+0)=1,即第一行的第一个方格,下面同理 |
* ( block+ 1 ) = 1 ; //*(block+0*width_block+1)=1 |
* ( block+ 2 ) = 1 ; //*(block+0*width_block+2)=1 |
* ( block+ 3 ) = 1 ; //*(block+0*width_block+3)=1 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
case 1 : //三角 |
width_block= 3 ; |
height_block= 2 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 0 ; //可以理解为*(block+0*width_block+0)=0,即第一行的第一个方格,下面同理 |
* ( block+ 1 ) = 1 ; //*(block+0*width_block+1)=1 |
* ( block+ 2 ) = 0 ; //*(block+0*width_block+2)=0 |
* ( block+ 3 ) = 1 ; //*(block+1*width_block+0)=1,第二行开始 |
* ( block+ 4 ) = 1 ; //*(block+1*width_block+1)=1 |
* ( block+ 5 ) = 1 ; //*(block+1*width_block+2)=1 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
case 2 : //左横折 |
width_block= 3 ; |
height_block= 2 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 1 ; //可以理解为*(block+0*width_block+0)=1,下面同理 |
* ( block+ 1 ) = 0 ; //*(block+0*width_block+1)=0 |
* ( block+ 2 ) = 0 ; //*(block+0*width_block+2)=0 |
* ( block+ 3 ) = 1 ; //*(block+1*width_block+0)=1 |
* ( block+ 4 ) = 1 ; //*(block+1*width_block+1)=1 |
* ( block+ 5 ) = 1 ; //*(block+1*width_block+2)=1 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
case 3 : //右横折 |
width_block= 3 ; |
height_block= 2 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 0 ; //可以理解为*(block+0*width_block+0)=0,下面同理 |
* ( block+ 1 ) = 0 ; //*(block+0*width_block+1)=0 |
* ( block+ 2 ) = 1 ; //*(block+0*width_block+2)=1 |
* ( block+ 3 ) = 1 ; //*(block+1*width_block+0)=1 |
* ( block+ 4 ) = 1 ; //*(block+1*width_block+1)=1 |
* ( block+ 5 ) = 1 ; //*(block+1*width_block+2)=1 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
case 4 : //左闪电 |
width_block= 3 ; |
height_block= 2 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 1 ; //可以理解为*(block+0*width_block+0)=1,下面同理 |
* ( block+ 1 ) = 1 ; //*(block+0*width_block+1)=1 |
* ( block+ 2 ) = 0 ; //*(block+0*width_block+2)=0 |
* ( block+ 3 ) = 0 ; //*(block+1*width_block+0)=0 |
* ( block+ 4 ) = 1 ; //*(block+1*width_block+1)=1 |
* ( block+ 5 ) = 1 ; //*(block+1*width_block+2)=1 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
case 5 : //右闪电 |
width_block= 3 ; |
height_block= 2 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 0 ; //可以理解为*(block+0*width_block+0)=0,下面同理 |
* ( block+ 1 ) = 1 ; //*(block+0*width_block+1)=1 |
* ( block+ 2 ) = 1 ; //*(block+0*width_block+2)=1 |
* ( block+ 3 ) = 1 ; //*(block+1*width_block+0)=1 |
* ( block+ 4 ) = 1 ; //*(block+1*width_block+1)=1 |
* ( block+ 5 ) = 0 ; //*(block+1*width_block+2)=0 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
case 6 : //石头 |
width_block= 2 ; |
height_block= 2 ; |
block= ( byte * ) malloc ( sizeof ( byte ) *width_block*height_block ); |
* ( block+ 0 ) = 1 ; //可以理解为*(block+0*width_block+0)=1,下面同理 |
* ( block+ 1 ) = 1 ; //*(block+0*width_block+1)=1 |
* ( block+ 2 ) = 1 ; //*(block+1*width_block+0)=1 |
* ( block+ 3 ) = 1 ; //*(block+1*width_block+1)=1 |
|
cur_top= 0 -height_block; |
cur_left= ( COLS-width_block ) / 2 ; |
break ; |
} |
return block!=NULL; |
} |
|
LRESULT CALLBACK WndProc ( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam ) |
{ |
HDC hdc; |
PAINTSTRUCT ps; |
//TCHAR szBuffer[1024]; |
|
switch ( message ) |
{ |
case WM_CREATE: |
MoveWindow ( hwnd, 400 , 10 ,CELL*COLS+ 8 ,CELL*ROWS+ 32 ,FALSE ); //补齐宽度和高度 |
srand ( time ( NULL ) ); |
ExportBlock(); |
|
timer_id=SetTimer ( hwnd,ID_TIMER,interval_base-level*interval_unit,NULL ); |
return 0 ; |
case WM_TIMER: |
hdc=GetDC ( hwnd ); |
DoDownShift ( hdc ); |
ReleaseDC ( hwnd,hdc ); |
return 0 ; |
case WM_KEYDOWN: |
hdc=GetDC ( hwnd ); |
switch ( wParam ) |
{ |
case VK_LEFT: //左移 |
if ( !isPause ) DoLeftShift ( hdc ); |
break ; |
case VK_RIGHT: //右移 |
if ( !isPause ) DoRightShift ( hdc ); |
break ; |
case VK_UP: //转向 |
if ( !isPause ) DoRedirection ( hdc ); |
break ; |
case VK_DOWN: //加速 |
if ( !isPause ) DoAccelerate ( hdc ); |
break ; |
case VK_SPACE: //暂停 |
isPause=!isPause; |
if ( isPause ) |
{ |
if ( timer_id ) KillTimer ( hwnd,ID_TIMER ); |
timer_id= 0 ; |
} |
else |
{ |
timer_id=SetTimer ( hwnd,ID_TIMER,interval_base-level*interval_unit,FALSE ); |
} |
break ; |
} |
ReleaseDC ( hwnd,hdc ); |
return 0 ; |
case WM_PAINT: |
hdc=BeginPaint ( hwnd,&ps ); |
DrawPanel ( hdc ); //绘制面板 |
RefreshPanel ( hdc ); //刷新 |
EndPaint ( hwnd,&ps ); |
return 0 ; |
case WM_DESTROY: |
if ( block ) free ( block ); |
if ( timer_id ) KillTimer ( hwnd,ID_TIMER ); |
PostQuitMessage ( 0 ); |
return 0 ; |
} |
return DefWindowProc ( hwnd,message,wParam,lParam ); |
} |
初级程序员
by: 云代码会员 发表于:2016-10-15 20:44:20 顶(0) | 踩(0) 回复
感谢分享
回复评论