自己写“俄罗斯方块”(一).实现基本业务逻辑和绘图

开发环境:VS2015

一如既往地新建一个MFC应用程序,开始执行的效果如图:

自己写“俄罗斯方块”(一).实现基本业务逻辑和绘图_第1张图片

首先设计一下业务逻辑:

通过一个计时器函数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);
	}
}

运行一下试试,应该会有一些初始化的效果:

自己写“俄罗斯方块”(一).实现基本业务逻辑和绘图_第2张图片

可以看到,首先用灰色的画刷刷了很多个GameMap0的小矩形,综合效果就是一个灰色的背景,然后再画已生成的正在下落的方块(如图红色所示),再绘画已经落地的,即GameMap1的小矩形,利用我们已经导入的红色方块的位图,调用BitBlt()函数即可。不过目前的效果,这个红色的方块是不会动的,因为我们还没有加入GoDown()函数的定义和计时器函数OnTimer()!


你可能感兴趣的:(MFC)