前些日子因为在CSDN上发 “程序开发的壳与核”一文结识了网友C,在QQ聊天的时候他说他在写一个俄罗斯方块的程序,我说好啊,我也写一个,到时一起讨论,然后就开始写了,断断续续写了好几天昨天他已经把写好的发给我看了,我的还只写到50%,所以今天写了一个下午把它写了出来,不过还是有些地方没实现,比如NEXT指示的显示,事件发生的音效也没加,(只有背景音乐,但背景MCI播放的MID循环也没做出来),还有有时会有个消行时的BUG,不过我没办法重现,又不大会测试,所以就这样子算了吧,下面是截图,最后是程序,C不介意把他的代码也贴上来,一比较,就会觉得我的代码不太规范,有些地方也不具备扩展性,不便修改,他比我还低一级,还不是计算机专业的,编程能力真是让我汗颜啊。唉。。。。。。
这是我做的:
///
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#define ID_TIMER 1
#define WHITE 0
#define BLACK 1
int level=1;
int score=0;
int global[18][16];
int diamond[4][2];
int current_max=18;
int current_type=0;
int xBase,yBase;
int game_over;
#include "mmsystem.h"
HWND hwnd=NULL;
HINSTANCE hInstance;
TCHAR szAppName[]=TEXT("俄罗斯方块");
int i;
bool Init(char * title,int xStart,int yStart,int width,int height); //Window Initialization
void DrawUnit(HWND hwnd,int m,int n,int color);
void DrawDiamond(int color);
void InitDiamond(HWND hwnd,int a,int b,int current_type);
void DownLine(HWND hwnd,int baseline); //all rows above the success row down one stair
bool CheckLeft();
void MoveLeft();
bool CheckRight();
void MoveRight();
void DownQuickly();
void Rotate();
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE prevInstance,PSTR szCmdLine,int iCmdShow)
{
MSG msg;
if(!Init(szAppName,150,100,800,610))
{
return 0;
}
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return (msg.wParam);
}
bool Init(char * title,int xStart,int yStart,int width,int height)
{
RECT WindowRect;
WindowRect.left=(long)xStart;
WindowRect.right=(long)(xStart+width);
WindowRect.top=(long)yStart;
WindowRect.bottom=(long)(yStart+height);
hInstance = GetModuleHandle(NULL);
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW ;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(208,221,238));
wc.lpszMenuName = NULL;
wc.lpszClassName = title;
if(!RegisterClass(&wc))
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}
if (!(hwnd=CreateWindow(title,
title,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME,
xStart, yStart,
WindowRect.right-WindowRect.left,
WindowRect.bottom-WindowRect.top,
NULL,
NULL,
hInstance,
NULL)))
{
MessageBox(NULL,"Failed to create window !","ERROR",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rectLeft; //left blank
rectLeft.left=0;
rectLeft.top=0;
rectLeft.right=150;
rectLeft.bottom=610;
RECT rectRight; //right blank
rectRight.left=665;
rectRight.top=0;
rectRight.right=800;
rectRight.bottom=610;
UINT wMIDIDeviceID; //for playing background music .mid
MCI_OPEN_PARMS mciOpenParams;
MCI_PLAY_PARMS mciPlayParams;
DWORD dwError;
static bool done=true;
static bool down=false;
switch(message)
{
case WM_CREATE:
SetTimer (hwnd, ID_TIMER,500, NULL); //start the timer
mciOpenParams.lpstrDeviceType ="sequencer"; //play music
mciOpenParams.lpstrElementName="Loop.mid";
if(dwError=mciSendCommand(0,MCI_OPEN,MCI_OPEN_ELEMENT|MCI_OPEN_TYPE,(DWORD)(LPVOID)&mciOpenParams))
{
}
else
{
wMIDIDeviceID=mciOpenParams.wDeviceID;
}
if(dwError=mciSendCommand(wMIDIDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParams))
{
mciSendCommand(wMIDIDeviceID,MCI_CLOSE,0,NULL);
}
return 0;
case WM_KEYDOWN:
switch(wParam)
{
case VK_LEFT:
if(CheckLeft())
{
MoveLeft();
}
break;
case VK_RIGHT:
if(CheckRight())
{
MoveRight();
}
break;
case VK_UP: //rotate
Rotate();
break;
case VK_DOWN:
DownQuickly();
break;
}
return 0;
case WM_TIMER:
if(done)
{
if(current_max<=0)
{
KillTimer(hwnd,ID_TIMER);
MessageBox(NULL," You do well this time! ","Game Over !",MB_OK);
SendMessage(hwnd,WM_DESTROY,0,0);
break;
}
srand((unsigned)time(NULL));
current_type=rand()%19;
xBase=0;
yBase=7;
InitDiamond(hwnd,xBase,yBase,current_type);
DrawDiamond(BLACK);
down=true;
done=false;
}
else
{
for(i=0;i<4;i++) //check for down
{
if(global[diamond[i][0]+1][diamond[i][1]]==1 || diamond[i][0]+1>17)
{
down=false;
}
}
if(down==true) //then refresh
{
DrawDiamond(WHITE);
for(i=0;i<4;i++)
{
diamond[i][0]=diamond[i][0]+1;
}
DrawDiamond(BLACK);
}
else
{
current_max=current_max<diamond[0][0]?current_max:diamond[0][0];
for(i=0;i<4;i++) //and check for is there any row can be clear?
{
global[diamond[i][0]][diamond[i][1]]=1;
}
for(i=0;i<4;i++)
{
bool clear=true;
for(int m=0;m<16;m++)
{
if(global[diamond[i][0]][m]==0)
{
clear=false;
}
}
if(clear==true)
{
score+=10;
DownLine(hwnd,diamond[i][0]);
}
}
done=true;
}
}
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
FillRect(hdc,&rectLeft,WHITE_BRUSH);
FillRect(hdc,&rectRight,WHITE_BRUSH);
TextOut(hdc,50,30,"Next",strlen("Next"));
TextOut(hdc,700,30,"Level :",strlen("Level :"));
char p_int[4];
wsprintf(p_int,"%d",level);
TextOut(hdc,715,50,p_int,strlen(p_int));
TextOut(hdc,700,200,"Score :",strlen("Score :"));
wsprintf(p_int,"%d",score);
TextOut(hdc,715,220,p_int,strlen(p_int));
EndPaint(hwnd,&ps);
for(i=18;i>=current_max;i--)
{
for(int n=0;n<16;n++)
{
if(global[i][n]==1)
{
DrawUnit(hwnd,i,n,BLACK);
}
else
{
DrawUnit(hwnd,i,n,WHITE);
}
}
}
if(diamond[0][0]!=0 && diamond[0][1]!=0)
{
for(int m=0;m<4;m++)
{
DrawUnit(hwnd,diamond[m][0],diamond[m][1],BLACK);
}
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
void DrawUnit(HWND hwnd,int m,int n,int color)
{
HDC hdcNow=GetDC(hwnd);
if(color==WHITE)
{
SelectObject(hdcNow,CreatePen(NULL,NULL,RGB(208,221,238)));
SelectObject(hdcNow,(HBRUSH)CreateSolidBrush(RGB(208,221,238)));
}
Rectangle(hdcNow,32*n+150,32*m,32*n+150+32,32*m+32);
ReleaseDC(hwnd,hdcNow);
}
void DrawDiamond(int color)
{
DrawUnit(hwnd,diamond[0][0],diamond[0][1],color);
DrawUnit(hwnd,diamond[1][0],diamond[1][1],color);
DrawUnit(hwnd,diamond[2][0],diamond[2][1],color);
DrawUnit(hwnd,diamond[3][0],diamond[3][1],color);
}
void InitDiamond(HWND hwnd,int a,int b,int current_type)
{
int c=0,d=0,e=0,f=0,g=0,h=0;
switch(current_type)
{
case 0:
c=a+1;
d=b-1;
e=a+1;
f=b;
g=a+1;
h=b+1;
break;
case 1:
c=a+1;
d=b;
e=a+1;
f=b+1;
g=a+2;
h=b;
break;
case 2:
c=a;
d=b+1;
e=a;
f=b+2;
g=a+1;
h=b+1;
break;
case 3:
c=a+1;
d=b-1;
e=a+1;
f=b;
g=a+2;
h=b;
break;
case 4:
c=a;
d=b+1;
e=a+1;
f=b-1;
g=a+1;
h=b;
break;
case 5:
c=a+1;
d=b;
e=a+1;
f=b+1;
g=a+2;
h=b+1;
break;
case 6:
c=a;
d=b+1;
e=a+1;
f=b+1;
g=a+1;
h=b+2;
break;
case 7:
c=a+1;
d=b-1;
e=a+1;
f=b;
g=a+2;
h=b-1;
break;
case 8:
c=a;
d=b+1;
e=a+1;
f=b;
g=a+1;
h=b+1;
break;
case 9:
c=a+1;
d=b-2;
e=a+1;
f=b-1;
g=a+1;
h=b;
break;
case 10:
c=a+1;
d=b;
e=a+2;
f=b;
g=a+2;
h=b+1;
break;
case 11:
c=a;
d=b+1;
e=a;
f=b+2;
g=a+1;
h=b;
break;
case 12:
c=a;
d=b+1;
e=a+1;
f=b+1;
g=a+2;
h=b+1;
break;
case 13:
c=a+1;
d=b;
e=a+1;
f=b+1;
g=a+1;
h=b+2;
break;
case 14:
c=a;
d=b+1;
e=a+1;
f=b;
g=a+2;
h=b;
break;
case 15:
c=a;
d=b+1;
e=a;
f=b+2;
g=a+1;
h=b+2;
break;
case 16:
c=a+1;
d=b;
e=a+2;
f=b-1;
g=a+2;
h=b;
break;
case 17:
c=a+1;
d=b;
e=a+2;
f=b;
g=a+3;
h=b;
break;
case 18:
c=a;
d=b+1;
e=a;
f=b+2;
g=a;
h=b+3;
break;
}
diamond[0][0]=a;
diamond[0][1]=b;
diamond[1][0]=c;
diamond[1][1]=d;
diamond[2][0]=e;
diamond[2][1]=f;
diamond[3][0]=g;
diamond[3][1]=h;
}
void DownLine(HWND hwnd,int baseline)
{
for(int i=baseline;i>=current_max;i--)
{
for(int n=0;n<16;n++)
{
global[i][n]=global[i-1][n];
/* if(global[i][n]==0)
{
DrawUnit(hwnd,i,n,WHITE);
}
else
{
DrawUnit(hwnd,i,n,BLACK);
}*/
}
}
InvalidateRect(hwnd,NULL,FALSE);
}
bool CheckLeft()
{
bool canleft=true;
for(i=0;i<4;i++)
{
if(global[diamond[i][0]][diamond[i][1]-1]==1 || diamond[i][1]-1<0)
{
canleft=false;
}
}
return canleft;
}
void MoveLeft()
{
DrawDiamond(WHITE);
for(i=0;i<4;i++)
{
diamond[i][1]=diamond[i][1]-1;
}
DrawDiamond(BLACK);
}
bool CheckRight()
{
bool canright=true;
for(i=0;i<4;i++)
{
if(global[diamond[i][0]][diamond[i][1]+1]==1 || diamond[i][1]+1>15)
{
canright=false;
}
}
return canright;
}
void MoveRight()
{
DrawDiamond(WHITE);
for(i=0;i<4;i++)
{
diamond[i][1]=diamond[i][1]+1;
}
DrawDiamond(BLACK);
}
void DownQuickly()
{
bool down=true;
for(i=0;i<4;i++) //check for down
{
if(global[diamond[i][0]+2][diamond[i][1]]==1 || diamond[i][0]+2>=18)
{
down=false;
}
}
if(down==true)
{
DrawDiamond(WHITE);
for(i=0;i<4;i++)
{
diamond[i][0]=diamond[i][0]+2;
}
DrawDiamond(BLACK);
}
}
void Rotate()
{
int diamond_backup[4][2];
int new_type=0;
for(int m=0;m<4;m++)
{
for(int n=0;n<2;n++)
{
diamond_backup[m][n]=diamond[m][n];
}
}
bool can_rotate=true;
xBase=diamond[0][0];
yBase=diamond[0][1];
switch(current_type)
{
case 0:
new_type=1;
break;
case 1:
new_type=2;
yBase=diamond[0][1]-1;
break;
case 2:
new_type=3;
yBase=diamond[0][1]+1;
break;
case 3:
current_type=0;
break;
case 4:
new_type=5;
yBase=diamond[0][1]-1;
break;
case 5:
new_type=4;
yBase=diamond[0][1]+1;
break;
case 6:
new_type=7;
yBase=diamond[0][1]+1;
break;
case 7:
new_type=6;
yBase=diamond[0][1]-1;
break;
case 8:
new_type=8;
break;
case 9:
new_type=10;
yBase=diamond[0][1]-1;
break;
case 10:
new_type=11;
break;
case 11:
new_type=12;
break;
case 12:
new_type=9;
break;
case 13:
new_type=14;
break;
case 14:
new_type=15;
break;
case 15:
new_type=16;
break;
case 16:
new_type=13;
break;
case 17:
new_type=18;
break;
case 18:
new_type=17;
break;
}
InitDiamond(hwnd,xBase,yBase,new_type);
for(m=0;m<4;m++)
{
if(global[diamond[m][0]][diamond[m][1]]==1 || diamond[m][0]>18 || diamond[m][1]<0 || diamond[m][1]>15)
{
can_rotate=false;
}
}
if(current_type!=8 && can_rotate==true)
{
for(int m=0;m<4;m++)
{
for(int n=0;n<2;n++)
{
diamond[m][n]=diamond_backup[m][n];
}
}
DrawDiamond(WHITE);
current_type=new_type;
InitDiamond(hwnd,xBase,yBase,current_type);
DrawDiamond(BLACK);
}
if(can_rotate==false) //restore the diamond
{
for(int m=0;m<4;m++)
{
for(int n=0;n<2;n++)
{
diamond[m][n]=diamond_backup[m][n];
}
}
}
}