初学者用C++写俄罗斯方块

本文介绍了作者初次接触C++时实现俄罗斯方块游戏的过程,分享了代码实现细节,包括二维数组、输入函数和Sleep函数的应用。代码中存在一些已知问题,如在边缘连续按键可能导致错误。文章提供了完整的游戏逻辑,包括方块生成、移动、消除行等功能,并给出了关键函数的实现。此外,作者强调了原创性的重要性,提醒读者避免抄袭。
摘要由CSDN通过智能技术生成

笔者刚接触C++,力图用的知识点简单一点。所以这次基本只运用了二维数组的知识,再去网上搜了输入的函数和Sleep函数就基本实现了相关功能。但我的代码也存在明显漏洞,比如一直按着移动键不放或者是在边缘处狂按会出bug,欢迎大家提出宝贵的改进建议。

最重要的是,如果您是为了交作业,希望我的代码可以给您带来崭新的思路,但是

请勿抄袭!

请勿抄袭!

请勿抄袭!

请勿抄袭!

请勿抄袭!

#include <iostream>
#include <windows.h>

#include <conio.h>
using namespace std;

#define SCREEN_WIDTH 16
#define SCREEN_HEIGHT 25
#define BLOCK_SIZE 4
//

// 已发现的bug:在边缘处狂按移动键或按着不发,会出bug。
// 我是在教员给的基础上写的,对部分函数进行了完善。因为我设置的每次输入一个,因此多线程不是很有必要。
//初始每1秒方块下降一个,每删去一行,score加1,时间减0.01秒; 


// 
//全局变量
int xPos, yPos;
bool t,h;
 
int f;
int y; //当前方块横、纵坐标
int ground[SCREEN_HEIGHT][SCREEN_WIDTH] = { 0 }; //背景矩阵
// 1代表有方块,0代表无方块 
	//声明并初始化俄罗斯方块数组,将每种形状的变形列出,通过改变访问的元素改变性状 
int blocks[19][4][4] = {
{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}},// l

{{0, 0, 0, 0}, {0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}},//2

{{0, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}},//3
{{0, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}},//


{{0, 0, 0, 0}, {0, 0, 1, 1}, {0, 1, 1, 0}, {0, 0, 0, 0}},//5
{{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}},//

{{0, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 1, 1, 0}},//7
{{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 1}, {0, 0, 0, 0}},//
{{0, 0, 0, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}},
{{0, 0, 0, 0}, {1, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}},//

{{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}},//11
{{0, 0, 0, 0}, {0, 1, 1, 1}, {0, 1, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 1, 1, 1}, {0, 0, 0, 0}},

{{0, 0, 0, 0}, {1, 1, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}},//15
{{0, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0}},
{{0, 0, 0, 0}, {0, 1, 0, 0}, {1, 1, 1, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 1, 0, 0}}
};
//在指定位置画一个方块
void drawBlock(int x, int y, int block[][BLOCK_SIZE]); 
//把光标定位到指定坐标
void gotoxy(int x, int y); 
//清除指定位置的方块
void clearBlock(int x, int y, int block[][BLOCK_SIZE]);
//向下移动方块
bool moveDown(int x, int y, int block[][BLOCK_SIZE]);
//在窗口顶部创建一个新的方块
int createBlock(); //无法创建时,返回-1,说明已经到顶。 
void key(int &x,int &y,int &index,int block[][BLOCK_SIZE]); 
void toLeft(int x,int y,int block[][BLOCK_SIZE]); 
void toRight(int x, int y, int block[][BLOCK_SIZE]);
int man(int g[SCREEN_HEIGHT][SCREEN_WIDTH]);
void change(int &i);
int main() {
//	drawBlock(8, 0, blocks[0]);
	cout<<"  俄罗斯方块  "<<endl;
	cout<<"< 左移; > 右移; ^ 翻转; \/ 下移;  空格键暂停,再输入任意数字,按下回车键继续游戏" ;
	Sleep(6000);
	for(int i=0;i<SCREEN_WIDTH+50;i++)
	{
		gotoxy(i,0);
		
		cout << "  "  ;
	}
	for(int i=0;i<SCREEN_WIDTH+50;i++)
	{
		gotoxy(i,1);
		
		cout << "  "  ;
	}
	for(int i=0;i<SCREEN_HEIGHT;i++)
	{
		gotoxy(0,i);
		ground[i][0]=1;
		cout << "■";
		gotoxy(15,i);
		ground[i][15]=1;
		cout << "■";
	} 
	for(int i=1;i<SCREEN_WIDTH-1;i++)
	{
		gotoxy(i,24);
		ground[24][i]=1;
		cout << "■";
		
	} 
	//初始化背景,将边缘初始化为1 
	int xPos = SCREEN_WIDTH / 2 - 2; //初始坐标
	int yPos = 0;
	bool t=true;
	bool k=true;
	int index=0;
	int s=0;
	while(t)
	{
		index=createBlock();
		if(index==-1)
		{
			break;
		}
		//到顶就GAME OVER了 
		
		k=true;
		xPos = SCREEN_WIDTH / 2 - 2; 
		yPos = 0;
		
			while (k) {
				if (moveDown(xPos, yPos, blocks[index])) {
					yPos++; //纵坐标加一
				}
				else {
					k=false;
				}
				
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]); 
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s);  
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				Sleep(100-s); 
				key(xPos,yPos,index,blocks[index]);
				//挂起一秒
			}
		h=true;
		while(h)
		{
			y=man(ground);
			if(y>0)
				s++;
			
			for(int i=y;i>0;i--)
			{
				for(int d=1;d<SCREEN_WIDTH-1;d++)
				{
					gotoxy(d,i);
					if(ground[i-1][d]==1)
					{
						ground[i][d]=1;
						cout <<"■";
					}
					else if(ground[i-1][d]==0)
					{
						ground[i][d]=0;
						cout << "  "  ;
					}
				}
				
				
			
			} 
			if(f==0)
			{
				h=false;
			}
		}
		
		
	}
	cout<<"Game over!!"<<"  your score: "<<s;;
	return 0;
	
	
}
void drawBlock(int x, int y, int block[][BLOCK_SIZE])
{
	for (int i = 0; i < BLOCK_SIZE; i++) {
		for (int j = 0; j < BLOCK_SIZE; j++) {
			if (block[i][j] == 1) {
				gotoxy(x + j, y + i); //注意横纵坐标的变换
				ground[y+i][x+j]=1;
				cout << "■";
			}
		}
	}
}
void gotoxy(int x, int y)
{
	COORD point;
	point.X = x * 2;
	point.Y = y;
	SetConsoleCursorPosition(
		GetStdHandle(STD_OUTPUT_HANDLE), point);
}
void clearBlock(int x, int y, int block[][BLOCK_SIZE])
{
	for (int i = 0; i < BLOCK_SIZE; i++) {
		for (int j = 0; j < BLOCK_SIZE; j++) {
			if (block[i][j] == 1) {
				gotoxy(x + j, y + i);
				 //注意横纵坐标的变换
				ground[y+i][x+j]=0;
				cout << "  ";
			}
		}
	}
}

bool moveDown(int x, int y, int block[][BLOCK_SIZE])
{
	bool canMoveDown = true;
	for (int i = 0; i < BLOCK_SIZE; i++) { //先判断能否向下移动
		for (int j = 0; j < BLOCK_SIZE; j++) {
			if  ((block[i][j] > 0 && block[i+1][j] == 0)
				&& ((y + i + 1 == 24)
					|| (ground[y + i+1][x + j] == 1))){
				canMoveDown = false;
				break;
			}
		}
		if (!canMoveDown) break;
	}
	if (canMoveDown) {
		clearBlock(x, y, block); //清除原来位置的方块
		drawBlock(x, y + 1, block); //在新的位置绘制方块
	}
	return canMoveDown;
}
int createBlock()
{
	int blockIndex = rand() % 19; //随机生成一个新的方块
	xPos = SCREEN_WIDTH / 2 - 2;
	yPos = 0;
	for (int i = 0; i < BLOCK_SIZE; i++) {
		for (int j = 0; j < BLOCK_SIZE; j++) {
			if ((blocks[blockIndex][i][j] == 1) //判断能否绘制新方块
				&& (ground[yPos + i][xPos + j] == 1))
				return -1;
		}
	}
	//drawBlock(xPos, yPos, blocks[blockIndex]); //绘制新方块
	return blockIndex;
}
void key(int &x,int &y,int &index,int block[][BLOCK_SIZE])
{
	if(kbhit( ))
	{
		int key;
		key=_getch();
		
		if(key==75)//输入左键 
		{
			toLeft(x, y, blocks[index]);
			x--;
		}
		if(key==77)//输入右键 
		{
			toRight(x, y, blocks[index]);
			x++;
		}
		if(key==32)//输入空格键 
		
		{
			cin>>f;//暂停,输入数字继续 
		 } 
		if(key==72)//输入上键
		{
			clearBlock(x, y, blocks[index]); //清除原来位置的方块
			
			
			change(index); 
			drawBlock(x, y , blocks[index]);
			 
		 } 
		if(key==80)//输入下键
		{
			t=moveDown(x, y, blocks[index]);
			y++;
		}
		
		
		
	}
}
void toLeft(int x,int y,int block[][BLOCK_SIZE])
{
	bool toleft=true;
	for (int i = 0; i < BLOCK_SIZE;i++) 
	{
		for (int j = 0; j < BLOCK_SIZE; j++)
		{
			if ((block[i][j] > 0 && block[i][j-1] == 0)&&
				//&& ((x + i - 1 == 0)因为已经初始化,此条件可省去 
					(ground[y + i][x + j-1] == 1))
			{
				toleft = false;
				break;	
			}
		}
		if (!toleft) break;
		
	}
	if (toleft) {
		clearBlock(x, y, block); //清除原来位置的方块
		drawBlock(x-1, y , block); //在新的位置绘制方块
	}

}
void toRight(int x, int y, int block[][BLOCK_SIZE])
{
	bool toright=true;
	for (int i = 0; i < BLOCK_SIZE;i++) 
	{
		for (int j = 0; j < BLOCK_SIZE; j++)
		{
			if ((block[i][j] > 0 && block[i][j+1] == 0)
				&& ((x + i + 1 == 16)
					|| (ground[y + i][x + j+1] == 1)))
			{
				toright = false;
				break;	
			}
		}
		if (!toright) break;
		
	}
	if (toright) {
		clearBlock(x, y, block); //清除原来位置的方块
		drawBlock(x+1, y , block); //在新的位置绘制方块
	}
}



int man(int g[SCREEN_HEIGHT][SCREEN_WIDTH])//从下往上遍历返回第一个满行的行数,若为0,说明没有满行的 
{
	int a= SCREEN_HEIGHT-2;
	for(int r= SCREEN_HEIGHT-2;r>0;r--)
	{
		for(int i=1;i<SCREEN_WIDTH-1;i++)
		{
			if(g[r][i]!=1)
				a=r-1;
				
		}
		if(a==r)
		{
			break;
		}
	}
	return a;
}
void change(int &i)//将每种形状的变形列出,通过改变访问的元素改变性状 
{
	if(i==0)
		i++;
	else if(i==1)
		i--;
	else if(i==3)
		i++;
	else if(i==4)
		i--;
	else if (i==5)	
		i++;
	else if (i==6)
		i--;
	else if (i==7  || i==8 || i==9)
		i++;
	else if(i==10)
		i=7;
	else if(i==11 || i==12 || i==13)
		i++;
	else if (i==14)
		i=11;
	else if(i==15 || i==16 || i==17)
		i++;
	else if (i==18)
		i=15;
	
	
}

程序设计课上,老师布置了俄罗斯方块作为我们的大作业。在自己写完以后,我也分享一下我的心得体会。

首先是审题,老师已经给了一部分代码,应该就是要我继续往后写,所以必须先弄懂老师设置的各个函数的意思。

最后就是不断的尝试啦,失败是成功之母!

最后,感谢其他博主的分享!

相关链接:

Sleep()函数的使用方法详解https://blog.csdn.net/weixin_52142731/article/details/110477154

_getch()函数的介绍

https://blog.csdn.net/jackJruit/article/details/108409652

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值