小聊C++实现俄罗斯方块的一点小细节

本文介绍了使用C++和EasyX图形库实现俄罗斯方块的过程,着重讨论了优化方块下落功能的细节。在原有实现基础上,作者发现了按键响应问题并提出了改进方案,确保方块下落符合实际游戏规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这段时间学习了一些C++的内容,跟着教程使用C++粗略还原了俄罗斯方块的一些基本内容,本文主要针对方块下落的环节找到一些可以选择的方案。

俄罗斯方块实现简述

工具介绍

编译软件采用VC++2010,图形库是EasyX,这算是比较初级的软件了,简单的功能往往只需要使用简单的工具[狗头]。

程序结构

俄罗斯方块的粗略实现只需要根据功能建立一些结构体,暂时还可以不使用到C++的类功能,下面对程序结构进行简要说明。

主函数部分void main(void)

1.显示欢迎界面
设计一个Hello界面
2.显示游戏界面
设计一个游戏界面。分为游戏区、下一个方块区、右侧积分和等级区、操作说明区。其中游戏区和NEXT区的外框、积分区的SCORE和LEVEL、操作区是固定好的。
3.在右上角产生新的方块
4.开始游戏部分(下面拆分)
5.结束

游戏部分

1.在游戏区产生一个新块,执行下落等功能(下面拆分)
2.判断这个块下落结束后是否需要消除行,是则消除行、加分、加等级,不是则跳过

下落等功能

1.使NEXT区显示的方块对应地在游戏区出现
2.在右上角绘制一个新的方块
3.向下移动(讨论部分)

实现原理

俄罗斯方块的实现原理是
将游戏区设计成二维数组(例如30×15大小),预先将各种块也设计成二位数组写好并存入一个.cpp文件中(例如5×5大小);随机生成一个存在NEXT区域,再将此块在游戏区生成并使其按时间下落,同时新随机生成一个块存在NEXT区域;在当前块下落后判断是否需要消除行,若是则执行消除,并且该行的所有上方数据向下移动一行。循环实现即可。

讨论部分:当前块下落过程

我按照教程写的第一版下落函数的流程为:

1.首先检查游戏是否结束,即GAME OVER!
2.做一个循环
(1)检查当前是否有按键按下,如果该键为SPACE,则暂停。
(2)将当前方块清除
(3)如果有按键按下,并且该键为“上”,则先判断该方块是否可以转换,如果可以则转换形状;如果该键为“下”,则将方块下落速度调整至最快;如果该键为“左(右)”,则判断该方块是否可以向左(右)移动,如果可以则把方块坐标向左(右)移动一格。
(4)将当前方块坐标向下移一格并绘制当前方块
(5)等待一段时间(这段时间可以被“下”键调整至极低)
(5)判断方块是否可以继续向下移动,若可以则继续循环,若不可则在地图二维数组中标记固化位置。
3.“等待”方法中,将等待时间分为若干个10ms的时间块,如果检测到按键输入,则跳出该模块,进入下一个循环中。

在该方法完成后发现,如果不按按键,是按照规定时间逐步下落,但是每按一次按键,方块都会迅速下落一格,即如果按了“左”,方块会瞬移到他的左下方,这与实际玩法不符,所以进行了改动,流程如下:

1.检查游戏是否结束,即GAME OVER!
2.循环开始
(1)清除当前方块,下落一格,生成新方块
(2)直接生成一个每10ms一周期的循环,每个周期内检查是否有按键按下,如果有并且是“上”、“左”、“右”,则判断是否能够到达新的位置,如果是则直接生成新的位置。如果是“下”则降低持续时间,缩短该10ms一周期的总周期数。
(3)方块的固化处理不变。

上代码

改动前:

//向下移动
void move(void) {
	//初始位置
	int x = START_X;
	int y = START_Y;
	int k = 0;	//y偏移量

	block_dir_t blockDir = BLOCK_UP;//当前朝向
	int curSpeed = speed;//当前速度

	//检测游戏是否结束
	failCheck();

	//持续向下
	while(1) {
		if(kbhit()) {				//检查是否有按键
			int key = getch();
			if(key == KEY_SPACE) {
				getch();
			}
		}
			//清除当前方块
		clearBlock(x, k, blockDir);

		if(kbhit()) {				//检查是否有按键
			int key = getch();

			if(key == KEY_UP) {
				block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4);
				if(rotateable(x, y+k, nextDir)) {
					blockDir = nextDir;
				}
			}
			else if(key == KEY_DOWN) {
				curSpeed = 50;
			}
			else if(key == KEY_LEFT){
				if(moveable(x, y+k, MOVE_LEFT, blockDir))
					x -= 20;
			}
			else if(key == KEY_RIGHT) {
				if(moveable(x, y+k, MOVE_RIGHT, blockDir))
					x += 20;
			}
		}

		k += 20;//偏移量加一格

		//绘制当前方块
		drawBlock(x, y+k, blockDir);
		
		//等待
		wait(curSpeed);
		

		//方块的"固化"处理,能否向下移动
		if(!moveable(x, y+k, MOVE_DOWN, blockDir)) {
			mark(x, y+k, blockDir);
			break;
		}
	}
}

改动后:

void move(void) {
	//初始位置
	int x = START_X;
	int y = START_Y;
	int k = 0;//y偏移量

	block_dir_t blockDir = BLOCK_UP;//当前朝向
	int curSpeed = speed;//当前速度

	//检测游戏是否结束
	failCheck();

	//持续向下
	while(1) {

		clearBlock(x, k, blockDir);//清除当前方块

		k += 20;//偏移量加一格

		//绘制当前方块
		drawBlock(x, y+k, blockDir);
				
		for(int i = 0; i < curSpeed / 10; i++) {
			Sleep(10);

			if(kbhit()) {
				int key = getch();
				//清除当前方块
				clearBlock(x, k, blockDir);

				if(key == KEY_UP) {
					block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4);
					if(rotateable(x, y+k, nextDir)) {
						blockDir = nextDir;
					}
				}
				else if(key == KEY_DOWN) {
					curSpeed = 50;
					break;
				}
				else if(key == KEY_LEFT){
					if(moveable(x, y+k, MOVE_LEFT, blockDir))
						x -= 20;
				}
				else if(key == KEY_RIGHT) {
					if(moveable(x, y+k, MOVE_RIGHT, blockDir))
						x += 20;
				}
				else if(key == KEY_SPACE) {
					getch();
				}
				drawBlock(x, y+k, blockDir);
			}
		}


		

		//方块的"固化"处理,能否向下移动
		if(!moveable(x, y+k, MOVE_DOWN, blockDir)) {
			mark(x, y+k, blockDir);
			break;
		}
	}
}

我是没信号的法杖,发不出去信号,也接收不到信号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值