c win32 API实现方块联机游戏历程
先简单介绍下自己的情况,2006年普通大专院校毕业,毕业后到了北京参加软件测试的
培训
焊锡培训资料ppt免费下载焊接培训教程 ppt 下载特设培训下载班长管理培训下载培训时间表下载
,目前做ASP.NET网站安全等方面的测试。很多人都说技术不好才去做测试的,很不幸言中了,我当时我的情况确实是这样的,这大概也是很多做测试的朋友心中的一个老梗。即使工作了,心中的梦魇一直没能除去,所以决定试试自己到底能不能写点东西。在工作期间,自学SQLSERVER+ASP.NET 在工作一年后正式参与网站开发。
写俄罗斯方块联机游戏想法,源于到北京后的培训经历,那时候的老师是一个在华为经历几年开发经验和测试经验的高手,当他告诉我说:“听说你号称学过C++的时候”,我心里其实蛮惭愧的,因为确实不懂。从此C++这东西,基本是心中不堪回首的回忆。也开始有想用C++写个小东西的想法。直到最近终于付诸于现实。
大学时间学习了MFC,对WINDOWS窗口的运行机制一窍不通,只会拖拖控件添加消息,是个准新手。于是开始看一些关于那方面的书和视频,主要是 《Windows程序
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
》和孙鑫老师的c++视频第一、二章节。了解面向对象的基本概念和WINDWOS窗口的消息机制等基本的理论。有了这些基础后,脑袋里大概就有个模型,觉得可以实现这个俄罗斯方块游戏。开始实际写代码。
我坚信所有复杂的东西都是由最简单的东西组成的,我所有的编程思路和实现都是基于这个简单的思路来做的。当然这个游戏很简单,对于一些有经验的朋友可以说是 一天半天就可以完成的,但是对于完全没有windwos窗口编程的新手来说,这会是一个让人务实,让人探索前进的思路。我坚信在开发进行中的所有困难或BUG都是因为一个很简单的错误而出现的。我能做的就是不停的实验和测试来实现。在这方面,测试的经验给了我不少的帮助。让我在出现问题的时候,有大量的想法去测试寻找问题的缘由,+上自己的耐心,所有的问题都迎刃而解。
实际过程:
1 对话框: 最开始,什么都不想,要玩游戏就得有个窗口。我用createwindow把里面大部分的窗口类型都组合测试了一边,最终才选定用一个没有最大化最小化按钮、没有改变大小边框的对话框窗口来实现。
2 游戏界面:用什么实现方块。有很多想法,用一张画好的图片,做方块格子,也想过用按钮。最后想想就用一个彩色矩形代
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
一个方块最简单。FillRect();
3 游戏方块: 接着用设计好游戏规格,方块大小,游戏界面宽高。就用FillRect()画个黑色矩形来表示游戏方块。现在想想其实建立一个子窗口做界面是最方便的了 .
4 显示第一个方块:游戏对话框有了,游戏界面有了,于是我试着在黑色矩形游戏界面中画第一个方块,是一个直条。这也是我第一次接触到WM_PAINT消息。第一次知道窗口的重绘。刚开始的时候,出现很多的问题,不是只有直条就是只有游戏界面。在重绘函数里面有很多错误的代码,走了很多湾路。光为了在游戏界面中画出一个直条我就画了两天,终于才明白重绘的原理和基本的函数的使用。当我在游戏界面中出现第一个直条的时候,我非常兴奋,我觉得这个是一个很好的开始,起码证明了我的
方法
快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载
在一定程度上是可行的。意味着前面的工作都没白费。给了我很大的鼓舞。
5 设计方块基类: 有了前面的基础,我就坚信可以完成。我觉得方块基类是整个游戏的基础, 一定要先确定好的,于是设计了一个4维的数组来表达7类方块20多种的变化。这样在游戏中需要方块的数据的时候都可以从中提取。其实最开始的时候在这块想了很多,因为不确定后面到底要怎么样用到方块,承前启后的想了很久,既要考虑到后面的使用,又要尽量简单,最开始的时候还想用vector来实现,于是还顺便学习了关于容器的内容,怎么使用怎么初始化等等。不过最后还是否定了这个
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
。
6 设计游戏类:其实不懂面向对象,只是觉得,不同类型的要分块。你只管提供数据,我只管操作。于是就设计了游戏类。
移 当时也不知道游戏类里面到底需要什么方法,只是觉得有些方法是必须要的。比如 动 下降 消行 游戏开始 游戏结束 游戏暂停等。也不想那么多,一股脑的都+上。
7 游戏运行机制:是游戏就要有开始,就要有结束,要有运行。看别人的代码都写的很好,一个死循环就可以让游戏不停运行。我想往上套,始终也不行。只能另想办法。最后因为方块游戏的运行就是下降。所以我只要弄一个函数不停的调用下降,就能实现游戏运行的原理。至于什么时候下降停止。那可以具体再写。我觉得这样是对的。最终找到了SETTIMMER来实现
8 游戏算法实现:当我第一次看到,随机生成的方块,在游戏界面里缓缓下降的时候„„ 我心里那个美啊„„ 我知道我对了,胜利在望了。接下的东西就是具体的游戏功能的写作,一切都顺利了许多,我只是不停的测试+写+测试。完成。在写完之前我开始想着,下一步的实现。网络版
9 单机游戏完成: 所有的都完成,单机游戏终于完成后,自己也是不停的测试,优化算法,这中间还出现内存泄露的严重问题,也因祸得福了解了内存的基本使用。直到修复问题。最终单机版的无bug版完成。我中间公司的项目也多了老加班,就先放下了。
10 网络版的孕育: 07年同学在武汉,有个朋友介绍他去干开发的工作。那边的人说了,在一个月之内,如果开发出一个网络版的俄罗斯方块游戏,那么OK,来上班。我想起这见事情,于是我想着能否实现它。其实这还是做一个测试的一个心结。自己也有心思转开发,所以决定去实现这个。
11 网络版的实现过程: 因为整个游戏只有两个类,所有我觉得给网络功能这块+一个类。所有的网络功能都在那里实现,在开发的过程中发现,由于没有很好的设计,导致在实现的时候出现很多的矛盾。从而我也认识到设计和算法在软件开发中的重要性。跌跌撞撞的用WIndows socket使用UDP的协议实现了联机通讯,中间专门先实验几个通讯小例子,再把觉得可用的代码用上,现在基本的联机功能都以实现。很想模仿腾讯QQ火拼俄罗斯游戏开发游戏道具。但目前也只停留在想的阶段。
游戏介绍:
1 单机版和网络版并存
2 网络版:实现在线用户实时状态显示,(空闲中 游戏中 离线)
3 网络版:邀请对方联机对战。若对方状态不可以邀请,则不能邀请
4 网络版:双人联机对战实现,可以看到对方实时的方块数据。游戏胜负根据率先到达10000分的一方获胜
5 网络版道具使用: 酝酿中„„
结束语: 第一个C++ WIN232的程序,虽然只是个小游戏,但也给了我一些信心和鼓舞,希望有机会能正式加入程序员阵营中来,目前职位还是测试工作,想这下一步的开发方向该怎么走。希望各位同仁多多指教,给点建议。多谢啦。
下载地址:
部分源码:
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];//新方块 0横坐标 1纵坐标
short int Old_Cake[4][2];//旧方块 0横坐标 1纵坐标
short int Top;//有方块的最高点
bool Gframe[10][20];//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"
//////////////////////////////////////////////////////////////////////
// Gameframe Class
//////////////////////////////////////////////////////////////////////
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+2
9);
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+FRA
ME_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
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(rightNow_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;//不能等于十九。因为要进行a--操作
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() {
/**********初始化界面为0,表示没有方块*********/
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;//游戏颜色都初始化为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;
}
}
/******初始化第一个NEXT和主界面的第一个方块********/
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;//分数起点为0
Child_Point=0;//对方分数起点为0
Down=0;//下降格数
Move=0;//移动格数
G_Level=0;//默认是0级
Space_on=false;//默认不按下空格键
InvalidateRect(hwnd,NULL,false); }
bool Gameframe::Game_Active(int Event) {
return ture;
}