写俄罗斯方块联机游戏想法,源于到北京后的培训经历,那时候的老师是一个在华为经历几年开发经验和测试经验的高手,当他告诉我说:“听说你号称学过C++的时候”。也开始有想用C++写个小东西的想法。直到最近终于付诸于现实。
大学时间学习了MFC,对WINDOWS窗口的运行机制一窍不通,只会拖拖控件添加消息,是个准新手。于是开始看一些关于那方面的书和视频,主要是 《Windows程序设计》和孙鑫的c++视频第一、二章节。了解面向对象的基本概念和WINDWOS窗口的消息机制等基本的理论。有了这些基础后,大概就有个模型,觉得可以实现这个俄罗斯方块游戏。开始实际写代码。
所有复杂的东西都是由最简单的东西组成的,我所有的编程思路和实现都是基于这个简单的思路来做的。当然这个游戏很简单,对于一些有经验的朋友可以说是 一天半天就可以完成的,但是对于完全没有windwos窗口编程的新手来说,这会是一个让人务实,让人探索前进的思路。我坚信在开发进行中的所有困难或BUG都是因为一个很简单的错误而出现的。我能做的就是不停的实验和测试来实现。在这方面,测试的经验给了我不少的帮助。让我在出现问题的时候,有大量的想法去测试寻找问题的缘由,+上自己的耐心,所有的问题都迎刃而解。
实际过程:
1 对话框: 最开始,什么都不想,要玩游戏就得有个窗口。我用createwindow把里面大部分的窗口类型都组合测试了一边,最终才选定用一个没有最大化最小化按钮、没有改变大小边框的对话框窗口来实现。
2 游戏界面:用什么实现方块。有很多想法,用一张画好的图片,做方块格子,也想过用按钮。最后想想就用一个彩色矩形代表一个方块最简单。FillRect();
3 游戏方块: 接着用设计好游戏规格,方块大小,游戏界面宽高。就用FillRect()画个黑色矩形来表示游戏方块。现在想想其实建立一个子窗口做界面是最方便的了 。
4 显示第一个方块:游戏对话框有了,游戏界面有了,于是我试着在黑色矩形游戏界面中画第一个方块,是一个直条。这也是我第一次接触到WM_PAINT消息。第一次知道窗口的重绘。刚开始的时候,出现很多的问题,不是只有直条就是只有游戏界面。在重绘函数里面有很多错误的代码,走了很多湾路。光为了在游戏界面中画出一个直条我就画了两天,终于才明白重绘的原理和基本的函数的使用。当我在游戏界面中出现第一个直条的时候,我非常兴奋,我觉得这个是一个很好的开始,起码证明了我的方法在一定程度上是可行的。意味着前面的工作都没白费。给了我很大的鼓舞。
5 设计方块基类: 有了前面的基础,我就坚信可以完成。我觉得方块基类是整个游戏的基础, 一定要先确定好的,于是设计了一个4维的数组来表达7类方块20多种的变化。这样在游戏中需要方块的数据的时候都可以从中提取。其实最开始的时候在这块想了很多,因为不确定后面到底要怎么样用到方块,承前启后的想了很久,既要考虑到后面的使用,又要尽量简单,最开始的时候还想用vector来实现,于是还顺便学习了关于容器的内容,怎么使用怎么初始化等等。不过最后还是否定了这个方案。
6 设计游戏类:其实不懂面向对象,只是觉得,不同类型的要分块。你只管提供数据,我只管操作。于是就设计了游戏类。
当时也不知道游戏类里面到底需要什么方法,只是觉得有些方法是必须要的。比如 移动 下降 消行 游戏开始 游戏结束 游戏暂停等。也不想那么多,一股脑的都+上。
7 游戏运行机制:是游戏就要有开始,就要有结束,要有运行。看别人的代码都写的很好,一个死循环就可以让游戏不停运行。我想往上套,始终也不行。只能另想办法。最后因为方块游戏的运行就是下降。所以我只要弄一个函数不停的调用下降,就能实现游戏运行的原理。至于什么时候下降停止。那可以具体再写。我觉得这样是对的。最终找到了SETTIMMER来实现
8 游戏算法实现:当我第一次看到,随机生成的方块,在游戏界面里缓缓下降的时候。。。 我心里那个美啊。。 我知道我对了,胜利在望了。接下的东西就是具体的游戏功能的写作,一切都顺利了许多,我只是不停的测试+写+测试。完成。在写完之前我开始想着,下一步的实现。网络版
9 单机游戏完成: 所有的都完成,单机游戏终于完成后,自己也是不停的测试,优化算法,这中间还出现内存泄露的严重问题,也因祸得福了解了内存的基本使用。直到修复问题。最终单机版的无bug版完成。我中间公司的项目也多了老加班,就先放下了。
10 网络版的孕育: 07年同学在武汉,有个朋友介绍他去干开发的工作。那边的人说了,在一个月之内,如果开发出一个网络版的俄罗斯方块游戏,那么OK,来上班。我想起这见事情,于是我想着能否实现它。其实这还是做一个测试的一个心结。自己也有心思转开发,所以决定去实现这个。
11 网络版的实现过程: 因为整个游戏只有两个类,所有我觉得给网络功能这块+一个类。所有的网络功能都在那里实现,在开发的过程中发现,由于没有很好的设计,导致在实现的时候出现很多的矛盾。从而我也认识到设计和算法在软件开发中的重要性。跌跌撞撞的用WIndows socket使用UDP的协议实现了联机通讯,中间专门先实验几个通讯小例子,再把觉得可用的代码用上,现在基本的联机功能都以实现。很想模仿腾讯QQ火拼俄罗斯游戏开发游戏道具。但目前也只停留在想的阶段。
.
游戏介绍:
1 单机版和网络版并存
2 网络版:实现在线用户实时状态显示,(空闲中 游戏中 离线)
3 网络版:邀请对方联机对战。若对方状态不可以邀请,则不能邀请
4 网络版:双人联机对战实现,可以看到对方实时的方块数据。游戏胜负根据率先到达10000分的一方获胜
5 网络版道具使用: 酝酿中。。。。。。。
结束语: 第一个C++ WIN232的程序,虽然只是个小游戏,但也给了我一些信心和鼓舞,希望有机会能正式加入程序员阵营中来,目前职位还是测试工作,想这下一步的开发方向该怎么走。希望各位同仁多多指教,给点建议。多谢啦。
下载地址:http://download.csdn.net/source/727355
部分源码:
Gameframe.h
- #include "GameNet.h"
- #ifndef _GAMEFRAME_H_
- #define _GAMEFRAME_H_
- using namespace std;
- #define SingleRect 30 //单个方块大小
- #define FRAME_L 15 //主界面的起点坐标 L
- #define FRAME_T 15 //主界面的起点坐标 T
- #define NEXT_L SingleRect*10+FRAME_L+15 //下一个方块的起点座标 L
- #define NEXT_T FRAME_T //下一个方块的起点座标 T
- #define MAIN_SIZE_R SingleRect*10+FRAME_L //主界面x_x
- #define MAIN_SIZE_B SingleRect*20+FRAME_T //主界面y_y
- #define NEXT_SIZE_R SingleRect*4+NEXT_L+20 //下一个方块x_x
- #define NEXT_SIZE_B SingleRect*4+NEXT_T+20 //下一个方块y_y
- class Gameframe:public GameNet
- {
- public:
- Gameframe();
- virtual ~Gameframe();
- void Draw_Frame(HDC hDC,HWND hwnd,HBRUSH G_brush);
- void Draw_Next(HDC hDC,HWND hwnd,HBRUSH G_brush);
- void Draw_Message(HDC hDC,HWND hwnd,HBRUSH G_brush);
- void Draw_Child(HDC hDC,HWND hwnd,HBRUSH G_brush);
- void Game_Start();
- bool G_Stop;
- bool Game_Over();
- void Game_Run();
- void Game_Down();
- void Game_Change();
- bool Game_Move(int i);
- void Game_Stop();
- void Game_Restart();
- void Game_Sound(unsigned short int sound);
- bool Down_end;
- bool Space_on;
- char G_Path[100];
- protected:
- void Next_Rand();
- RECT N;
- RECT F;
- RECT Active_Rect;
- RECT Total;
- RECT re;
- unsigned short int Actvie_bottom;
- Square squ;
- short int Next_A;
- short int Next_B;
- short int Frame_A;
- short int Frame_B;
- short int Move;
- short int Down;
- short int Now_Cake[4][2];
- short int Old_Cake[4][2];
- short int Top;
- bool Gframe[10][20];
- unsigned short int G_Level;
- int Rect_Falling;
- short int Gframe_Color[10][20];
- short int Rect_Color;
- short int Rect_Color_N;
- COLORREF G_BasicColor[7];
- bool Game_Active(int Event);
- bool Game_DelRect();
- private:
- };
- #endif
Gamefrme.cpp
- #include "Gameframe.h"
- int Move_temp;
- extern HINSTANCE h_inst;
- extern HWND hwnd;
- extern HWND U_hwnd;
- void Gameframe::Draw_Next(HDC hDC,HWND hwnd,HBRUSH G_brush)
- {
- N.left=Total.left;
- FillRect(hDC,&N,G_brush);
- FillRect(hDC,&Total,G_brush);
-
- SetDCBrushColor(hDC,G_BasicColor[Rect_Color_N]);
- for(int c=0;c<4;c++)
- {
- for(int d=0;d<4;d++)
- {
- if(1==squ.Nextframe[Next_A][Next_B][d][c])
- {
- SetRect(&re,NEXT_L+c*30+1+10,NEXT_T+d*30+1+10,NEXT_L+c*30+29+10,NEXT_T+d*30+29+10);
- FillRect(hDC,&re,G_brush);
- }
- }
- }
- char szChar[25];
- sprintf(szChar,"%d VS %d",Game_Point,Child_Point);
- unsigned short int count=0,i=0;
- while(szChar[i] != '/0')
- {
- count++;
- i++;
- }
- TextOut(hDC,NEXT_L+20,NEXT_T+185,szChar,count);
- }
- void Gameframe::Draw_Frame(HDC hDC,HWND hwnd,HBRUSH G_brush)
- {
- SetDCBrushColor(hDC,RGB(0,0,0));
- FillRect(hDC,&F,G_brush);
- for(unsigned short int o=0;o<10;o++)
- {
- for(unsigned short int p=0;p<20;p++)
- {
- if(1==Gframe[o][p])
- {
- SetDCBrushColor(hDC,G_BasicColor[Gframe_Color[o][p]]);
- SetRect(&re,FRAME_L+o*30+1,FRAME_T+p*30+1,FRAME_L+o*30+29,FRAME_T+p*30+29);
- FillRect(hDC,&re,G_brush);
- }
- }
- }
- if(G_Over)
- {
- if(G_Level>9)
- {
- G_Level=1;
- TextOut(hDC,FRAME_L+100,FRAME_T+270,"通关了!厉害",strlen(" "));
- }
- else
- {
- if(!Arrive)
- {
- TextOut(hDC,FRAME_L+100,FRAME_T+270,"GAME OVER",strlen("GAME OVER"));
- }
- else
- {
- TextOut(hDC,FRAME_L+100,FRAME_T+270,"YOU'RE WINNER",strlen("YOU'RE WINNER"));
- }
- }
- }
- }
- void Gameframe::Draw_Message(HDC hDC,HWND hwnd,HBRUSH G_brush)
- {
- SetDCBrushColor(hDC,RGB(255,255,255));
- SetTextColor(hDC,RGB(0,0,0));
- FillRect(hDC,&Info,G_brush);
- DrawText(hDC,InfoChar,strlen(InfoChar),&Info,DT_LEFT);
- }
- void Gameframe::Draw_Child(HDC hDC,HWND hwnd,HBRUSH G_brush)
- {
- SetDCBrushColor(hDC,RGB(0,0,0));
- SetRect(&re,0,0,200,400);
- FillRect(hDC,&re,G_brush);
- for(unsigned short int o=0;o<10;o++)
- {
- for(unsigned short int p=0;p<20;p++)
- {
- if(0!=Child_Frame[o][p])
- {
- SetDCBrushColor(hDC,G_BasicColor[Child_Frame[o][p]-1]);
- SetRect(&re,o*20+1,p*20+1,o*20+19,p*20+19);
- FillRect(hDC,&re,G_brush);
- }
- }
- }
- }
- Gameframe::Gameframe()
- {
-
- SetRect(&F,FRAME_L,FRAME_T,MAIN_SIZE_R,MAIN_SIZE_B);
- SetRect(&N,NEXT_L,NEXT_T,NEXT_SIZE_R,NEXT_SIZE_B);
- SetRect(&Total,NEXT_L,NEXT_T+170,NEXT_SIZE_R,NEXT_SIZE_B+80);
- SetRect(&Info,NEXT_SIZE_R+FRAME_L+FRAME_L,FRAME_T+400+20,NEXT_SIZE_R+FRAME_L+FRAME_L+200,FRAME_T+400+20+100);
-
- G_BasicColor[0] = RGB(220, 39, 75);
- G_BasicColor[1] = RGB(232, 123, 20);
- G_BasicColor[2] = RGB(200, 200, 102);
- G_BasicColor[3] = RGB(51, 204, 102);
- G_BasicColor[4] = RGB(0, 143, 224);
- G_BasicColor[5] = RGB(153, 153, 204);
- G_BasicColor[6] = RGB(204, 204, 204);
-
- getcwd(G_Path,80);
- strcat(G_Path,"//resource//Wav//");
- G_NET=false;
- this->Game_Restart();
- }
- Gameframe::~Gameframe()
- {
- squ.~Square();
- }
- void Gameframe::Game_Start()
- {
-
- Next_Rand();
- unsigned short int left=0,top=0,right=0,bottom=0;
- for(unsigned short int h=0;h<4;h++)
- {
- if(left>Now_Cake[h][0])
- {
- left=Now_Cake[h][0];
- }
- if(right
- {
- right=Now_Cake[h][0];
- }
- if(bottom
- {
- bottom=Now_Cake[h][1];
- }
- Actvie_bottom=bottom+1;
- SetRect(&Active_Rect,FRAME_L+left*30+90,FRAME_T+top*30,FRAME_L+right*30+30+90,FRAME_T+bottom*30+30);
- }
- if(Game_Over())
- {
- if(G_NET)
- {
- if(!Arrive)
- {
- SendSelect(8);
- }
- Game_Run();
- return;
- }
- G_start=false;
- G_Over=true;
- Rect_Falling=1000;
- Next_Rand();
- Game_Sound(2);
- KillTimer(hwnd,TIMER_ID);
- InvalidateRect(hwnd,NULL,false);
- }
- else
- {
- InvalidateRect(hwnd,&Active_Rect,false);
- InvalidateRect(hwnd,&N,false);
- Game_Run();
- }
- }
- bool Gameframe::Game_Over()
- {
- if(G_Over)
- {
- return G_Over;
- }
- for(unsigned short int a=0;a<4;a++)
- {
- if(1==Gframe[Now_Cake[a][0]][Now_Cake[a][1]])
- {
- G_Over=true;
- }
- else
- {
- Gframe[Now_Cake[a][0]][Now_Cake[a][1]]=1;
- Gframe_Color[Now_Cake[a][0]][Now_Cake[a][1]]=Rect_Color;
- }
- }
- if(G_Over)
- {
- return G_Over;
- }
- else
- {
- for(unsigned short int b=0;b<4;b++)
- {
- Gframe[Now_Cake[b][0]][Now_Cake[b][1]]=1;
- }
- return G_Over;
- }
- return G_Over;
- }
- void Gameframe::Game_Run()
- {
- if(G_Over)
- {
- KillTimer(hwnd,TIMER_ID);
- if(G_NET)
- {
- G_NET=false;
- G_start=false;
- SendSelect(11);
- ::SendMessage(U_hwnd,WM_COMMAND,LBN_SELCHANGE,0);
- if(Arrive)
- {
- Game_Sound(7);
- }
- else
- {
- Game_Sound(2);
- }
- InvalidateRect(hwnd,&F,false);
- return;
- }
- }
- else
- {
- if(!G_NET)
- {
- G_Level=Game_Point/1000;
- if(G_Level<10)
- {
- Rect_Falling=1000-G_Level*100;
- SetTimer(hwnd,TIMER_ID,Rect_Falling,NULL);
- }
- else
- {
- G_start=false;
- G_Over=true;
- Game_Sound(7);
- Rect_Falling=1000;
- KillTimer(hwnd,TIMER_ID);
- InvalidateRect(hwnd,NULL,false);
- }
- }
- else
- {
- SetTimer(hwnd,TIMER_ID,NET_SPEED,NULL);
- }
- }
- }
- void Gameframe::Game_Stop()
- {
- G_Stop=true;
- KillTimer(hwnd,TIMER_ID);
- }
- bool Gameframe::Game_Move(int i)
- {
- Move_temp=i;
- if(Game_Active(2))
- {
- if(1==i)
- {
- Active_Rect.right=Active_Rect.right+i*30;
- InvalidateRect(hwnd,&Active_Rect,false);
- Active_Rect.left=Active_Rect.left+i*30;
- }
- else
- {
- Active_Rect.left=Active_Rect.left+i*30;
- InvalidateRect(hwnd,&Active_Rect,false);
- Active_Rect.right=Active_Rect.right+i*30;
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- void Gameframe::Game_Down()
- {
- if(G_Over)
- {
- Game_Run();
- }
- if(Down<19)
- {
- Down=Down+1;
- }
- else
- {
- Down=0;
- }
- if(Game_Active(1))
- {
- Down_end=true;
- Active_Rect.bottom=Active_Rect.bottom+30;
- Actvie_bottom=Actvie_bottom+1;
- if(!Space_on)
- {
- InvalidateRect(hwnd,&Active_Rect,false);
- }
- Active_Rect.top=Active_Rect.top+30;
- }
- else
- {
- Game_Sound(4);
- if(G_NET)
- {
- SendSelect(5);
- }
- Space_on=false;
- if(!Game_DelRect())
- {
- InvalidateRect(hwnd,&F,false);
- }
- Down_end=false;
- Game_Start();
- }
- }
- void Gameframe::Game_Change()
- {
- Frame_B=Frame_B+1;
- if(6==Frame_A||5==Frame_A||2==Frame_A)
- {
- if(Frame_B>3)
- {
- Frame_B=0;
- }
- }
- else
- {
- if(Frame_B>1)
- {
- Frame_B=0;
- }
- }
- if(Game_Active(3))
- {
- Game_Sound(6);
- InvalidateRect(hwnd,&Active_Rect,false);
- short int left=0,top=0,right=0,bottom=0,k=0;
- for(short int h=0;h<4;h++)
- {
- if(left>Now_Cake[h][k])
- {
- left=Now_Cake[h][k];
- }
- if(right
- {
- right=Now_Cake[h][k];
- }
- if(bottom
- {
- bottom=Now_Cake[h][k+1];
- }
- if(top>Now_Cake[h][k+1])
- {
- top=Now_Cake[h][k+1];
- }
- }
- Actvie_bottom=bottom+1;
- SetRect(&Active_Rect,FRAME_L+left*30,FRAME_T+top*30,FRAME_L+right*30+30,FRAME_T+bottom*30+30);
- InvalidateRect(hwnd,&Active_Rect,false);
- }
- else
- {
- if(6==Frame_A||5==Frame_A||2==Frame_A)
- {
- if(Frame_B>=1)
- {
- Frame_B=Frame_B-1;
- }
- else
- {
- Frame_B=Frame_B+3;
- }
- }
- else
- {
- if(Frame_B>=1)
- {
- Frame_B=Frame_B-1;
- }
- else
- {
- Frame_B=Frame_B+1;
- }
- }
- InvalidateRect(hwnd,&F,false);
- }
- }
- bool Gameframe::Game_DelRect()
- {
- int del=0,Count=0;
- bool re=false;
- for(short int a=19;a>=Top;a--)
- {
- for(short int b=0;b<10;b++)
- {
- if(1==Gframe[b][a])
- {
- del=del+1;
- }
- }
- if(10==del)
- {
- Count=Count+1;
- for(a;a>=0;a--)
- {
- if(0==a)
- {
- for(short int d=0;d<10;d++)
- {
- Gframe[d][a]=false;
- Gframe_Color[d][a]=0;
- }
- }
- else
- {
- for(short int c=0;c<10;c++)
- {
- Gframe[c][a]=Gframe[c][a-1];
- Gframe_Color[c][a]=Gframe_Color[c][a-1];
- }
- }
- }
- a=20;
- Top=Top+1;
- }
- del=0;
- }
- switch(Count)
- {
- case 1:
- re=true;
- Game_Sound(5);
- Game_Point=Game_Point+100;
- InvalidateRect(hwnd,NULL,false);
- break;
- case 2:
- re=true;
- Game_Sound(5);
- Game_Point=Game_Point+300;
- InvalidateRect(hwnd,NULL,false);
- break;
- case 3:
- re=true;
- Game_Sound(5);
- Game_Point=Game_Point+500;
- InvalidateRect(hwnd,NULL,false);
- break;
- case 4:
- re=true;
- Game_Sound(5);
- Game_Point=Game_Point+800;
- InvalidateRect(hwnd,NULL,false);
- break;
- default:
- break;
- }
- if(G_NET)
- {
- if(Count>0)
- {
- SendInfo[1]=Count;
- SendSelect(6);
- if(Game_Point>=Aim)
- {
- SendSelect(7);
- }
- }
- }
- return re;
- }
- void Gameframe::Game_Restart()
- {
-
- for(unsigned short int a1=0;a1<20;a1++)
- {
- for(unsigned short int b1=0;b1<10;b1++)
- {
- Gframe[b1][a1]=0;
- Gframe_Color[b1][a1]=0;
- Child_Frame[b1][a1]=0;
- }
- }
-
- for(unsigned short int j=0;j<4;j++)
- {
- for(unsigned short int k=0;k<2;k++)
- {
- Now_Cake[j][k]=0;
- Old_Cake[j][k]=0;
- }
- }
-
- struct _timeb timebuffer;
- _ftime(&timebuffer);
- unsigned short int tem=timebuffer.millitm;
- unsigned short int a=tem%7;
- short int b=0;
- srand(tem);
- if(6==a||5==a||2==a)
- {
- b=timebuffer.millitm%4;
- }
- else
- {
- b=timebuffer.millitm%2;
- }
- Frame_A=Next_A=a;
- Frame_B=Next_B=b;
- Rect_Color=Rect_Color_N=rand()%7;
-
- Down_end=true;
- Rect_Falling=1000;
- G_start=false;
- G_Over=false;
- G_Stop=false;
- Arrive=false;
- Top=19;
- Game_Point=0;
- Child_Point=0;
- Down=0;
- Move=0;
- G_Level=0;
- Space_on=false;
- InvalidateRect(hwnd,NULL,false);
- }
- bool Gameframe::Game_Active(int Event)
- {
- return ture;
- }