第一次真正意义上的用VC++实现的一个完整的Win32程序。
//Block.h
//-------------------------------------------------------------------------------------------------
/*
定义每个方块的结构
*/
#if !defined _BLOCK_H_
#define _BLOCK_H_
#define BLOCK_VERSION &H01000000 //主版本号、辅版本、附加版本、附加2
#define BLOCK_SIZE 6 //存储到文件时占用的字节数
#define BLOCK_HEADER_SIZE 8 //存储文件头信息的大小
struct _Block
{//注意:这些字段对于存储文件来说是有先后之分的。
unsigned int ID:8;
unsigned int NextID:8;
int Width:4;
int Height:4;
int OffsetY:4;
int OffsetX:4;
unsigned int Elements; //方块的各位是否为实体
};
typedef _Block BLOCK;
#endif
//-------------------------------------------------------------------------------------------------
//CustomGDI.h
//-------------------------------------------------------------------------------------------------
#pragma once
#include "windows.h"
//#include "d3d9.h"
#define BORDER_STYLE_NONE 0
#define BORDER_STYLE_FLAT 1
//为简单起见,目前只提供FLAT
//#define BORDER_STYLE_FIXED3D 2
//#define BORDER_STYLE_INNER3D 4
#define BORDER_STYLE_DEFAULT BORDER_STYLE_NONE
#define INNER_STYLE_EMPTY 0
#define INNER_STYLE_SOLID 1
#define INNER_STYLE_DEFAULT INNER_STYLE_EMPTY
#define TRANSPARENT_COLOR RGB(0,0,0)
#define BACKGROUND_DEFAULT_COLOR RGB(0,0,0)
typedef int INNER_STYLE;
typedef int BORDER_STYLE;
typedef DWORD GDI_COLOR;
class CCustomGDI
{
public:
//CCustomGDI(void);
CCustomGDI(HWND hWnd);
~CCustomGDI(void);
void TextOut(int x, int y,const char* lpString, int cbString);
void Drawbox(PRECT prect, BORDER_STYLE bstyle=BORDER_STYLE_DEFAULT, INNER_STYLE istyle=INNER_STYLE_DEFAULT);
void Drawbox(int x, int y, int height, int width, BORDER_STYLE bstyle=BORDER_STYLE_DEFAULT, INNER_STYLE istyle=INNER_STYLE_DEFAULT);
void DrawPic(int x, int y, int height, int width, const char* file);
void DrawPic(PRECT prect, const char* file);
void Clear(void);
void Clear(PRECT prect);
void Clear(GDI_COLOR color);
void Clear(PRECT prect, GDI_COLOR color);
void Clear(int x, int y, int height, int width, GDI_COLOR color);
void SetBkColor(GDI_COLOR color); //设置背景色
void SetColor(GDI_COLOR color); //设置前景色
void Set3DColor(GDI_COLOR ul_color, GDI_COLOR rb_color); //设置绘制3D时左上角与右下角的颜色
void SetBorderColor(GDI_COLOR color);
void SetBorderSize(int size);
protected:
//LPDIRECT3D9 m_pD3D;
//LPDIRECT3DDEVICE9 m_pd3dDevice;
//HDC m_hdc;
HWND m_hwnd;
//HBRUSH m_hbrBkgnd;
GDI_COLOR m_background;
int m_bordersize;
GDI_COLOR m_bordercolor;
GDI_COLOR m_color;
};
//-------------------------------------------------------------------------------------------------
//CustomGDI.cpp
//-------------------------------------------------------------------------------------------------
#include ".\customgdi.h"
//
//CCustomGDI::CCustomGDI(void)
//{
//}
//
CCustomGDI::CCustomGDI(HWND hWnd)
{
//初始化图形设备
m_hwnd=hWnd;
//m_hdc=GetDC(hWnd);
m_background=BACKGROUND_DEFAULT_COLOR;
m_bordersize=1;
m_bordercolor=RGB(0x80,0x80,0x80); //gray
m_color=RGB(0xFF,0xFF,0xFF); //white
}
CCustomGDI::~CCustomGDI(void)
{
//ReleaseDC(m_hwnd, m_hdc);
}
void CCustomGDI::TextOut(int x, int y,const char* lpString, int cbString)
{
HDC hdc=GetDC(m_hwnd);
::TextOut(hdc,x,y,lpString,cbString);
ReleaseDC(m_hwnd,hdc);
}
void CCustomGDI::Drawbox(PRECT prect, BORDER_STYLE bstyle, INNER_STYLE istyle)
{
HBRUSH hbr;
HDC hdc;
hdc=GetDC(m_hwnd);
RECT rect;
rect.top=prect->top;
rect.bottom=prect->bottom;
rect.left=prect->left;
rect.right=prect->right;
if(bstyle==BORDER_STYLE_FLAT)
{
//如果为BORDER_STYLE_FLAT
hbr=CreateSolidBrush(m_bordercolor);
FrameRect(hdc, &rect, hbr); //这里不知道如何画线,呵呵。
DeleteObject(hbr);
rect.left+=m_bordersize;
rect.right-=m_bordersize;
rect.top+=m_bordersize;
rect.bottom-=m_bordersize;
}
if(istyle==INNER_STYLE_SOLID) {
hbr=CreateSolidBrush(m_color);
FillRect(hdc, &rect, hbr);
DeleteObject(hbr);
}
ReleaseDC(m_hwnd,hdc);
}
void CCustomGDI::Drawbox(int x, int y, int height, int width, BORDER_STYLE bstyle, INNER_STYLE istyle)
{
RECT rect;
rect.top=y;
rect.left=x;
rect.bottom=y+height-1;
rect.right=x+width-1;
Drawbox(&rect,bstyle,istyle);
}
void CCustomGDI::DrawPic(int x, int y, int height, int width, const char* file)
{
}
void CCustomGDI::DrawPic(PRECT prect, const char* file)
{
}
void CCustomGDI::Clear(void)
{
//清除屏幕
RECT rect;
GetClientRect(m_hwnd,&rect);
Clear(&rect, m_background);
}
void CCustomGDI::Clear(PRECT prect)
{
Clear(prect, m_background);
}
void CCustomGDI::Clear(GDI_COLOR color)
{
RECT rect;
GetClientRect(m_hwnd,&rect);
Clear(&rect, color);
}
void CCustomGDI::Clear(PRECT prect, GDI_COLOR color)
{
HDC hdc;
hdc=GetDC(m_hwnd);
HBRUSH hbr=CreateSolidBrush(color);
FillRect(hdc, prect, hbr);
DeleteObject(hbr);
ReleaseDC(m_hwnd,hdc);
}
void CCustomGDI::Clear(int x, int y, int height, int width, GDI_COLOR color)
{
RECT rect;
rect.left=x;
rect.top=y;
rect.right=x+height-1;
rect.bottom=y+width-1;
Clear(&rect,color);
}
void CCustomGDI::SetBkColor(GDI_COLOR color)
{
m_background=color;
}
void CCustomGDI::SetColor(GDI_COLOR color)
{
m_color=color;
}
void CCustomGDI::Set3DColor(GDI_COLOR ul_color, GDI_COLOR rb_color)
{
}
void CCustomGDI::SetBorderSize(int size)
{
}
void CCustomGDI::SetBorderColor(GDI_COLOR color)
{
}
//--------------------------------------------------------------------------------------------------
//Els.h
//-------------------------------------------------------------------------------------------------
#include <windows.h>
//#include <d3d9.h>
#include <stdio.h>
#include <direct.h>
#include <time.h>
#include "Block.h"
#include "CustomGDI.h"
#define PLAYAREA_HEIGHT 24
#define PLAYAREA_WIDTH 12
#define PLAYAREA_EMPTY_COLOR RGB(0,0,0)
#define IDT_PLAY 2005
#define GAME_STATUS_STOPPED 0
#define GAME_STATUS_RUNNING 1
#define GAME_STATUS_PAUSED -1
#define PLAYER_DEFAULT_NAME "<Player>"
#define PLAYER_MAX_LEVEL 12
#define PLAYER_MAX_SCORE 999999999
struct _PLAYER
{
char Name[50];
int Power; //爆了几次
int Score; //得分,最大为999999999
};
struct _ELSSYS
{
int Level; //当前游戏级别
int ClientHeight; //当前客户区域高度
int ClientWidth; //当前客户区域宽度
int PlayAreaX; //游戏区域X坐标(注意:不包含游戏区域外的边框等)
int PlayAreaY; //游戏区域Y坐标(注意:不包含游戏区域外的边框等)
int SingleHeight; //单个格的高度
int SingleWidth; //单个格的宽度
int BorderSize; //边框大小
int Spacing; //格与格之间的间隔
int NextX; //下一个方块显示区域的X坐标
int NextY; //下一个方块显示区域的Y坐标
bool IsNextShown; //下一个方块是否显示
};
typedef _PLAYER PLAYER;
typedef _ELSSYS EVIRONMENT;
//---------------------------------------------------------------------------------------------------
//Els.cpp
//---------------------------------------------------------------------------------------------------
#include "Els.h"
//Direct3D Object
//LPDIRECT3D9 g_pD3D = NULL;
//Direct3D Device
//LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
//窗体的HWND
HWND g_hwnd;
int g_Status=GAME_STATUS_STOPPED; //存储游戏的状态
//当前的时间间隔
//int g_Interval=1000;
//游戏区域,存放每个格的颜色值,如果为0,表示当前格没有占用,否则已占用。
GDI_COLOR g_PlayArea[PLAYAREA_HEIGHT][PLAYAREA_WIDTH];
//当前行、列
int g_CurRow=0;
int g_CurCol=0;
//当前方块的索引
int g_CurBlock;
//当前方块的颜色
GDI_COLOR g_CurBlockColor;
//下一个方块的索引
int g_NextBlock;
GDI_COLOR g_NextBlockColor;
//存放所有的方块
BLOCK* Blocks=NULL;
//方块的个数
int g_BlockCount=0;
//当前级别
int g_Level=0;
int g_NextLevelPower=0;
int g_NextLevelScore=1000;
//环境信息
EVIRONMENT g_Env;
//用户的信息
PLAYER g_Player={"Player",0,0};
//声明自己的GDI对象
CCustomGDI* g_GDI;
//所有函数定义
extern void CaculateEnv(void); //计算界面环境信息
extern void Render(void); //绘制界面
extern HRESULT LoadBlocks(void); //载入方块
extern void ClearBlocks(void); //清除所有方块所占内存
extern void _Bottom(void); //方块置底后的处理过程
extern void Bottom(void); //方块置底的处理过程
extern void Down(void); //方块下落
extern void MapCurBlockToPlayArea(void); //把当前方块影射到游戏区域
//
//void ShowDebugMsg(const char* sMsg, int x=100, int y=100)
//{
// HDC hdc;
// hdc=GetDC(g_hwnd);
// TextOut(hdc,x,y, sMsg, (int)strlen(sMsg));
//}
//
//清除释放所有方块所占内存
void ClearBlocks()
{
if(Blocks!=NULL)
{
free(Blocks);
}
}
//从文件中调入所有的方块
HRESULT LoadBlocks()
{
int i;
FILE* fp;
char sPath[_MAX_PATH];
char Header[BLOCK_HEADER_SIZE];
//char sMsg[255];
if(Blocks!=NULL)
{
ClearBlocks();
}
_getcwd(sPath, _MAX_PATH); //这里不判断了
strcat(sPath, "\Turn.Right.blk");
fp=fopen(sPath, "rb");
if(fp==NULL) {
//存在错误。
return E_FAIL;
}
fread(Header,1,BLOCK_HEADER_SIZE,fp);
//这里不再判断这个文件是否正确了,同时没有判断版本信息。
//0-2字节为:BLK
//3-6字节为:版本信息
//7字节为方块个数。
g_BlockCount=(unsigned int)Header[BLOCK_HEADER_SIZE-1];
//然后申请g_BlockCount大小的方块数组
Blocks=(BLOCK *)malloc(sizeof(BLOCK)*g_BlockCount);
for(i=0;i<g_BlockCount;i++)
{
fread(&Blocks[i], sizeof(BLOCK), 1, fp);
//测试载入的小片段
//sprintf(sMsg, "ID:%d;Next:%d.",Blocks[i].ID,Blocks[i].NextID);
//ShowDebugMsg(sMsg, 0, 24*i);
//MessageBox(g_hwnd, sMsg, "test",MB_OK);
}
fclose(fp);
return S_OK;
}
//_Drawbox:
//在俄罗斯方块区域以颜色color绘制第r行,第c列的单元格方块。
void _Drawbox(int r, int c, GDI_COLOR color)
{
int x,y;
x=g_Env.PlayAreaX + g_Env.BorderSize + (c+1)*g_Env.Spacing + c*g_Env.SingleWidth;
y=g_Env.PlayAreaY + g_Env.BorderSize + (r+1)*g_Env.Spacing + r*g_Env.SingleHeight;
g_GDI->SetColor(color);
//g_GDI->Set3DColor(WHITE,BLACK);
if(color==PLAYAREA_EMPTY_COLOR)
{
g_GDI->Drawbox(x,y,g_Env.SingleHeight,g_Env.SingleWidth,BORDER_STYLE_NONE,INNER_STYLE_SOLID);
}
else
{
g_GDI->Drawbox(x,y,g_Env.SingleHeight,g_Env.SingleWidth,BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
}
}
void HideCurBlock()
{
//清除屏幕上当前方块的显示
int row,col;
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
if(g_CurRow+row<0) continue;
for(col=0;col<=Blocks[g_CurBlock].Width;col++)
{
if(((Blocks[g_CurBlock].Elements) & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
_Drawbox(g_CurRow+row,g_CurCol+col,PLAYAREA_EMPTY_COLOR);
}
}
}
}
void ShowCurBlock()
{
//在屏幕上显示当前方块
int row,col;
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
if(g_CurRow+row<0) continue;
for(col=0;col<=Blocks[g_CurBlock].Width;col++)
{
if(((Blocks[g_CurBlock].Elements) & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
_Drawbox(g_CurRow+row,g_CurCol+col,g_CurBlockColor); //注意g_CurBlockColor值是否设置
}
}
}
//char s[200];
//sprintf(s,"Block:%d,%2x;SIZE:%d.",g_CurBlock, Blocks[g_CurBlock].Elements,sizeof(BLOCK));
//g_GDI->Drawbox(0,g_Env.ClientHeight-35,30,g_Env.ClientWidth*3/10-10,BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
//g_GDI->TextOut(10,g_Env.ClientHeight-30,s,(int)strlen(s));
}
void ShowNextBlock()
{
//在下一个方块的显示框中显示下一个方块
int row,col;
int blkRow,blkCol;
blkRow=(3-Blocks[g_NextBlock].Height)/2;
blkCol=(3-Blocks[g_NextBlock].Width)/2;
g_GDI->SetColor(PLAYAREA_EMPTY_COLOR);
g_GDI->Drawbox(g_Env.NextX,g_Env.NextY,((g_Env.SingleHeight+g_Env.Spacing)<<2)+g_Env.Spacing+(g_Env.BorderSize<<1),((g_Env.SingleWidth+g_Env.Spacing)<<2)+g_Env.Spacing+(g_Env.BorderSize<<1),BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
for(row=0;row<4;row++)
{
for(col=0;col<4;col++)
{
if(row>=blkRow && row<=blkRow+Blocks[g_NextBlock].Height && col>=blkCol && col<=blkCol+Blocks[g_NextBlock].Width)
{
if((Blocks[g_NextBlock].Elements & (1<<((row-blkRow)*(Blocks[g_NextBlock].Width+1)+(col-blkCol))))!=0)
{
g_GDI->SetColor(g_NextBlockColor);
g_GDI->Drawbox(g_Env.NextX+g_Env.BorderSize+g_Env.Spacing+(g_Env.SingleWidth+g_Env.Spacing)*col, g_Env.NextY+g_Env.BorderSize+g_Env.Spacing+(g_Env.SingleHeight+g_Env.Spacing)*row,g_Env.SingleHeight,g_Env.SingleWidth,BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
continue;
}
}
g_GDI->SetColor(PLAYAREA_EMPTY_COLOR);
g_GDI->Drawbox(g_Env.NextX+g_Env.BorderSize+g_Env.Spacing+(g_Env.SingleWidth+g_Env.Spacing)*col, g_Env.NextY+g_Env.BorderSize+g_Env.Spacing+(g_Env.SingleHeight+g_Env.Spacing)*row,g_Env.SingleHeight,g_Env.SingleWidth,BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
}
}
}
void ShowGameInfo()
{
char s[200];
//显示游戏数据信息
if(g_Status==GAME_STATUS_STOPPED)
{
strcpy(s,"Game Status: Stopped.");
}
if(g_Status==GAME_STATUS_RUNNING)
{
strcpy(s,"Game Status: Running.");
}
if(g_Status==GAME_STATUS_PAUSED)
{
strcpy(s,"GameStatus: Paused.");
}
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight-30," ",30);
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight-30,s,(int)strlen(s));
//用户得分、当前级别
sprintf(s,"Score: %d",g_Player.Score);
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2-50," ",30);
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2-50,s,(int)strlen(s));
sprintf(s,"Level: %d",g_Level);
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2-30," ",30);
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2-30,s,(int)strlen(s));
}
BOOL CanMoveDown()
{
int row,col;
if(Blocks==NULL) return FALSE;
if(g_BlockCount<=0) return FALSE;
if(g_CurBlock<0||g_CurBlock>=g_BlockCount) return FALSE;
//如果已经到达最下面一行,不能再向下移了。
if((g_CurRow+Blocks[g_CurBlock].Height+1)>=PLAYAREA_HEIGHT) return FALSE;
for(col=0;col<=Blocks[g_CurBlock].Width;col++)
{
for(row=Blocks[g_CurBlock].Height;row>=0;row--)
{
//找到最下的非空
if(((Blocks[g_CurBlock].Elements) & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
//如果游戏区域的下一行相应位置不空,则也不能再向下移动了。
if(g_PlayArea[g_CurRow+row+1][g_CurCol+col]!=PLAYAREA_EMPTY_COLOR)
{
return FALSE;
}
}
}
}
return TRUE;
}
BOOL CanMoveLeft()
{
int row,col;
if(Blocks==NULL) return FALSE;
if(g_BlockCount<=0) return FALSE;
if(g_CurBlock<0||g_CurBlock>=g_BlockCount) return FALSE;
//如果已经到达最左一列,不能再左移了。
if(g_CurCol<=0) return FALSE;
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
for(col=0;col<=Blocks[g_CurBlock].Width;col++)
{
//找到最左的非空
if(((Blocks[g_CurBlock].Elements) & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
//如果游戏区域的左位置不空,则也不能再左移动了。
if(g_PlayArea[g_CurRow+row][g_CurCol+col-1]!=PLAYAREA_EMPTY_COLOR)
{
return FALSE;
}
}
}
}
return TRUE;
}
BOOL CanMoveRight()
{
if(Blocks==NULL) return FALSE;
if(g_BlockCount<=0) return FALSE;
if(g_CurBlock<0||g_CurBlock>=g_BlockCount) return FALSE;
//如果已经到达最右一列,不能再右移了。
if(g_CurCol+Blocks[g_CurBlock].Width+1>=PLAYAREA_WIDTH) return FALSE;
int row,col;
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
for(col=Blocks[g_CurBlock].Width;col>=0;col--)
{
//找到最右的非空
if(((Blocks[g_CurBlock].Elements) & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
//如果游戏区域的右位置不空,则也不能再右移动了。
if(g_PlayArea[g_CurRow+row][g_CurCol+col+1]!=PLAYAREA_EMPTY_COLOR)
{
return FALSE;
}
}
}
}
return TRUE;
}
BOOL CanTurn()
{
int row,col;
int ARow,ACol;
BLOCK* next;
if(Blocks==NULL) return FALSE;
if(g_BlockCount<=0) return FALSE;
if(g_CurBlock<0||g_CurBlock>=g_BlockCount) return FALSE;
if(Blocks[g_CurBlock].NextID<0||Blocks[g_CurBlock].NextID>=(unsigned int)g_BlockCount) return FALSE; //说明原数据文件有错误,需更正
next=&Blocks[Blocks[g_CurBlock].NextID];
//这里的OffsetY、OffsetX,应该是由当前Block提供。
ARow=g_CurRow + Blocks[g_CurBlock].OffsetY;
ACol=g_CurCol + Blocks[g_CurBlock].OffsetX;
//如果超过高度了,应该不允许变换了,要不,一直按变换键,可能就永远落不了地了。
if(ARow+next->Height+1>PLAYAREA_HEIGHT) return FALSE;
//如果列超出游戏区域,可以处理一下。
if(ACol<0) ACol=0;
if(ACol+next->Width+1>=PLAYAREA_WIDTH)
{
ACol=PLAYAREA_WIDTH-next->Width-1;
}
//实现CanTurn时,突然想到,当前方块所占的空,不要在g_PlayArea中记录
for(row=0;row<=next->Height;row++)
{
for(col=0;col<=next->Width;col++)
{
if(((next->Elements) & (1<<(row*next->Width+col+1)))!=0)
{
//如果下一个变换的相应位置非空的话
if(g_PlayArea[ARow+row][ACol+col]!=PLAYAREA_EMPTY_COLOR)
{
//如果游戏区域也非空
return FALSE;
}
}
}
}
return TRUE;
}
void _Turn()
{
g_CurRow = g_CurRow + Blocks[g_CurBlock].OffsetY;
g_CurCol = g_CurCol + Blocks[g_CurBlock].OffsetX;
g_CurBlock = Blocks[g_CurBlock].NextID;
//关于列的超范围值,变换应该同CanTurn中的算法相同。
if(g_CurCol<0) g_CurCol=0;
if(g_CurCol + Blocks[g_CurBlock].Width+1>=PLAYAREA_WIDTH)
{
g_CurCol = PLAYAREA_WIDTH-Blocks[g_CurBlock].Width-1;
}
//变换完毕
}
void Turn()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
if(CanTurn()==TRUE)
{
HideCurBlock();
_Turn();
ShowCurBlock();
}
}
void _MoveLeft()
{
g_CurCol--;
}
void MoveLeft()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
if(CanMoveLeft()==TRUE)
{
HideCurBlock();
_MoveLeft();
ShowCurBlock();
}
}
void _MoveRight()
{
g_CurCol++;
}
void MoveRight()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
if(CanMoveRight()==TRUE)
{
HideCurBlock();
_MoveRight();
ShowCurBlock();
}
}
void _Down()
{
g_CurRow++;
}
void MapCurBlockToPlayArea()
{
int row,col;
row=0;
col=0;
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
for(col=0;col<=Blocks[g_CurBlock].Width;col++)
{
if((Blocks[g_CurBlock].Elements & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
g_PlayArea[g_CurRow+row][g_CurCol+col]=g_CurBlockColor;
}
}
}
}
void Gain()
{
int row,col;
int gain=0;
BOOL full; //当前行是否全部填满
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
full=TRUE;
for(col=0;col<PLAYAREA_WIDTH;col++)
{
if(g_PlayArea[g_CurRow+row][col]==PLAYAREA_EMPTY_COLOR)
{
full=FALSE;
break;
}
}
if(full==TRUE)
{
//消当前行的动画效果
//消当前行
int tmpRow,tmpCol;
for(tmpRow=g_CurRow+row;tmpRow>0;tmpRow--)
{
for(tmpCol=0;tmpCol<PLAYAREA_WIDTH;tmpCol++)
{
g_PlayArea[tmpRow][tmpCol]=g_PlayArea[tmpRow-1][tmpCol];
_Drawbox(tmpRow,tmpCol,g_PlayArea[tmpRow][tmpCol]);
}
}
for(tmpCol=0;tmpCol<PLAYAREA_WIDTH;tmpCol++)
{
g_PlayArea[0][tmpCol]=PLAYAREA_EMPTY_COLOR;
_Drawbox(tmpRow,tmpCol,PLAYAREA_EMPTY_COLOR);
}
gain++;
}
}
//变更用户的相关情况
if(gain>0)
{
g_Player.Score+=(100*(gain*gain-gain+1)); //1:100;2:300;3:700;4:1300;
if(g_Player.Score>PLAYER_MAX_SCORE)
{
g_Player.Power++;
g_Player.Score %= (PLAYER_MAX_SCORE+1);
}
ShowGameInfo();
}
}
void UpdateSys()
{
//变更系统相关情况
if(g_Player.Power==g_NextLevelPower)
{
if(g_Player.Score>=g_NextLevelScore)
{
//变更级别
g_Level++;
g_Level %= PLAYER_MAX_LEVEL;
g_NextLevelScore+=(100*(g_Level*g_Level)+1000);
if(g_NextLevelScore>PLAYER_MAX_SCORE)
{
g_NextLevelPower++;
g_NextLevelScore%=(PLAYER_MAX_SCORE+1);
}
//变更系统速度
KillTimer(g_hwnd,IDT_PLAY);
SetTimer(g_hwnd, IDT_PLAY,1000/(g_Level+1),NULL);
}
}
}
BOOL NextBlock()
{
g_CurBlock=g_NextBlock;
g_CurBlockColor=g_NextBlockColor;
g_CurRow=0;
g_CurCol=(PLAYAREA_WIDTH-Blocks[g_CurBlock].Width)/2;
srand((unsigned)time(NULL));
g_NextBlock=rand()%g_BlockCount;
g_NextBlockColor=RGB((rand()%4)*64+63,(rand()%4)*64+63,(rand()%4)*64+63);
ShowNextBlock();
ShowCurBlock();
int row,col;
for(row=0;row<=Blocks[g_CurBlock].Height;row++)
{
for(col=0;col<=Blocks[g_CurBlock].Width;col++)
{
if((Blocks[g_CurBlock].Elements & (1<<(row*(Blocks[g_CurBlock].Width+1)+col)))!=0)
{
if(g_PlayArea[g_CurRow+row][g_CurCol+col]!=PLAYAREA_EMPTY_COLOR) //如果所在位置已经不为空则Game Over。
{
return FALSE;
}
}
}
}
return TRUE;
}
void Stop()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
KillTimer(g_hwnd,IDT_PLAY);
g_Status=GAME_STATUS_STOPPED;
ShowGameInfo();
}
void Down()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
//g_GDI->Drawbox(0,g_Env.ClientHeight,60,20,BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
//g_GDI->TextOut(10, g_Env.ClientHeight-30,"Downning!",9);
if(CanMoveDown()==TRUE)
{
//BeginPaint(g_hwnd,NULL);
HideCurBlock();
_Down();
ShowCurBlock();
//ValidateRect(g_hwnd,NULL);
//UpdateWindow(g_hwnd);
}
else
{
_Bottom();
}
}
void _Bottom()
{
//把当前方块映射到游戏区域中
MapCurBlockToPlayArea();
//检查是否有可消行,变更用户得分
Gain();
//检查游戏级别是否需要提高
UpdateSys();
//设置当前方块为下一个方块,并重新产生一个下一方块
if(NextBlock()==FALSE)
{
//如果下一个方块顶死应该Game Over。
Stop(); //首先停止游戏。
//然后检查最高分,记录到排行榜。
}
ShowGameInfo();
}
void Bottom()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
while(CanMoveDown()==TRUE)
{
HideCurBlock();
_Down();
ShowCurBlock();
}
_Bottom();
}
void Pause()
{
if(g_Status!=GAME_STATUS_RUNNING) return;
//clear timer.
KillTimer(g_hwnd, IDT_PLAY);
g_Status=GAME_STATUS_PAUSED;
ShowGameInfo();
}
//写到Resume,觉得应该引入一个变量,用来标识游戏是否已经开始,是否是继续游戏,而Start()只能算作重新从头开始。
void Resume()
{
if(g_Status!=GAME_STATUS_PAUSED) return;
SetTimer(g_hwnd, IDT_PLAY,1000/(g_Level+1),NULL);
g_Status=GAME_STATUS_RUNNING;
ShowGameInfo();
}
void Start()
{
if(g_Status!=GAME_STATUS_STOPPED) return;
int row,col;
for(row=0;row<PLAYAREA_HEIGHT;row++)
{
for(col=0;col<PLAYAREA_WIDTH;col++)
{
g_PlayArea[row][col]=PLAYAREA_EMPTY_COLOR;
}
}
//产生当前方块及下一个方块
srand((unsigned)time(NULL));
g_CurBlock=rand()%g_BlockCount;
g_CurBlockColor=RGB((rand()%4)*64+63,(rand()%4)*64+63,(rand()%4)*64+63);
g_NextBlock=rand()%g_BlockCount;
g_NextBlockColor=RGB((rand()%4)*64+63,(rand()%4)*64+63,(rand()%4)*64+63);
//决定当前方块的位置
g_CurRow=0;
g_CurCol=(PLAYAREA_WIDTH-Blocks[g_CurBlock].Width)/2;
//初始化系统信息
g_Level=0; //将来可以通过用户定制现在级别
g_NextLevelPower=0;
g_NextLevelScore=1000;
//初始化用户信息
strcpy(g_Player.Name, PLAYER_DEFAULT_NAME);
g_Player.Power=0;
g_Player.Score=0;
//然后开始游戏
Render(); //重新绘制界面
g_Status=GAME_STATUS_RUNNING;
SetTimer(g_hwnd, IDT_PLAY,(10-g_Level)*100,NULL);
ShowNextBlock();
ShowCurBlock();
ShowGameInfo();
}
void CaculateEnv()
{
RECT rect;
GetClientRect(g_hwnd, &rect); //得到当前窗口的大小
//更改环境变量
g_Env.ClientHeight=rect.bottom-rect.top+1;
g_Env.ClientWidth=rect.right-rect.left+1;
g_Env.BorderSize=3;
g_Env.Spacing=1;
g_Env.IsNextShown=true;
//得到各区域坐标
//游戏区域
g_Env.PlayAreaX=g_Env.ClientWidth*3/10+g_Env.BorderSize;
g_Env.PlayAreaY=g_Env.BorderSize;
g_Env.SingleHeight = (g_Env.ClientHeight-g_Env.PlayAreaY*2-g_Env.BorderSize*2-g_Env.Spacing)/PLAYAREA_HEIGHT-g_Env.Spacing;
g_Env.SingleWidth = (g_Env.ClientWidth - g_Env.PlayAreaX*2-g_Env.BorderSize*2-g_Env.Spacing)/PLAYAREA_WIDTH-g_Env.Spacing;
//下一个区域
g_Env.NextX = g_Env.ClientWidth*17/20-g_Env.BorderSize-g_Env.Spacing*5/2-g_Env.SingleWidth*2;
g_Env.NextY = g_Env.BorderSize*2;
//UpdateWindow(g_hwnd);
}
VOID Render()
{ //绘制整个界面
char s[200];
//清除所有
g_GDI->Clear(RGB(0x80,0x80,0x80));
//绘制图片
//g_GDI->DrawPic(g_Env.BorderSize*2,g_Env.BorderSize*2, g_Env.ClientWidth/5-g_Env.BorderSize*5,g_Env.ClientWidth/5-g_Env.BorderSize*5, "mydaughter.bmp");
//绘制Logo
//g_GDI->DrawPic(g_Env.BorderSize*2,rect.bottom-g_Env.BorderSize*2,100,100, "logo.bmp");
//绘制游戏区域
g_GDI->SetColor(0);
g_GDI->Drawbox(g_Env.PlayAreaX,g_Env.PlayAreaY,(g_Env.SingleHeight+g_Env.Spacing)*PLAYAREA_HEIGHT+g_Env.Spacing+g_Env.BorderSize*2,(g_Env.SingleWidth+g_Env.Spacing)*PLAYAREA_WIDTH+g_Env.Spacing+g_Env.BorderSize*2,BORDER_STYLE_FLAT,INNER_STYLE_SOLID);
int row,col;
for(row=0;row<PLAYAREA_HEIGHT;row++)
{
for(col=0;col<PLAYAREA_WIDTH;col++)
{
if(g_PlayArea[row][col]!=PLAYAREA_EMPTY_COLOR)
{
_Drawbox(row,col,g_PlayArea[row][col]);
}
}
}
//绘制当前方块
if(g_Status!=GAME_STATUS_STOPPED)
{
ShowNextBlock();
ShowCurBlock();
}
//绘制Next
//绘制各按钮
strcpy(s,"[Enter]: Start/Resume");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2,s,(int)strlen(s));
strcpy(s,"[Pause]: Pause");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+20,s,(int)strlen(s));
strcpy(s,"↑: 翻转方块");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+40,s,(int)strlen(s));
strcpy(s,"↓: 向下落一格");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+60,s,(int)strlen(s));
strcpy(s,"←: 左移");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+80,s,(int)strlen(s));
strcpy(s,"→: 右移");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+100,s,(int)strlen(s));
strcpy(s,"[Space]: 置底");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+120,s,(int)strlen(s));
strcpy(s,"[ESC]: Stop Game");
g_GDI->TextOut(g_Env.ClientWidth*3/4,g_Env.ClientHeight/2+140,s,(int)strlen(s));
//绘制当前状态
ShowGameInfo();
//以下为调试信息
//sprintf(s,"ClientWidth:%d",g_Env.ClientWidth);
//g_GDI->TextOut(0,0,s,(int)strlen(s));
//sprintf(s,"ClientHeight:%d",g_Env.ClientHeight);
//g_GDI->TextOut(0,20,s,(int)strlen(s));
//sprintf(s,"PlayAreaX:%d",g_Env.PlayAreaX);
//g_GDI->TextOut(0,40,s,(int)strlen(s));
//sprintf(s,"PlayAreaY:%d",g_Env.PlayAreaY);
//g_GDI->TextOut(0,60,s,(int)strlen(s));
//sprintf(s,"SingleHeight:%d",g_Env.SingleHeight);
//g_GDI->TextOut(0,80,s,(int)strlen(s));
//sprintf(s,"SingleWidth:%d",g_Env.SingleWidth);
//g_GDI->TextOut(0,100,s,(int)strlen(s));
}
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_TIMER:
Down();
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_ACTIVATE:
if(wParam==WA_INACTIVE)
{
Pause();
}
break;
case WM_SIZE:
if(wParam!=SIZE_MINIMIZED)
{
CaculateEnv();
if(wParam==SIZE_RESTORED)
{
Render();
}
//UpdateWindow(hWnd);
}
return 0;
case WM_PAINT:
Render();
ValidateRect(hWnd, NULL); //呵呵,目前还不能去掉该行
return 0;
//case WM_SYSKEYDOWN:
case WM_KEYDOWN:
switch(wParam)
{
case VK_UP:
Turn();
break;
case VK_DOWN:
Down();
break;
case VK_LEFT:
MoveLeft();
break;
case VK_RIGHT:
MoveRight();
break;
case VK_SPACE:
Bottom();
break;
case VK_RETURN:
if(g_Status==GAME_STATUS_PAUSED)
{
Resume();
}
else
{
Start();
}
break;
case VK_PAUSE:
Pause();
break;
//case VK_END:
case VK_ESCAPE:
Stop();
break;
}
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
//系统初始化
HRESULT Initialize()
{
//绑定当前窗口到自己的GDI
g_GDI=new CCustomGDI(g_hwnd);
if(SUCCEEDED(LoadBlocks()))
{
return S_OK;
}
return E_FAIL;
}
//释放系统资源
void Cleanup()
{
//释放方块资源
ClearBlocks();
//释放GDI
delete g_GDI;
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//创建窗体
WNDCLASS wndclass={0, MsgProc, 0L, 0L, hInstance, NULL,NULL,NULL,NULL,"Els"};
RegisterClass(&wndclass);
g_hwnd=CreateWindow("Els","Els v1.0.0.0",
WS_OVERLAPPEDWINDOW,100,100,640,480,GetDesktopWindow(),NULL,wndclass.hInstance,NULL);
//初始化
if(SUCCEEDED(Initialize()))
{
ShowWindow(g_hwnd,SW_SHOWDEFAULT);
UpdateWindow(g_hwnd);
//进入Window消息循环
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Cleanup();
UnregisterClass("Els", wndclass.hInstance);
return 0;
}
//--------------------------------------------------------------------------------------------------------