先说这种俄罗斯方块的游戏规则('w','a','s','d' -> 旋转,左边,快速下降,右边):
1、右边4x4方块群内左键自造积木,右键放下积木(只有等当前积木下落停靠后,右键放下新的积木才有效)。
2、右面的墙是粘性墙,会黏住最右边的积木而只能下降不能向左(这会形成分散型积木,从而出现真空静止的积木)。
3、靠上固定的积木就会一同固定(也就是说每块积木之间都有粘性)


左手键盘wasd,右手(或者女朋友的手)操作鼠标左键来构造新积木,右键放下构造的积木。




总共237行,代码如下:

(VC08下编译通过)
 1/* SelfTetris.h */
 2
 3
 4#include <windows.h>
 5
 6class SelfTetris 
 7{
 8#define DELTA_LEFTTOP 20
 9#define PV(v) (DELTA_LEFTTOP+(v)*D_LEN)
10#define BIN_FOR_BEGINE(i,j,topi,topj)  for(i=0;i!=(topi);++i)for(j=0;j!=(topj);++j) 
11public:
12    void Action();
13    int  IsMove(int x,int y);/* 是否能向(x,y)向量移动 */
14    int  IsDis(int y);/* 是否消除第y行 */
15    int  GoCurdle(int x,int y,int isFall,int isX);/* 按(x,y)向量*/
16    void KeyDown(WPARAM wparam);
17    void Run(int x,int y,int isX);/* 一次移动 */
18    void RotateBlocks();
19    void CastBlocks();
20    void SetBlocks(int mx,int my);
21    int  Rectangle(int i,int j,int isStill);/* 在游戏矩阵内画矩形,isStill为是否画静止类型的矩形 */
22    SelfTetris(int dtime_=100);
23public:
24    static const int W_NUM=18,H_NUM=35,D_LEN=15,H_HIDE=1;/* 游戏区域宽,高,单位长度象素,顶部是否隐藏*/
25    int canDrop,_x,_y,obj[4][4];/* _x,_y 为当前下落积木重心 ,obj为当前构造积木形状, canDrop为是否可下新积木*/
26    int scores;/* 分数,临时变量*/
27    int board[H_NUM][W_NUM];/* 俄罗斯方块游戏区域矩阵 */
28    int x,y,dtime,i,j;/* x,y,i,j为临时变量 dtime为游戏action周期*/
29    HDC hdc;
30}
;
31



  1/* SelfTetris.cpp */
  2
  3#include "SelfTetris.h"
  4
  5int SelfTetris::Rectangle(int i,int j,int isStill)
  6{
  7    isStill=isStill?GRAY_BRUSH:WHITE_BRUSH;
  8    SelectObject (hdc, GetStockObject (isStill)) ;
  9    ::Rectangle(hdc,PV(j),PV(i),PV(j+1),PV(i+1));
 10    SelectObject (hdc, GetStockObject (GRAY_BRUSH)) ;
 11    return 0;
 12}

 13int SelfTetris::IsMove(int x,int y)
 14{
 15    BIN_FOR_BEGINE(i,j,H_NUM,W_NUM)
 16        if((board[i][j]==2)&&((i+y>=H_NUM||i+y<=-1)||(board[i+y][j+x]==1)))
 17            return -1;
 18        else if((board[i][j]==2)&&((j+x>=W_NUM||j+x<=-1)))
 19            return 0;
 20    return 1;
 21}

 22int SelfTetris::IsDis(int y)
 23{
 24    for(j=0;j!=W_NUM;j++)
 25        if(board[y][j]!=1return 0;
 26    for(j=0;j!=W_NUM;j++) board[y][j]=0;
 27    for(int i=y-1;i!=-1;--i)
 28        for(int j=0;j!=W_NUM;++j)
 29            if(board[i][j]==1)
 30            {
 31                board[i+1][j]=1;
 32                i>=H_HIDE?Rectangle(i+1,j,1):1;
 33                board[i][j]=0;
 34            }

 35            return 1;
 36}

 37int SelfTetris::GoCurdle(int x,int y,int isFall,int isX)
 38{
 39    int tag=0,a,b,d;
 40    a=W_NUM-1,b=-1,d=-1;
 41    if(x==-1) b=W_NUM-1,a=0,d=1;
 42    for(i=H_NUM-1;i!=-1;--i)
 43        for(j=a;j!=b;j+=d)
 44            if(board[i][j]==2)
 45            {
 46                if(isFall==-1){
 47                    canDrop=1;
 48                    board[i][j]=1;
 49                    i>=H_HIDE&&isX==0?Rectangle(i,j,1):1
 50                }
else  if(isFall==1)
 51                {
 52                    board[i+y][j+x]=2,board[i][j]=0;
 53                    i>=H_HIDE&&isX==0?Rectangle(i+y,j+x,0):1
 54                    tag=1;
 55                }

 56            }
else if(board[i][j]==1)
 57                i>=H_HIDE&&isX==0?Rectangle(i,j,1):1;
 58    if(tag==1) _x+=x,_y+=y;
 59    if(isX==0)
 60      BIN_FOR_BEGINE(i,j,4,4)
 61        Rectangle(H_NUM/2+4+i,W_NUM+4+j,!(obj[i][j]==1));
 62    return isFall;
 63}

 64void SelfTetris::KeyDown(WPARAM wparam)
 65{
 66    switch (wparam)
 67    {
 68    case 0x41:i=-1;break;
 69    case 0x57: RotateBlocks();break;
 70    case 0x53:i=2;break;
 71    case 0x44:i=1;
 72    }

 73}

 74void SelfTetris::Run(int x,int y,int isX)
 75{    
 76    SelectObject (hdc, GetStockObject (BLACK_PEN)) ;
 77    ::Rectangle(hdc,DELTA_LEFTTOP,DELTA_LEFTTOP+H_HIDE*D_LEN,DELTA_LEFTTOP+W_NUM*D_LEN,DELTA_LEFTTOP+H_NUM*D_LEN);
 78    SelectObject (hdc, GetStockObject (GRAY_BRUSH)) ;
 79    int mul=0;
 80    GoCurdle(x,y,IsMove(x,y),isX);
 81    for(i=0;i!=H_NUM;i++)
 82        IsDis(i)?++mul>=2?scores+=10*mul:scores+=10:1;
 83    static wchar_t str[40];
 84    SelectObject (hdc, GetStockObject (BLACK_PEN));
 85    wsprintf(str,L" Total Score : %d ",scores);
 86    TextOut(hdc,320,200,str,wcslen(str));
 87    wsprintf(str,L" Game Level : %d ",scores/10+1);
 88    TextOut(hdc,320,250,str,wcslen(str));
 89}

 90
 91void SelfTetris::RotateBlocks()
 92{
 93    int _board[H_NUM][W_NUM]={0};
 94    BIN_FOR_BEGINE(x,y,H_NUM,W_NUM)
 95        if(board[x][y]==2)
 96            if((_x+_y-x)>=W_NUM||(_x+_y-x)<=-1||(_y-(_x-y))>=H_NUM||
 97                (_y-(_x-y))<=-1||board[_y-(_x-y)][_x+(_y-x)]==1)
 98                return;
 99    BIN_FOR_BEGINE(x,y,H_NUM,W_NUM)
100        if(board[x][y]==2)
101            board[x][y]=0,_board[_y-(_x-y)][_x+(_y-x)]=2;
102    BIN_FOR_BEGINE(x,y,H_NUM,W_NUM)
103        if(_board[x][y]==2)
104            board[x][y]=_board[x][y];
105}

106void SelfTetris::SetBlocks(int mx,int my)
107{
108    BIN_FOR_BEGINE(x,y,4,4)
109        if(my>PV(H_NUM/2+4+x)&&
110            my<PV(H_NUM/2+4+x+1)&&
111            mx>PV(W_NUM+4+y)&&
112            mx<PV(W_NUM+4+y+1))
113            obj[x][y]=(obj[x][y]+1)%2;
114}

115void SelfTetris::CastBlocks()
116{
117    if(canDrop==0)
118        return;
119    BIN_FOR_BEGINE(x,y,4,4)
120        if(obj[x][y]==1)
121            board[0+x][W_NUM/2+y]=2;
122    canDrop=0;
123    _x=W_NUM/2+2;
124    _y=2;
125}

126void SelfTetris::Action()
127{
128    if(i==2)  Run(0,1,1);
129    else if(i!=0) Run(i,0,1);
130    for(x=0;x!=scores/10+1;x++)
131        Run(0,1,0);
132    i=0;
133}

134SelfTetris::SelfTetris(int dtime_)
135{
136    canDrop=0;
137    memset(obj,0,sizeof(int)*16);
138    memset(board,0,sizeof(int)*H_NUM*W_NUM);
139    board[0][W_NUM/2-1]=board[0][W_NUM/2+2]=board[0][W_NUM/2+4]=board[0][W_NUM/2+3]=2;
140    _x=W_NUM/2+2;
141    _y=2;
142    i=j=0;
143    scores=0;
144    dtime=dtime_;
145}


 1/* TetrisGame.cpp */
 2
 3#include  "SelfTetris.h"
 4
 5SelfTetris aTetris(100);
 6
 7LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
 8{
 9    aTetris.hdc=GetDC(hwnd);
10    int    mx = (int)LOWORD(lparam),my = (int)HIWORD(lparam);
11    switch(msg)
12    {
13    case WM_KEYDOWN:
14        aTetris.KeyDown(wparam);
15        break;
16    case WM_LBUTTONDOWN:
17        aTetris.SetBlocks(mx,my);
18        break;
19    case WM_RBUTTONUP:
20        aTetris.CastBlocks();
21        break;
22    case WM_CREATE:
23        SetTimer(hwnd,10,aTetris.dtime,0);
24        break;
25    case WM_TIMER:
26
27        aTetris.Action();
28        break;
29    case WM_PAINT:
30        break;
31    case WM_CLOSE :
32        MessageBoxW(0,L"非常感谢测试~",L"SelfTetrisv1.0",0);
33        break;
34    case WM_QUIT:
35    case WM_DESTROY:
36        PostQuitMessage(0);
37        break;
38    default:break;
39    }

40    ReleaseDC(hwnd,aTetris.hdc);
41    return DefWindowProc(hwnd, msg, wparam, lparam);
42}
 
43
44
45int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR lpcmdline,int ncmdshow)
46{
47    WNDCLASSEX winclass={sizeof(WNDCLASSEX),CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
48        WindowProc,0,0,hinstance,LoadIcon(NULL, IDI_APPLICATION),
49        LoadCursor(NULL, IDC_ARROW),(HBRUSH__*)GetStockObject(BLACK_BRUSH),0,
50        L"SelfTetris",0}
;
51    HWND  hwnd;   
52    MSG   msg;   
53    if (!RegisterClassEx(&winclass))
54        return 0;
55    if (!(hwnd = CreateWindowEx(NULL,L"SelfTetris",L"SelfTetrisV1.0",
56        WS_OVERLAPPEDWINDOW | WS_VISIBLE,0,0,455,600,NULL,NULL,hinstance,NULL)))   
57        return 0;
58
59    while(GetMessage(&msg,NULL,0,0))
60    {
61        TranslateMessage(&msg);
62        DispatchMessage(&msg);
63    }

64    return msg.wParam;
65}
 

源文件这里下载: SelfTetrisV1.1.rar