卷二:C++图形编程第3篇 俄罗斯方块

项目采用easyX编程操作实现:

学完C语言即可完全实现。

1.欢迎和基本界面

 (1)初始界面函数:

//一定要边该边调试
void initGameSence() {

	char str[16];
	cleardevice();//清除屏幕

	rectangle(27,27,336,635);  //调用两个矩形函数,在左边创建两个方框
	rectangle(29,29,334,633);
	rectangle(370,50,515,195);  //右边创建接下来出现的提示方块

	setfont(24,0,_T("楷体"));  //下一个方块的提示文字
	setcolor(LIGHTGRAY); //设置颜色灰色
	outtextxy(405,215,_T("下一个"));

	setcolor(RED);
	outtextxy(405,280,_T("分数"));
	//显示分数
	sprintf(str,"%d",score);  //将整型分数score转化为字符输入到字符串str
	outtextxy(415,310,str);  //该项目属性,字符集Unicode修改为多字符集
	//显示游戏等级

	outtextxy(405,375,_T("等级"));  //显示等级
	sprintf(str,"%d",myrank);
	outtextxy(415,405,str);    //等级数,outtextxy显示变量的方法

	//操作说明
	setcolor(LIGHTBLUE);  //设置颜色蓝色
	outtextxy(390,475,_T("操作说明")); 
	outtextxy(390,500,"↑:旋转");  //显示箭头提示
	outtextxy(390,525,"↓:下降");  //显示箭头提示
	outtextxy(390,550,"←:左移");  //显示箭头提示
	outtextxy(390,575,"→:右移");  //显示箭头提示
	outtextxy(390,600,"空格:暂停");  //显示箭头提示
}
//培训编程一定要轻松听着舒服的氛围,且废话不多

void welcome() {  //画布、文本
	//初始化画布,ctrl+j自动提示(非常方便)
	initgraph(550,650);
	
	//设置窗口标题
	HWND window = GetHWnd();//获取当前窗口
	SetWindowText(window,_T("荔枝番 俄罗斯方块"));//哪个窗口,设置什么值

	//文本1:字体样式、颜色、内容
	setfont(40,0,_T("微软雅黑")); //高度,宽度(不指定),样式,_T是转码
	setcolor(WHITE);  //颜色
	outtextxy(205,200,_T("俄罗斯方块")); //输出文本在坐标位置(X,Y)和内容

	//文本1:字体样式、颜色、内容
	setfont(20,0,_T("楷体")); //高度,宽度(不指定),样式
	setcolor(WHITE);  //文本颜色
	outtextxy(175,300,_T("学习C++编程,开始游戏!")); 

	Sleep(1500);//休息1.5s
}

 2.游戏控制功能

// 如果在指定位置可以向指定方向移动,就返回1, 否则就返回0
int moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) {
	// 计算当前方块的左上角在30x15的游戏区中的位置(第多少行,第多少列)
	int x = (y0 - minY) / UNIT_SIZE;
	int y = (x0 - minX) / UNIT_SIZE;
	int id = BlockIndex * 4 + blockDir;
	int ret = 1;

	if (moveDir == MOVE_DOWN) {
		for (int i=0; i<5; i++) {
			for (int j=0; j<5; j++) {
				if (block[id][i][j] == 1 &&
					(x + i + 1 >= 30  ||  visit[x+i+1][y+j] == 1)) {
						 ret = 0;
				}
			}
		}
	} else if (moveDir == MOVE_LEFT) {
		for (int i=0; i<5; i++) {
			for (int j=0; j<5; j++) {
				if (block[id][i][j] == 1 &&
					(y + j == 0 ||  visit[x+i][y+j-1]==1)) {
						ret = 0;
				}
			}
		}

	} else if (moveDir == MOVE_RIGHT) {
		for (int i=0; i<5; i++) {
			for (int j=0; j<5; j++) {
				if (block[id][i][j] == 1 && 
					(y+j+1>=15 || visit[x+i][y+j+1]==1)) {
						 ret = 0;
				}
			}
		}
	}

	return ret;
}

// 检测游戏是否结束
void failCheck() {
	if (!moveable(START_X, START_Y, MOVE_DOWN, BLOCK_UP)) {
		setcolor(WHITE);
		setfont(45, 0, "隶体");
		outtextxy(75, 300, "GAME OVER!");
		Sleep(1000);
		system("pause");
		closegraph();
		exit(0);
	}
}



// 判断当前方块是否可以转向到指定方向
// 注意, 此时还没有转到该方向!!!
int rotatable(int x, int y, block_dir_t dir) {
	int id = BlockIndex * 4 + dir;
	int xIndex = (y - minY) / 20;
	int yIndex = (x - minX) / 20;


	if (!moveable(x, y, MOVE_DOWN, dir)) {
		return 0;
	}

	for (int i=0; i<5; i++) {
		for (int j=0; j<5; j++) {
			 if (block[id][i][j] == 1 &&
				 (yIndex+j<0 || yIndex+j>=15 || visit[xIndex+i][yIndex+j]==1)) {
					 return 0;
			 }
		}
	}

	return 1;
}

void wait(int interval) { 
	int count  = interval / 10;
	for (int i=0; i<count; i++) {
		Sleep(10);
		if (kbhit()) {
			return;
		}
	}
}

void mark(int x, int y, int blockIndex, block_dir_t dir) {
	int id = blockIndex * 4 + dir;
	int x2 = (y - minY) / 20;
	int y2 = (x - minX) / 20;

	for (int i=0; i<5; i++) {
		for (int j=0; j<5; j++) {
			if (block[id][i][j] == 1) {
				visit[x2+i][y2+j] = 1;
				markColor[x2+i][y2+j] = color[blockIndex];
			}
		}
	}
}

void move(void){
	int x = START_X;
	int y = START_Y;
	int k = 0;
	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 (rotatable(x, y+k, nextDir)) {
					blockDir = nextDir;
				}
			} else if (key == KEY_DOWN) {
				curSpeed = 50;
			} else if (key == KEY_LEFT) {
				if (moveable(x, y+k+20, MOVE_LEFT, blockDir)) {
					x -= 20;
				}
			} else if (key ==KEY_RIGHT) {
				if (moveable(x, y+k+20, MOVE_RIGHT, blockDir)) {
					x += 20;  //x = x + 20;
				}
			}
		}

		k += 20;

		// 绘制当前方块
		drawBlock(x, y+k, BlockIndex, blockDir);

		wait(curSpeed);
		
		//k += 20;

		// 方块的“固化”处理
		if (!moveable(x, y+k, MOVE_DOWN, blockDir)) {
			 mark(x, y+k, BlockIndex, blockDir);
			 break;
		}
	}
}

void newblock() {
	// 确定即将使用的方块的类别
	BlockIndex = NextIndex;

	// 绘制刚从顶部下降的方块
	drawBlock(START_X, START_Y);

	// 让新出现的方块暂停一会,让用户识别到
	Sleep(100); //0.1秒

	// 在右上角区域,绘制下一个方块
	nextblock();

	// 方块降落
	move();
}

//消除第x行,并把上面的行都下移
void down(int x){
	for (int i=x; i>0; i--) {
		// 消除第i行,第j列的方格消除
		for (int j=0; j<15; j++) {
			if (visit[i-1][j]) {
				visit[i][j] = 1;
				markColor[i][j] = markColor[i-1][j];
				setcolor(markColor[i][j]);
				outtextxy(20*j + minX, 20*i+minY, "■");
			} else {
				visit[i][j] = 0;
				setcolor(BLACK);
				outtextxy(20*j + minX, 20*i+minY, "■");
			}
		}
	}

	// 清除最顶上的哪一行(就是行标为0的那一行)
	setcolor(BLACK);
	for (int j=0; j<15; j++) {
		visit[0][j] = 0;
		outtextxy(20*j + minX, minY, "■");
	}
}

// 更新分数,参数lines表示消除的行数
void addScore(int lines) {
	char str[32];

	setcolor(RED);
	score += lines * 10;
	sprintf(str, "%d", score);
	outtextxy(415, 310, str);
}

void updateGrade() {
	// 更新等级的提示
	// 假设:50分一级
	rank = score / 50;
	char str[16];
	sprintf(str, "%d", rank);
	outtextxy(425, 405, str);

	// 更新速度, 等级越高,速度越快,speed越小!
	// 最慢:500, 最快是100
	speed = 500 - rank*100;
	if (speed <= 100) {
		speed = 100;
	}
}

void check(void) {
	int i, j;
	int clearLines = 0;

	for (i=29; i>=0; i--) {
		// 检查第i行有没有满
		for (j=0; j<15 && visit[i][j]; j++) ;

		//执行到此处时,有两种情况:
		// 1. 第i行没有满,即表示有空位 此时 j<15
		// 2. 第i行已满了,此时 j>=15
		if (j >= 15) {
			// 此时,第i行已经满了,就需要消除第i行
			down(i);  //消除第i行,并把上面的行都下移
			i++;  // 因为最外层的循环中有 i--, 所以我们先i++, 使得下次循环时,再把这一行检查一下
			clearLines++;
		}
	}

	// 更新分数
	addScore(clearLines);

	// 更新等级(更新等级提示,更新速度)
	updateGrade();
}

int main(void) {
	welcome();
	initGameScene();

	// 产生新方块
	nextblock();
	Sleep(500);

	// 初始化访问数组
	memset(visit, 0, sizeof(visit));

	while (1) {
		newblock();

		// 消除满行,并更新分数和速度
		check();
	}

	system("pause");
	closegraph();
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值