开发环境:VS2015
一如既往地新建一个MFC应用程序,开始执行的效果如图:
首先设计一下业务逻辑:
通过一个计时器函数OnTimer(),每触发一次,调用一次Invalidate()函数,使得场景重新绘制,由此来模拟我们的方块以一定的速度在往下落,用一个bool数组来表示这个方格有没有成为地底的一部分,每一种形状的方块用一个中心点来表示这个方块的位置,用一个数组存储它的另外几个子方块的位置,来表示形状。
先做好头文件的声明中要加入的成员:
class CMy18TetrisView : public CView
{
protected: // 仅从序列化创建
CMy18TetrisView();
DECLARE_DYNCREATE(CMy18TetrisView)
// 特性
public:
CMy18TetrisDoc* GetDocument() const;
// 操作
public:
/*---------------------自己加入的类成员-----------------*/
public:
void start(); // 初始化方块变量,生成图形
void trans(); // 方块落地转化为地图
void LineDelete(); // 除去都是方块的行
void ShapeSwitch(); // 变形 旋转
bool GoDown(); // 下落 落地返回true
void GoLeft(); // 左移
void GoRight(); // 右移
bool IsOver(); // 是否游戏失败了
private:
int rowCount; // 横格个数
int colCount; // 竖格个数
int elen; // 半格长度
bool GameMap[30][30];
int rowPos, colPos; // 方块中心坐标
int shift[4][2]; // 相对中心的偏移量 半格为单位
int kind; // 类型
CBitmap block; //方块位图
/*---------------------自己加入的类成员-----------------*/
// 重写
public:
virtual void OnDraw(CDC* pDC); // 重写以绘制该视图
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// 实现
public:
virtual ~CMy18TetrisView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
afx_msg void OnFilePrintPreview();
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
DECLARE_MESSAGE_MAP()
};
在TerisView.cpp中依次加入定义,
构造函数中加入成员变量的初始化,调用start()函数:
CMy18TetrisView::CMy18TetrisView()
{
// TODO: 在此处添加构造代码
rowCount = 12;//一行13个格子
elen = 15;
colCount = 20; //屏幕高20个格子
block.LoadBitmap(IDB_BITMAP1);//CBitmap对象载入这个图片
srand(time(0)); //这个干啥的呢?初始化随机种子?
memset(GameMap, 1, sizeof(GameMap));
for (int i = 1; i <= rowCount; ++i)
for (int j = 0; j <= colCount; ++j)
GameMap[i][j] = 0;
start();
}
而start()函数如下代码如下,主要是开始制造一个block:
void CMy18TetrisView::start() { //产生新图形
rowPos = rowCount + 2;
colPos = 1;
kind = rand() % 7; //随机取形状
for (int i = 0; i<4; ++i)
for (int j = 0; j<2; ++j)
shift[i][j] = RussiaData[kind][i][j]; //赋值,变成该种形状
}// 初始化方块变量
再在onDraw()函数中,加入我们的绘图代码:
void CMy18TetrisView::OnDraw(CDC* pDC)
{
CMy18TetrisDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
//CBrush background;
//background.CreateSolidBrush(RGB(233, 233, 233));
CBrush background;
background.CreateSolidBrush(RGB(233, 233, 233));
CDC Dc;
if (Dc.CreateCompatibleDC(pDC) == FALSE)
AfxMessageBox(_T("Can't create DC"));
Dc.SelectObject(block);
for (int i = 1; i <= rowCount; ++i)
for (int j = 1; j <= colCount; ++j) {
if (GameMap[i][j] == 0) {
CRect myrect(i*elen * 2, j*elen * 2, (i + 1)*elen * 2, (j + 1)*elen * 2); //矩形的四个定点
pDC->FillRect(myrect, &background);
}
/*
x:目标矩形区域的左上角x轴坐标点。
y:目标矩形区域的左上角y轴坐标点。
nWidth:在目标设备中绘制位图的宽度。
nHight:在目标设备中绘制位图的高度。
pSrcDC:源设备上下文对象指针。
xSrc:源设备上下文的起点x轴坐标,函数从该起点复制位图到目标设备。
ySrc:源设备上下文的起点y轴坐标,函数从该起点复制位图到目标设备。
dwRop:光栅操作代码
*/
else pDC->BitBlt(i*elen * 2, j*elen * 2, (i + 1)*elen * 2, (j + 1)*elen * 2, &Dc, 0, 0, SRCCOPY);
}
for (int w = 0; w<4; ++w) {
int i = (shift[w][0] + rowPos) / 2;
int j = (shift[w][1] + colPos) / 2;
//该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境
//src_copy 将源矩形区域直接拷贝到目标矩形区域
if (i > 0 && j > 0) pDC->BitBlt(i*elen * 2, j*elen * 2, (i + 1)*elen * 2, (j + 1)*elen * 2, &Dc, 0, 0, SRCCOPY);
}
}
运行一下试试,应该会有一些初始化的效果:
可以看到,首先用灰色的画刷刷了很多个GameMap为0的小矩形,综合效果就是一个灰色的背景,然后再画已生成的正在下落的方块(如图红色所示),再绘画已经落地的,即GameMap为1的小矩形,利用我们已经导入的红色方块的位图,调用BitBlt()函数即可。不过目前的效果,这个红色的方块是不会动的,因为我们还没有加入GoDown()函数的定义和计时器函数OnTimer()!