1.适配两种分辨率
俄罗斯方块游戏要适配两种分辨率,分别是320480和480800,这是目前主流的分辨率尺寸,尤其是后者。我们将游戏区域分为左右两个部分。左边是游戏区域,方块的移动限制在此区域内;右边是信息显示区域,显示下一个即将落下的方块、得分和游戏状态,如图9-4所示。在本例中,游戏运行区域分为10列,但是行数则在运行时计算获得。每一个小的单元格正好是方块的宽度。方块在移动过程中,需要检测是否与边界碰撞,如果碰撞则不能继续向此方向运动。
图9-4 游戏区域设计图
如果需要适应上述两种分辨率,那么确定砖块的宽度和游戏运行区域的行数是关键。对于砖块的宽度,我们为两种分辨率分别设定为16像素和25像素。这样根据已知的砖块宽度就可以计算得到游戏区域的行数了。这些工作在Screen的构造器中完成,代码如下所示:
public Screen(Context context) {
super(context);
if (bWidth == 0) {
DisplayMetrics dm = new DisplayMetrics();
((WindowManager) getContext().getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(dm);
if (dm.widthPixels == 320) {
bWidth = 16;
} else if (dm.widthPixels == 480) {
bWidth = 25;
}
ROW = dm.heightPixels/bWidth;
bricks = new int[ROW][COL];
copy = new int[ROW][COL];
}
reset();
}
2.Screen初始化
Screen类扩展了View,实现了渲染整个游戏区域的功能。创建Screen对象时,需要完成如下的初始化工作:
确定游戏运行区域的边界mLeft、mTop、mBottom和right。
初始化下一个方块next,并设置其左上角坐标。
初始化当前运行的方块current,并设置其左上角坐标。
初始化方块运行区域的数组bricks。
设置当前屏幕的背景图片。
游戏的初始化工作在Screen类的reset()方法中完成,这个方法在Screen对象创建,以及游戏结束后会被调用。reset()方法的代码如下所示:
// 初始化游戏数据
private void reset() {
// 计算方块运行区域的边界
mLeft = 0;
mTop = 0;
mBottom = mTop + ROW * bWidth;
right = bWidth * COL + mLeft;
// 初始化下一个方块
next = new Brick(this);
next.setShape(Shape.random());
next.left = right + BORDER;
next.top = mTop;
// 初始化当前方块
current = new Brick(this);
current.setShape(Shape.random());
current.left = 3 * bWidth + mLeft;
current.top = mTop;
int mt = current.getShape().marginTop();
current.top -= mt * bWidth;
// 初始化方块运行区域的数组
initializeBricks();
state = READY;
thread = null;
this.score = 0;
// 设置屏幕背景图片
setBackgroundResource(R.drawable.sea);
}
private void initializeBricks() {
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
bricks[i][j] = 0;
}
}
}
3.游戏区域渲染
Screen类的渲染工作在onDraw()方法中实现,包括绘制当前正在运行的方块、已经落下的方块、下一个方块、得分和游戏运行状态等信息。onDraw()方法的实现如下所示,请参考注释阅读。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.CYAN);
paint.setColor(Color.BLACK);
// 绘制左右游戏区域分割线
canvas.drawLine(right, mTop, right, mTop + getHeight(), paint);
if (next != null) {
// 画下一个砖块
next.draw(canvas);
}
int color = paint.getColor();
int m_left = next.left;
int m_top = next.top + bWidth * 6;
paint.setColor(Color.parseColor("#FFFFFF"));
paint.setTextSize(20);
// 画得分
canvas.drawText(score + "", m_left, m_top, paint);
int s_left = next.left;
int s_top = m_top + bWidth * 2;
// 画游戏砖块,暂停,游戏中...
canvas.drawText(getStateText(state), s_left, s_top, paint);
if (current != null)
// 画当前的砖块
current.draw(canvas);
paint.setColor(color);
color = paint.getColor();
// 画屏幕上的砖块
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
if (bricks[i][j] == 1) {
int r = i;
int c = j;
int l = c * bWidth;
int t = r * bWidth;
paint.setColor(Color.parseColor("#f7faf3"));
canvas.drawRect(l, t, l + bWidth, t + bWidth,
paint);
paint.setColor(Color.parseColor("#4c8e0b"));
canvas.drawRect(l + 1, t + 1, l + bWidth - 1, t
+ bWidth - 1, paint);
}
}
}
paint.setColor(color);
}