通过Acllib实现的俄罗斯方块小游戏

Acllib俄罗斯方块小游戏,第二次使用ACLLIB写图形,第一次是参考不明真相的板蓝根 实现的一个桌面时钟,写的很详细,链接见底

对于Acllib感兴趣的同学可以参考一下。

下面说下俄罗斯方块游戏的设计的关键:

#为方便起见,下文中所有 L,l, Z 等等(包括旋转后)的图形都用“俄罗斯方块”来替代

1.通过数组存储所有俄罗斯方块的图形位置信息(包括旋转后的),PS.本来想通过对位置做旋转算法来实现,后来网上参考了一下,因为做运算的时间远超重画图形的时间,网上俄罗斯方块的实现似乎都是存储所有图形的,便作罢,感兴趣的同学可以讨论一下

2.利用全局二维数组WINODW来存储已经存在的俄罗斯方块的信息。

3.代码中注释写的很详细,感兴趣的同学请仔细阅读,欢迎留言讨论~

#include <acllib.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>

using namespace std;

//黑色 RGB值
#define BLACK RGB(0,0,0)
//定义单位像素的边长
#define step 10
//游戏窗体高度
#define boundaryH 28
//游戏窗体宽体
#define boundaryW 14
//俄罗斯方块形状的总数目(包括旋转后的)
#define Max_Shape 19

//窗体内已经存在的内容(重要,用于存放已经落下的俄罗斯方块的信息)
int WINDOW[boundaryH][boundaryW] = { 0 };

//旋转,向左/右移动的标志
bool isTransform = false;
bool isToLeft = false;
bool isToRight = false;

//俄罗斯方块形状编号num(重要全局变量,用于控制记录移动,形变以及边界是否碰撞) , 用于记录定时器次数cnt
int num = 0,cnt=0;

//位置信息结构体
struct Pstruct {
	int  y,x;
};

//形状信息结构体
struct Sstruct {
	int shape[4][4];
	int next;
};

//每个形状的标准方向的编号,用于初始化生成随机俄罗斯方块使用
int seq[7] = { 0,2,6,10,12,14,15 };

//每个俄罗斯方块形状的图形数据(包括旋转后的),用4*4二维数组表示,心中有数即可,请直接略过
struct Sstruct SHAPE[19] = {
//l
{
 1,0,0,0,
 1,0,0,0,
 1,0,0,0,
 1,0,0,0,1
}
,
//一
{
	0,0,0,0,
	0,0,0,0,
	1,1,1,1,
	0,0,0,0,0
}
//L
,{
	0,0,0,0,
	1,0,0,0,
	1,0,0,0,
	1,1,0,0,3

}
,
{
	0,0,0,0,
	1,1,1,0,
	1,0,0,0,
	0,0,0,0,4
}

,{
	0,0,0,0,
	1,1,0,0,
	0,1,0,0,
	0,1,0,0,5

}
,
{
	0,0,0,0,
	0,0,1,0,
	1,1,1,0,
	0,0,0,0,2
}
//rL
,{
	0,0,0,0,
	0,1,0,0,
	0,1,0,0,
	1,1,0,0,7

}
,
{
	0,0,0,0,
	1,0,0,0,
	1,1,1,0,
	0,0,0,0,8

}

,{
	0,0,0,0,
	1,1,0,0,
	1,0,0,0,
	1,0,0,0,9

}

,
{
	0,0,0,0,
	1,1,1,0,
	0,0,1,0,
	0,0,0,0,6
}
//Z
,
{
	0,0,0,0,
	0,1,0,0,
	1,1,0,0,
	1,0,0,0,11
}
,
{
	0,0,0,0,
	1,1,0,0,
	0,1,1,0,
	0,0,0,0,10
}
,
//rZ
{
	0,0,0,0,
	0,1,1,0,
	1,1,0,0,
	0,0,0,0,13
}
,
{
	0,0,0,0,
	1,0,0,0,
	1,1,0,0,
	0,1,0,0,12
}
,
//田
{
	0, 0, 0, 0,
	1, 1, 0, 0,
	1, 1, 0, 0,
	0, 0, 0, 0,14
}
,
//T
{
	0, 0, 0, 0,
	0, 1, 0, 0,
	1, 1, 1, 0,
	0, 0, 0, 0,16
}
,
{
	0,0,0,0,
	1,0,0,0,
	1,1,0,0,
	1,0,0,0,17
}
,
{
	0, 0, 0, 0,
	1, 1, 1, 0,
	0, 1, 0, 0,
	0, 0, 0, 0,18
}
,
{
	0,0, 0, 0,
	0,1, 0, 0, 
	1,1, 0, 0,
	0,1, 0, 0,15
}
};
//当前正在运动的俄罗斯方块的位置变量posi,(重要全局变量,用于控制记录方块移动,是否碰撞,4*4数组最左上角的位置)
struct Pstruct posi;

//俄罗斯方块生成函数
void initCube();
//定时器中断
void timeEvent(int tid);
//键盘中断
void keyEvent(int key, int event);
/*
//获取俄罗斯方块的右边源
int getRightEdge(int num);
//获取俄罗斯方块的底边源
int getBottomEdge(int num);
*/


int Setup()
{
	//生成窗口
	initWindow("Test", DEFAULT, DEFAULT, 380, 300);
	int x;
	
	initCube();
	//注册定时器中断
	registerTimerEvent(timeEvent);
	//注册键盘中断
	registerKeyboardEvent(keyEvent);
	//开启定时器,50ms
	startTimer(0, 50);
	return 0;
}

void initCube() {
	//方块初始位置,游戏窗体的中点处
	posi = { 0,(boundaryW+5)/2 };
	//srand生成随机因子,rand生成随机数
	srand((unsigned)time(NULL));
	num = seq[rand() % 7];
}

//定时器每中断一次重画一次游戏窗体,即每50ms重画一次
void picture_a_Cube() {
	beginPaint();
	//清屏
	clearDevice();
	//定义画笔画刷为黑色
	setPenColor(BLACK);
	setBrushColor(BLACK);
	//勾画游戏窗体边界
	line(50, 0, 50, boundaryH*step);
	line(50 + boundaryW* step, 0, 50 + boundaryW* step, boundaryH*step);
	line(50, boundaryH * step, 50 + boundaryW * step, boundaryH * step);

	//将WINDOW内存在的并且还未消除的俄罗斯方块画出
	for (int i = 0; i < boundaryH; i++) {
		for (int j = 0; j < boundaryW; j++) {
			if (WINDOW[i][j])rectangle((j + 5)* step, i * step, (j + 5 + 1) * step, (i + 1) * step);
		}
	}
	
	//旋转
	if (isTransform) {
		isTransform = false;
		//temp用于存储原来的形状
		int temp = num;
		num = SHAPE[num].next;
		//判断是否可以进行旋转,如果旋转后的与原WINDOW内存在内容冲突则撤销
		bool isReach = false;
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) {
				if (SHAPE[num].shape[i][j]) {
					if (posi.y + i + 1 >= boundaryH || WINDOW[posi.y + i + 1][posi.x - 5 + j]) {
						isReach = true;
						break;
					}
				}
			}
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) {
				if (SHAPE[num].shape[i][j]) {
					if (posi.x + j + 1 >= boundaryW + 5 || WINDOW[posi.y + i][posi.x - 5 + 1 + j]) {
						isReach = true;
						break;
					}
				}
			}
		//撤销
		if (isReach) num = temp;
	}
	//左移
	if (isToLeft) {
		isToLeft = false;
		bool isReach = false;
		//判断左移后是否冲突
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) {
				if (SHAPE[num].shape[i][j]) {
					if (posi.x + j - 1 < 5 || WINDOW[posi.y + i][posi.x - 5 - 1 + j]) {
						isReach = true;
						break;
					}
				}
			}
		if(!isReach) posi.x--;

	}
	//右移
	if (isToRight) {
		isToRight = false;
		bool isReach = false;
		//判断是否冲突
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++) {
				if (SHAPE[num].shape[i][j]) {
					if (posi.x + j + 1 >= boundaryW+5 || WINDOW[posi.y + i][posi.x - 5 + 1 + j]) {
						isReach = true;
						break;
					}
				}
			}
		if (!isReach) posi.x++;
	}
	//画出俄罗斯方块图形
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			if (SHAPE[num].shape[i][j]) {
				rectangle((j + posi.x) * step, (i + posi.y) * step, (j + 1 + posi.x) * step, (i + 1 + posi.y) * step);
			}
		}
	}

	//判断WINDOW数组是否存在某一行都存在方块,如果是则消除该行,并将之上的数据下移一行
	for(int i=0;i<boundaryH;i++)
	{
		int count = 0;
		for (int j = 0; j < boundaryW; j++) {
			if (!WINDOW[i][j])break;
			count++;
		}
		if (count == boundaryW) {
			for (int k = i-1; k >= 0; k--) {
				for (int j = 0; j < boundaryW; j++) {
					WINDOW[k+1][j] = WINDOW[k][j];
				}
			}
			for (int j = 0; j < boundaryW; j++) WINDOW[0][j] = 0;
		}
	}
	endPaint();

}

void timeEvent(int tid) {
	cnt++;
	//每隔50*5ms下降一个单位
	if (cnt >= 5 ) {
		cnt = 0;
		bool isReach = false;
		//判断是否可以下降
		for (int i = 0; i < 4; i++)
				for (int j = 0; j < 4; j++) {
					if (SHAPE[num].shape[i][j]) {
						if (posi.y + i + 1>=boundaryH || WINDOW[posi.y + i + 1][posi.x - 5 + j]) {
							isReach = true;
							break;
						}
					}
				}
		if(!isReach) posi.y++;
		else { //方块落地/障碍。
			for (int i = 0; i < 4; i++)
				for (int j = 0; j < 4; j++) {
					if (SHAPE[num].shape[i][j]) {
						WINDOW[posi.y + i][posi.x - 5 + j] = 1;
					}
				}
			initCube();
		}
	}
	//重绘游戏窗体
	picture_a_Cube();
}
void keyEvent(int key, int event) {
	//形变
	if (key == VK_SPACE) {
		if (event == KEY_UP) {
			isTransform = true;
		}
	}
	//左移
	if (key == VK_LEFT) {
		if (event == KEY_UP) {
			isToLeft = true;
		}
	}
	//右移
	if (key == VK_RIGHT) {
		if (event == KEY_UP) {
			isToRight = true;
		}
	}
	//加速下降,50ms改为10ms
	if (key == VK_DOWN) {
		if (event == KEY_DOWN) {
			startTimer(0, 10);
		}
		else if (event == KEY_UP) {
			startTimer(0, 50);
		}
	}
}

《利用Acllib写的一个桌面时钟》:http://blog.csdn.net/plank_root/article/details/52640681

未经允许请勿转载,谢谢



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值