VC++ 实现俄罗斯方块小游戏(附全部源码)

VC++ 实现俄罗斯方块小游戏(附全部源码)

实现效果

在这里插入图片描述

实现思路

基于VS2017 MFC工程
俄罗斯方块是学习游戏开发经典项目,小巧而且特别容易实现。我们不去探究复杂的游戏引擎,也不去深入windows底层,直接创建mfc对话框程序就是干!

程序结构

在这里插入图片描述
程序结构非常简单,TerisApp就是游戏程序,程序里面有一个对话框TerisDlg,对话框里面有一个游戏TerisGame。

TerisApp

这个没什么可说的,我直接用向导生成的,一行代码没改

TerisDlg

对话框也是主窗口逻辑,主要是支撑显示和交互。
在这里插入图片描述

显示

在对话框的显示函数中调用渲染函数
在这里插入图片描述
渲染调用最后到达游戏

void CTetrisDlg::Render()
{
   
	CDC* dc = this->GetDC();

	CRect rect;
	GetClientRect(&rect);
	CDC memDC;
	memDC.CreateCompatibleDC(dc);
	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap(dc, rect.Width(), rect.Height());
	CBitmap* oldBitmap = memDC.SelectObject(&bitmap);

	m_pGame->Paint(memDC);

	dc->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
	memDC.SelectObject(oldBitmap);
	bitmap.DeleteObject();
	memDC.DeleteDC();
	this->ReleaseDC(dc);
	CDialogEx::OnPaint();
}

定时(心跳)

设置定时器,对话框初始化的时候设置定时器

BOOL CTetrisDlg::OnInitDialog()
{
   
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
   
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
   
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
	// TODO: 在此添加额外的初始化代码
	m_pGame->Init();
	this->SetTimer(1,500,NULL);
	this->SetTimer(2, 1, NULL);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

定时调用驱动游戏心跳和渲染

void CTetrisDlg::OnTimer(UINT_PTR nIDEvent)
{
   
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (nIDEvent)
	{
   
	case 1:
		m_pGame->Run();
		break;
	case 2:
		Render();
		break;
	default:
		break;
	}
	CDialogEx::OnTimer(nIDEvent);
}

键盘事件

主要是传入键盘事件,左右移动

void CTetrisDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
   
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (nChar)
	{
   
	case VK_UP:
		m_pGame->Rotate();
		break;
	case VK_DOWN:
		m_pGame->Down();
		break;
	case VK_LEFT:
		m_pGame->Left();
		break;
	case VK_RIGHT:
		m_pGame->Right();
		break;
	default:
		break;
	}
	CDialogEx::OnKeyDown(nChar, nRepCnt, nFlags);
}

无法响应键盘重写父类函数

BOOL CTetrisDlg::PreTranslateMessage(MSG* pMsg)
{
   
	// TODO: 在此添加专用代码和/或调用基类
	this->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
	return CDialogEx::PreTranslateMessage(pMsg);
}

游戏逻辑

头文件

enum TerisConst
{
   
	//总行数
	RowLimit = 30,
	//总列数
	ColLimit = 15,
	//绘制起始坐标
	BackX = 100,
	BackY = 30,
	//方块宽度大小
	ElementSize = 20,

	//移动方块单元数
	BlockSize = 4,
	//移动方块默认放置位置
	BlockIndex = (ColLimit / 2) - (BlockSize) / 2,
	//消去一行得分
	ScoreDelta = 100,

	//HUD
	HUD_Block_X = 560,
	HUD_Text_X = 500,

	//下一个方块
	NextBlockTextY = 50,
	NextBlockY = 100,
	ScoreTextY = 240,
	UpTextY = 340,
	DownTextY = 380,
	LeftTextY = 420,
	RightTextY = 460,
};

class CTerisGame
{
   
public:
	CTerisGame();
	~CTerisGame();

public:
	bool Init();
	void Run();
	void Paint(CDC& dc);

public:
	//左移
	void Left();
	//右移
	void Right();
	//旋转
	void Rotate();
	//速落
	void Down();

protected:
	//背景方块
	int m_nBackArr[RowLimit][ColLimit];
	//下落的方块
	int m_nFallBlock[BlockSize][BlockSize];
	//右边显示的下一个方块
	int m_nNextBlock[BlockSize][BlockSize];
	//旋转方块缓存
	int m_nRotateBlock[BlockSize][BlockSize];
	//移动方块下落行
	int m_nFallRow;
	//移动方块下落列
	int m_nFallCol;
	//是否游戏结束
	bool m_bGameOver;
	//分数
	int m_nScore;

private:
	//画一个小方块
	void DrawElement(CDC& dc, int x, int y, 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当当小螳螂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值