Android使用GridView实现俄罗斯方块(附源码)(三)

GitHub地址: https://github.com/weijifen/AndroidTetris

移动方向

移动方向包括左移,右移和下移。
移动方块实际是对position向量做改变,改变之后使用handler进行渲染:

/* 将正在下落的方块与停止下落的方块区别对待 */
for ( int i = 0; i < ySize; i++ )
{
	if ( allBlock[i] == 0 )
	{
		for ( int j = 0; j < xSize; j++ )
		{
			blockList.set( i * xSize + j, 0 );
		}
	} else {
		for ( int j = 0; j < xSize; j++ )
		{
			blockList.set( i * xSize + j, blockColor[i][j] );
		}
	}
}
for ( int i = 3; i >= 0; i-- )
{
	int line = i + position[0];
	if ( line >= 0 && StateFang.shape[rand][i] != 0 )
	{
		for ( int j = 0; j < xSize; j++ )
		{
			if ( ( (1 << j) & (leftMath( StateFang.shape[rand][i], position[1] ) ) ) != 0 )
			{
				blockList.set( line * xSize + j, randColor );
			}
		}
	}
}

这里将能否进行这些动作的判断放在改变posiotion之前判断。

左移

在判断该位置符合左移的条件就改变position数组,然后通过handler.sendEmptyMessage(1)进行渲染。
如何判断是否可以左移?

  1. 判断是否越界
  2. 判断是否重复
判断是否越界

本游戏方块的左移实际是二进制的右移,我们可以根据二进制右移的特性来做判断。
右移的时候低位移出,高位补0,左移的时候高位移出,低位补0.
所以我们可以通过先右移再左移,如果结果和原数字相同,则说明可以右移,如果和原数字不相同,则说明不可以右移。
( 1010 ) 2 (1010)_2 (1010)2右移一位为 ( 101 ) 2 (101)_2 (101)2,再左移一位为 ( 1010 ) 2 (1010)_2 (1010)2.
( 1011 ) 2 (1011)_2 (1011)2右移一位为 ( 101 ) 2 (101)_2 (101)2,再左移一位为 ( 1010 ) 2 (1010)_2 (1010)2.

判断是否与其他方块重复

如果没有越界,则通过将可以运动的方块与已经固定的方块进行按位与操作,如果结果为0,则说明没有重复,如果结果不为0,则说明有重复。

leftMove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //左移实际是数字的右移
                //左移需要判断是否能够左移
                for (int i=3;i>=0;i--) {

                    if ((((leftMath(StateFang.shape[rand][i] ,position[1])) >> 1) << 1)
                            != (leftMath(StateFang.shape[rand][i] ,position[1]))) {
//                        如果越界了
                        return;

                    }
                }
                for (int i=3;i>=0;i--) {
                    int line = i + position[0];
                    if (line >= 0 && StateFang.shape[rand][i]!=0) {
                        if ((allBlock[line] & (leftMath(StateFang.shape[rand][i], position[1]) >> 1)) != 0) {

                            return;
                        }
                    }

                }
                position[1]--;
                handler.sendEmptyMessage(1);

            }
        });
右移
判断是否越界

通过判断右移之后的二进制数组是否大于10位二进制可以表示的最大数字,如果大于,则说明右移之后越界,不可以右移,如果不大于,说明可以右移。

判断是否与其他方块重复

与左移一样。

rightMove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (int i=3;i>=0;i--) {

                    if (((leftMath(StateFang.shape[rand][i], position[1])) << 1) > 0x3ff
                            ) {
//                        如果越界了
                        return;

                    }
                }
                for (int i=3;i>=0;i--) {
                    int line = i + position[0];
                    if (line >= 0 && StateFang.shape[rand][i]!=0) {
                        if ((allBlock[line] & (leftMath(StateFang.shape[rand][i], position[1]) << 1)) != 0) {

                            return;
                        }
                    }

                }
                position[1]++;
                handler.sendEmptyMessage(1);

            }
        });

旋转设计

反L形方块表示方法如下:

{0x8, 0x8, 0xc, 0x0}

表示为二进制为:

1 0 0 0
1 0 0 0
1 1 0 0
0 0 0 0

但是方格以左边为低位更方便,所以变为:

0 0 0 1
0 0 0 1
0 0 1 1
0 0 0 0

所以这是一个形状为反L的方块。
那么方块的旋转应该如何表示?
例如反L形的逆时针旋转之后为shape[1]({0xe, 0x8, 0, 0}):

0 1 1 1
0 0 0 1
0 0 0 0
0 0 0 0

这样我们就可以定义一个数组nextShape,其下标i表示第i个方块形状,值表示旋转之后是第几个方块形状。

public static int[] nextShape = new int[] {
	1, 2, 3, 0, 5, 6, 7, 4, 9, 8, 11, 10, 13, 14, 15, 12, 17, 16, 18
};

这样需要旋转的时候我们就可以根据数组的下标的下标(shape[nextShape[i]])找到旋转之后的形状。

另外需要判断旋转之后是否越界或者与已经固定的方块重复,如果出现这些情况,那就不能旋转。
方法是先旋转,再检查。

rotateMove.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        int nextRotate = StateFang.nextShape[rand];
         for (int i=3;i>=0;i--) {
            int line = i + position[0];
//                检查是否越界
            if (leftMath(StateFang.shape[nextRotate][i] ,position[1]) > 0x3ff){
                //右边界
                return;
            }else if(StateFang.shape[nextRotate][i]>0 && line>=ySize){
                //下边界
                return;
            } else if (leftMath(leftMath(StateFang.shape[nextRotate][i], position[1]),
                    -position[1]) != StateFang.shape[nextRotate][i]) {
                return;
            }
            //检查是否与其他方块重合
            else if (line>0 && line<ySize &&
                    (leftMath(StateFang.shape[nextRotate][i], position[1]) & allBlock[line]) != 0) {
                return;
            }

        }
        rand = nextRotate;
        handler.sendEmptyMessage(1);

    }
});

值得一提的是,检查是否超越左边界的方法和检查左移的方法类似,先将方块移到指定位置,再反向移动,检查是否和原来数字相同。

下移

目标:一次下移到不能再下移的为位置。
计算运动的方块的每一行可以下移的最大距离,再找出这些最大距离里面的最小值。
如何找出运动的方块的某一行可以下移的最大距离
这一行的每一列检测是否有方块,如果有方块,则检测该列下方最近的方块(检查下一行是否有方块,再下一行是否有方块,直到边界处)。记录最大的移动量。
通过该移动量改变position数组,使用handler.sendEmptyMessage(0)渲染游戏界面。

downMove.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int down=1<<10;
                for(int i=3;i>=0;i--) {
                    int line = i + position[0];
                    if (line >= 0 && StateFang.shape[rand][i] != 0) {
                        down = Math.min(down, ySize - line - 1);
                        for (int j=0;j<xSize;j++) {
                            if (((1 << j)& (leftMath(StateFang.shape[rand][i] ,position[1])))!=0) {
                                for(int k=0;k+line<ySize;k++) {
                                    if (blockColor[k + line][j] > 0) {
                                        down = Math.min(down, k-1);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                if (down <= 0 || down==(1<<10)) {
                    return;
                } else {
                    position[0] += down;
                    handler.sendEmptyMessage(0);
                }
            }
        });

下落速度设计

该游戏可以选择下落速度。
在selectActivity中:

    @Override
    public void onClick(View v) {
        Intent intent = new Intent(SelectActivity.this, MainActivity.class);

        switch (v.getId()) {
            case R.id.grade1:
                intent.putExtra("grade", 1);
                break;
            case R.id.grade2:
                intent.putExtra("grade", 2);
                break;
            case R.id.grade3:
                intent.putExtra("grade", 3);
                break;
            case R.id.grade4:
                intent.putExtra("grade", 4);
                break;
            case R.id.grade5:
                intent.putExtra("grade", 5);
                break;
            default:
                break;
        }
        startActivity(intent);
    }

使用intent传输:

Intent intent = getIntent();
grade = intent.getIntExtra( "grade", 3 );

switch ( grade )
{
case 1:
	timeInterval = 1200;
	break;
case 2:
	timeInterval = 1000;
	break;
case 3:
	timeInterval = 800;
	break;
case 4:
	timeInterval = 600;
	break;
case 5:
	timeInterval = 400;
	break;
default:
	break;
}

该游戏使用定时器,每过一个 timeInterval 时间,自动下落一格,所以通过改变timeInterval控制下落速度。
感兴趣的朋友请继续阅读 Android使用GridView实现俄罗斯方块(附源码)(四)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值