j2me版本的俄罗斯方块写法要点

这几天一直想写点自己的小游戏,刚巧手头有本《J2MEMIDP手机游戏程序设计》,其中第六章有讲俄罗斯方块的写法,但是一看之后却发现根本不是,于是在网上四处查找简单有效的俄罗斯方块源码,并且研究了一下,发现,基本思想大同小异,但是我找到的代码虽然简单,却有疏漏,他没有考虑方块在边界的时候能否变形,没有考虑方块夹在别的方块中间的时候能不能变形等等这样的问题,所以,我将此代码大幅修改,感觉可以写点心得体会出来:

关键点:

1:关于方块的定义和地图的定义

地图其实就是二维数组,而方块也是一个大的二维数组,我见过别的写法,是把每个方块各自定义,这里的代码比较简单,就是一个二维数组,定义了所有的7种方块体。

/**
	 * 这个数组存放了所有类型的方块
	 */
	private static int blocklibary[][] = {
			{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,

			1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },// I

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

			0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,

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

			{ 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 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 },// 反7

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

			0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,

			1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },// Z

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

			1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,

			0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },// S

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

			0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,

			0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },// O

			{ 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0 } // T
	};
每个都是4*4

地图:

if (getWidth() == 240) {
			CHESSW = 10;
		} else if (getWidth() == 128) {
			CHESSW = 10;
		}
		int tempH = getHeight();
		if (tempH >= 266) {
			CHESSH = 30;
		} else {
			CHESSH = 20;
		}
		chess = new int[CHESSW][CHESSH];

根据手机屏幕的宽高进行定义,也是个二维数组。


2:旋转

俄罗斯方块最关键的逻辑就是旋转,以及之后的碰撞检测,包括变形之后是否出界(上下左右),变形之后是否会与其他方块体重合。

这里的锚点用的是左上角的第一个点:

/**
	 * 贴墙,贴别的方块,都可以转动了,如果能转的话
	 * 
	 * @return
	 */
	public boolean canTurn() {
		int i, j, next;
		int tempX = currentX;
		boolean isAlianSizeLeft = false;
		boolean isAlianSizeRight = false;
		int[][] blockNext = new int[4][4];

		next = (currentBlockDirection + 1) % blockDirection;// 准备要变化的方向
		for (int ii = 0; ii < 4; ii++) {
			for (int jj = 0; jj < 4; jj++) {
				blockNext[ii][jj] = blocklibary[currentBlockType][next * 16
						+ ii * 4 + jj];
			}
		}

		// 判断是否出界
		// 左右下
		if (currentX < 0)// 左检测
		{
			isAlianSizeLeft = true;
			for (i = 0; i < -tempX; i++) {
				// 之所以有可能是负数,是因为锚点坐标是左上角,而左上角有可能在屏幕外,比如说“竖”
				// {0,1,0,0
				// 0,1,0,0
				// 0,1,0,0
				// 0,1,0,0}
				for (j = 0; j < 4; j++) {
					if (blockNext[j][i] == 1) {// 就是说,变化之后的方块在屏幕外,那就返回false,这个写法不太智能,就是说,竖靠边就不能变化了,所以改成了下面这样
						tempX++;// 比如说T,他变成卜并且靠左的时候那就不能变了,可以先把他向右移一格,下面再去判断是不是和原有重合了
						break;
					}
				}
			}
		}
		if (currentX + 3 > (CHESSW - 1))// 右检测
		{
			isAlianSizeRight = true;
			for (i = CHESSW - currentX; i < 4; i++) {// 这个意思是有几个空的竖行,就循环几次,行
				for (j = 0; j < 4; j++) {// 列
					if (blockNext[j][i] == 1) {// 看屏幕外竖着的那些
						// 行有没有小方块,如果有,那一定是说变形之后有点在屏幕外
						tempX--;// 同样道理,先左移一格
						break;
					}
				}
			}
		}
		if (currentY + 3 > CHESSH)// 下检测
		{
			for (i = 0; i < 4; i++) {
				for (j = CHESSH - currentY; j < 4; j++) {
					if (blockNext[j][i] == 1)// 变形之后出下边界的部分有没有小方块,如果有,就不能变形了
						return false;
				}
			}
		}

		// 判断是否重合
		if (isAlianSizeLeft || isAlianSizeRight) {

			for (j = 0; j < 4; j++) {// 竖
				for (i = 0; i < 4; i++)// 横
				{
					if (blockNext[j][i] == 1
							&& chess[tempX + i][currentY + j] == 1) {
						return false;
					}
//					if (i + tempX < 0 || i + tempX > (CHESSW - 1)) {
//						// 左右贴边
//						continue;
//					}
//
//					if (j + currentY < 0 || j + currentY > CHESSH) {
//						// 上下?
//						continue;
//					}

				}
			}
		} else {
			int miniMap[][] = testShowAreaMap(tempX, currentY);
			for (j = 0; j < 4; j++) {// 竖

				for (i = 0; i < 4; i++)// 横
				{
					if (blockNext[j][i] == 1 && miniMap[j][i] == 1) {

						// System.out.println("方块重合检测");
						if (i % 4 == 0 || i % 4 == 1) {// 说明是数组的最左边那一列,也就是方块左边靠着别的方块
							tempX++;
							miniMap = testShowAreaMap(tempX, currentY);
							for (j = 0; j < 4; j++) {
								// 竖
								for (i = 0; i < 4; i++)// 横
								{
									if (blockNext[i][j] == 1// 仅仅是试验坐标平移,方块形状没变,还是可以用这个blockNext
											&& miniMap[i][j] == 1) {// 如果贴边变形后还是和别的地方重合了,就返回失败,不能变形
										return false;
									} // 要考虑变形后是不是已经出了右边界
									if (tempX + 3 > (CHESSW - 1))// 右检测
									{
										for (i = CHESSW - tempX; i < 4; i++) {
											for (j = 0; j < 4; j++) {
												if (blockNext[j][i] == 1) {
													return false;
												}
											}
										}
									}
								}
							}
						} else if (i % 4 == 3 || i % 4 == 2) {// 说明是数组的最右边那一列,也就是方块右边靠着别的方块
//							System.out.println("右边有方块");
							// int temp1 = tempX - 1;
							if (i % 4 == 3) {
								tempX -= 1;
							} else {
								tempX -= 2;
							}

							for (j = 0; j < 4; j++) {
								// 竖
								for (i = 0; i < 4; i++)// 横
								{
//									System.out.println("右边有方块,检测左边");
									if (tempX < 0) {// 左检测
										for (i = 0; i < -tempX; i++) {
											for (j = 0; j < 4; j++) {
												if (blockNext[j][i] == 1) {// 移位变形后,出界了,那就不能变
													return false;
												}
											}
										}
									} else {
										miniMap = testShowAreaMap(tempX,
												currentY);
										if (blockNext[j][i] == 1
												&& miniMap[j][i] == 1) {// 如果贴边变形后还是和别的地方重合了,就返回失败,不能变形
//											System.out.println("不能变形!");
											return false;
										}
									}
								}
							}
						}

					}
				}
			}
		}

		// System.out.println("重合检测完毕");
		currentX = tempX;
		return true;
	}

这样就可以了。

3:左右下移动

通过上面的代码其实能看出来如何判断左右边界,就不多说了。

4:界面美化和debug

由于写法简单,直接可以绘制方块,所以要立刻看到结果并不是太难,但是由此带来的问题就是如何美化界面,以及如何让debug的过程更加便利

以下是我的debug界面:


<img src="https://img-blog.csdn.net/20150625190152120?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYnl3dXU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
这样可以很好地理解锚点,地图,和其他方块键的虚实位置关系。

下图是实际运行画面:


最后放上代码,下次讲讲把这个项目移植到android的方法。

也可能研究一下AI。。。
http://download.csdn.net/detail/bywuu/8839377

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值