C++开发游戏(俄罗斯方块)

游戏成品概览

 无UI,命令行形式,初学C++游戏制作以游戏逻辑的学习为主。

七种俄罗斯方块的设计

//创建资源
	tetromino[0].append(L"..X.");
	tetromino[0].append(L"..X.");
	tetromino[0].append(L"..X.");
	tetromino[0].append(L"..X.");

	tetromino[1].append(L"..X.");
	tetromino[1].append(L".XX.");
	tetromino[1].append(L".X..");
	tetromino[1].append(L"....");

	tetromino[2].append(L".X..");
	tetromino[2].append(L".XX.");
	tetromino[2].append(L"..X.");
	tetromino[2].append(L"....");

	tetromino[3].append(L"....");
	tetromino[3].append(L".XX.");
	tetromino[3].append(L".XX.");
	tetromino[3].append(L"....");

	tetromino[4].append(L"..X.");
	tetromino[4].append(L".XX.");
	tetromino[4].append(L"..X.");
	tetromino[4].append(L"....");

	tetromino[5].append(L"....");
	tetromino[5].append(L".XX.");
	tetromino[5].append(L"..X.");
	tetromino[5].append(L"..X.");

	tetromino[6].append(L"....");
	tetromino[6].append(L".XX.");
	tetromino[6].append(L".X..");
	tetromino[6].append(L".X..");

游戏碰撞检测机制

俄罗斯方块不能叠到一起,在距离相近时产生碰撞,不再下落

bool DoesPieceFit(int nTetromino, int nRotation, int nPosX, int nPosY)//碰撞检测机制
{
	for (int px = 0; px < 4; px++)
		for (int py = 0; py < 4; py++)
		{
			//获取块内索引
			int pi = Rotate(px, py, nRotation);

			//获取区域索引
			int fi = (nPosY + py) * nFieldWidth + (nPosX + px);

			if (nPosX + px >= 0 && nPosX + px < nFieldWidth)
			{
				if (nPosY + py >= 0 && nPosY + py < nFieldHeight)
				{
					if (tetromino[nTetromino][pi] == L'X' && pField[fi] != 0)
						return false;//产生碰撞,检测不合格
				}
			}
		}
}

游戏核心逻辑

旋转

int Rotate(int px, int py, int r)
{
	switch (r % 4)//根据旋转进行坐标变换
	{
	case 0: return py * 4 + px;			// 0度
	case 1: return 12 + py - (px * 4);	// 90度
	case 2: return 15 - (py * 4) - px;	// 180度
	case 3: return 3 - py + (px * 4);	// 270度
	}
}

根据矩阵不同索引进行旋转

按键控制

//输入
		for (int k = 0; k < 4; k++)								//R		L	D	Z
			bKey[k] = (0x8000 & GetAsyncKeyState((unsigned char)("\x27\x25\x28\Z"[k]))) != 0;//按下这一系列按键bKey为真,其它则无响应为假(异步判断)

		//游戏逻辑
		nCurrentX += (bKey[0] && DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX + 1, nCurrentY)) ? 1 : 0;
		nCurrentX -= (bKey[1] && DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX - 1, nCurrentY)) ? 1 : 0;
		nCurrentY += (bKey[2] && DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1)) ? 1 : 0;
		

游戏流程

强制下移

if (bForceDown)
		{
			if (DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY + 1))
				nCurrentY++;//能下来
			else
			{
				//锁住当前方块
				for (int px = 0; px < 4; px++)
					for (int py = 0; py < 4; py++)
						if (tetromino[nCurrentPiece][Rotate(px, py, nCurrentRotation)] == L'X')
							pField[(nCurrentY + py) * nFieldWidth + (nCurrentX + px)] = nCurrentPiece + 1;
				
				nPieceCount++;
				if (nPieceCount % 10 == 0)
					if (nSpeed >= 10) nSpeed--;//随着游戏下落方块的增加,游戏难度不断上升
				
				//检查一行是否满
				for(int py=0;py<4;py++)
					if (nCurrentY + py < nFieldHeight - 1)
					{
						bool bLine = true;
						for (int px = 1; px < nFieldWidth - 1; px++)
							bLine &= (pField[(nCurrentY + py) * nFieldWidth + px]) != 0;//这一行若是没有空隙,按位与运算为真

						if (bLine)
						{
							//这一行消失,设置为 =
							for (int px = 1; px < nFieldWidth - 1; px++)
								pField[(nCurrentY + py) * nFieldWidth + px] = 8;
							
							vLines.push_back(nCurrentY + py);//将改行存储到数组中
						}
					}

				nScore += 25;
				if (!vLines.empty()) nScore += (1 << vLines.size()) * 100;//给线条打分

				//选择下一个块
				nCurrentX = nFieldWidth / 2;
				nCurrentY = 0;
				nCurrentRotation = 0;
				nCurrentPiece = rand() % 7;
				
				//无法下落情况且方块形状产生碰撞检测,游戏结束
				bGameOver = !DoesPieceFit(nCurrentPiece, nCurrentRotation, nCurrentX, nCurrentY);
			}
			nSpeedCounter = 0;//每下落一次清零一次
		}

游戏滴答(速度控制)

//处理时机
		this_thread::sleep_for(50ms);//一个游戏“滴答”
		nSpeedCounter ++;
		bForceDown = (nSpeedCounter == nSpeed);//设置方块自由下落的速度(学到的一个有趣的逻辑)

分数获取

nScore += 25;
if (!vLines.empty()) nScore += (1 << vLines.size()) * 100;//给线条打分

共有两种逻辑的获取方式、

1:下落方块数量,每个加25分

2:根据消除线条数量给分(危险奖励机制)

线条消除

if (!vLines.empty())
		{
			//显示窗口
			WriteConsoleOutputCharacter(hConsole, screen, nScreenHeight * nScreenWidth, { 0,0 }, &dwBytesWritten);
			this_thread::sleep_for(400ms);//产生一些延迟,为了保证消除的顺利,游戏的流畅

			for (auto& v : vLines)
				for (int px = 1; px < nFieldWidth - 1; px++)
				{
					for (int py = v; py > 0; py--)
						pField[py * nFieldWidth + px] = pField[(py - 1) * nFieldWidth + px];//把上一行的移到下一行
					pField[px] = 0;
				}
			vLines.clear();//清除存储的行
		}

至此,俄罗斯方块游戏的核心逻辑全部结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值