`
zhengjj_2009
  • 浏览: 154129 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android 游戏:俄罗斯方块的小结和开发过程

 
阅读更多

       最近觉得在android上开发游戏是一件很有趣的事情,所以查找了一些资料,自己做出了一个简单俄罗斯方块游戏,现将其总结如下:

1、基础数据模型

     一个俄罗斯方块都是以一个4*4的二维数组来存储的,在我的demo游戏中,一共有7种方块类型: I S Z J O L  T七种类型。见下图:

 

每种类型都有四种旋转状态, 如何在一个4*4的二位数组表示呢?可以用0和1来表示,1表示该小单元格需要显示,0表示该小单元格不需要显示。
设置屏幕为320*480,每个小单元格是20像素,这样宽就是COLS=16,高就是ROWS=24。

 

2、涉及到的几个JavaBean

2.1   Shape:把每种图形抽象出来为一个对象,具有的属性是

         int的 left(x方向)和top(y方向)、

         int的 status 旋转状态,可选择的值是0,1,2,3   默认是0

         int[][] body 存储四种旋转状态的数据

         int LEFT = 1, RIGHT = 2, DOWN = 3, ROTATE = 4

       

        Shape具有的方法是moveLeft()    moveRight()   moveDown()和rotate()四种基本方法,对应模拟器上的四个方向键。如果模拟器的方向键不能使用,自己在百度或google上看看是怎么解决的,这里不记录。

       同时Shape还应该具有drawMe()画出值为1的单元格、checkBound()检查是否出了边界 和 checkValue(x, y)检查对应的小单元格的值是否为1或0,  1显示0不显示。

 

2.2 Ground:地面类 就是各个小单元格堆放起来的那个地面,我们也把它抽象成为一个JavaBean,经过分析,它也应该具有如下的属性和方法。

        int[][] body  这个body就是面板的最大面积COLS * ROWS =16*24

        它应该有一个drawMe()的方法,显示他目前已经接纳且未消行的小单元格,另外它应该有消行和统计分数的方法removeRows(),检查某个小单元格是否为1的方法checkValue(),接纳Shape的方法addShape()。

 

2.3 定义一个GameView,用来显示Shape和Ground的图形变化,需要重写的方法有

     onDraw():主要是画Shape和Ground

     onKeyDown():处理方向键按下的事件

     在它的构造函数里面需要实现小单元格的静态资源的获取,

     调用setFocusable(true);  以显示图形

     在正式运行时需要执行定时器,以3秒钟不停刷新页面的数据。

 

2.4 MainActivity  将系统的标题栏去掉,调用

    //以下去掉标题和全屏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
          WindowManager.LayoutParams.FLAG_FULLSCREEN);

   然后调用GameView。

 

===================================================================

按照以上的步骤,我开始逐步编程

 1、ShapeFactory的代码

  

import java.util.Random;

public class ShapeFactory {
	public static Shape getShape(){
		Shape shape = new Shape();
		int type = new Random().nextInt(shapes.length);
		shape.setBody(shapes[type]);
		shape.setStatus(0);
		return shape;
	}
	
	// 方块的形状 第一组代表方块类型有S、Z、L、J、I、O、T 7种
	// 第二组为图型的型状态
	//每三组图型数据,根据这些数来描绘在view中
	private final static int shapes[][][] = new int[][][] {
	   // i
	   { { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
	     { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
	     { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
	     { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },
	   // s
	   { { 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 } },
	   // z
	   { { 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 } },
	   // J
	   { { 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, 0 },
	     { 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
	   // o(田字)
	   { { 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, 0 } },
	   // l(竖右勾)
	   { { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 },
	     { 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	     { 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
	     { 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
	   // T
	   { { 0, 1, 0, 0, 1, 1, 1, 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 },
	     { 1, 1, 1, 0, 0, 1, 0, 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 } } };
}

配置文件

public class Config {
	public static final int CELL_SIZE = 20;
	//320*480  宽 *高
	public static final int ROWS = 24;//行--高
	public static final int COLS = 16;//列 --宽
}

 

 

2、Shape的代码

 

import android.graphics.Canvas;
import android.graphics.drawable.Drawable;

public class Shape {
	private int left;
	private int top;
	private int[][] body;
	
	private int status;
	public static final int LEFT = 1, RIGHT = 2, DOWN = 3, ROTATE = 4;
	
	public void moveLeft(){
		left--;
	}	
	public void moveRight(){
		left++;
	}
	//move down
	//must controller multiple thread(1-refresh schedule, 2-event) 
	public synchronized void moveDown(Ground ground) {   
		if (checkBound(Shape.DOWN, ground))    
			top ++;  
	}
	
	//旋转其实就是转到下一个图形中,通过改变status的值即可
	public void rotate(){
		status = (status+1)%body.length;
	}
	
	/**绘制Shape需要传入画布Canvas和图片资源**/
	public void drawMe(Canvas canvas, Drawable d){
		for(int x=0; x<4; x++){
			for(int y=0; y<4; y++){
				if(checkValue(x,y)){//如果单元格的值不为0则为1,需要绘制单元格
					//绘制之前需要先设置边界,设置边界有两种方法,这里选择四个参数的
					//这四个参数需要计算出其绝对坐标值
					int tempx = (x+left)*Config.CELL_SIZE;
					int tempy = (y+top)*Config.CELL_SIZE;
					int right = tempx+Config.CELL_SIZE;
					int bottom = tempy+Config.CELL_SIZE;
					d.setBounds(tempx, tempy, right, bottom);
					d.draw(canvas);
				}
			}
		}
		
	}
	
	//检查Shape是否到达边界,这里需要考虑向左 向右和向下三种情况
	public boolean checkBound(int action, Ground ground){
		int temptop = top;
		int templeft = left;
		switch(action){
		case LEFT:
			templeft--;
			break;
		case RIGHT:
			templeft++;
			break;
		case DOWN:
			temptop++;
			break;
		case ROTATE:
			break;
		}
		for(int x=0; x<4; x++){
			for(int y=0; y<4; y++){
				if(checkValue(x,y)){//如果单元格的值为1,需要判断它是否到达边界					
					if(templeft<0 || templeft >Config.COLS //X方向的边界判断
							|| temptop > Config.ROWS //Y方向的边界判断
							|| ground.checkValue(templeft,temptop,x,y) ){
						return false;
					}//end if					
				}
			}
		}//end for
		return true;		
	}
	
	//判断x,y点的值是否为1,1返回true 0返回false
	public boolean checkValue(int x, int y){
		return body[status][4*y+x]==1;		
	}	
	public int[][] getBody() {
		return body;
	}
	public void setBody(int[][] body) {
		this.body = body;
	}
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}

 

3、 Ground的代码

import android.graphics.Canvas;
import android.graphics.drawable.Drawable;

public class Ground {

	public boolean checkValue(int left, int top, int x, int y) {
		if (body[left + x][top + y] == 1) {
		  return true;
	    }
	    return false;
	}
	
   public int[][] body = new int[Config.COLS][Config.ROWS];
	
	public void drawMe(Canvas canvas, Drawable d) {
		for (int x = 0; x < Config.COLS; x++) {//列 --> X方向
			for (int y = 0; y < Config.ROWS; y++) {//行--> Y方向
				if (body[x][y] == 1) {
					int tempX = x * Config.CELL_SIZE;
					int tempY = y * Config.CELL_SIZE;
		            int right = tempX + Config.CELL_SIZE;
		            int bottom = tempY + Config.CELL_SIZE;
		            d.setBounds(tempX, tempY, right, bottom);
		            d.draw(canvas);
		        }
		   }
	    }
   }
	
	/**
	 * remember drawed block 
	 * @param type  block type(seven type)  
	 * @param status block status
	 * @param left   x coordinate 
	 * @param top   y coordinate
	 */
	 public void add(int left, int top, Shape shape) {
		 for (int x = 0; x < 4; x++) {
			 for (int y = 0; y < 4; y++) {
				 if (shape.checkValue(x, y)){
					 try{
						 body[left + x][top + y] = 1;  
					 } catch(Exception e) {
						 e.printStackTrace();
					 }//end try-catch
				 }//end if
			 }//end for loop
		 }//end for loop
	}
	 
	 /**
     * remove rows 当所堆积的小框框满一行时,就要进行消行。
     * 消行的逻辑是:以Y方向为基准,从最底下一行的开始检查,当某一行全部满格时,则进行消行
     * 消行其实就是把上一行的数据填充到下一行的位置上,以此进行循环操作
     */
	public void removeRow() {//消掉多少行
		int c = 0;
	    int removeRows = 0;//counter 
	    for (int y = Config.ROWS - 1; y > 0; y--) {//y coordinate
	    	for (int x = 0; x < Config.COLS; x++) {//x coordinate
	    		if (body[x][y] == 1){
	    			c++;
		            if (c == Config.COLS) {//should remove the row
		            	removeRows++;
		            	for (int j = y; j > 0; j--) {//reset all block in body y coordinate
		            		for (int z = 0; z < Config.COLS; z++) {//x coordinate
		            			body[z][j] = body[z][j - 1];
		            		}//end for loop
		            	}//end for loop
		            	y++;//because the row has fall down one row.
		            }//end if
	    		}//end if
	    	}//end for
	    	c = 0;
	    }//end for
	    countScore(removeRows);
	}
	   
	/**
	 * count score统计分数
	 * @param removeRows
	 */
	public void countScore(int removeRows) {
	}
}

 

4、GameView

import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.KeyEvent;
import android.view.View;

public class GameView extends View {

	private Shape shape;
	private Drawable d;
	Ground ground = new Ground();
	public GameView(Context context) {
		super(context);
		d = context.getResources().getDrawable(R.drawable.brick);
		shape = ShapeFactory.getShape();
		//new Thread(this).start();
		setFocusable(true);
		schedule();
	}

	/**
	* onDraw()方法只会在初始化后被调用一次,或者在使用postInvalidate()的时候会被调用
	*/
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		shape.drawMe(canvas, d);
		ground.drawMe(canvas, d);
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {   
			case KeyEvent.KEYCODE_DPAD_UP:    
				shape.rotate();    
				break;  
			case KeyEvent.KEYCODE_DPAD_DOWN:   
				if(shape.checkBound(Shape.DOWN, ground))
					shape.moveDown(ground);   				  
				break;   
			case KeyEvent.KEYCODE_DPAD_LEFT:  
				if(shape.checkBound(Shape.LEFT,ground))
					shape.moveLeft();    
				break;   
			case KeyEvent.KEYCODE_DPAD_RIGHT:   
				if(shape.checkBound(Shape.RIGHT, ground))
					shape.moveRight();    
				break;   
			default:    
				break;   
		}    
		return super.onKeyDown(keyCode, event);  
	}
	
	private void schedule(){
		 Timer nT1 = new Timer();
		 nT1.schedule(new TimerTask(){ //计划运行时间间隔
			 public void run(){
				 refresh(); //过3秒调用一下refresh()
	         }
	     },0,500);
	}
	
	 public void refresh(){   
		 //auto down   
		 if (shape.checkBound(Shape.DOWN, ground)){    
			 shape.moveDown(ground);    
			 this.postInvalidate(); //使用postInvalidate();刷新   
		 } else{//generator new block        
			 ground.add(shape.left, shape.top, shape);        
			 ground.removeRow();        
			 shape = ShapeFactory.getShape();   
		 }      
	}
	 
	/*@Override
	public void run() {
		while(true){
			if(shape.checkBound(Shape.DOWN))
				shape.moveDown();
			postInvalidate();
			try {
				Thread.sleep(500);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}*/
}

 6、MainActivity

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//setContentView(R.layout.activity_main);
		
      //以下去掉标题和全屏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
          WindowManager.LayoutParams.FLAG_FULLSCREEN);
        GameView gameView = new GameView(this);
        setContentView(gameView);
	}

}

  

 

 

6、

  • 大小: 5.5 KB
分享到:
评论

相关推荐

    Android 俄罗斯方块游戏源码

    本篇文章将详细解析一个简单的Android俄罗斯方块游戏的源码,帮助你理解游戏的核心机制、Android游戏开发的基本原理以及如何在Android环境中运行游戏。 一、Android游戏开发基础 Android游戏开发基于Android SDK,...

    基于Android平台的俄罗斯方块--毕业设计说明书

    ### 基于Android平台的俄罗斯方块毕业设计说明知识点 #### 1. Android平台介绍 - **平台背景概述**:Android是由Google公司发起的、基于Linux内核的开源操作系统项目,旨在为移动设备提供一个完整且开放的操作系统...

    android做的俄罗斯方块

    总结,开发Android版的俄罗斯方块游戏,不仅需要掌握Android的基本框架和组件,还要理解游戏逻辑和动画原理。通过这个项目,开发者可以深入学习Android开发,锻炼解决问题和优化代码的能力,为后续更复杂的项目打下...

    Android俄罗斯方块游戏代码

    总结,开发Android版的俄罗斯方块游戏,涉及到了Android应用的基础架构、图形绘制、事件处理、动画效果等多个方面,是学习Android开发的绝佳实践项目。通过这个游戏,开发者不仅能掌握Android开发的基本技巧,还能...

    android平台俄罗斯方块游戏完整代码

    通过分析这个简单的俄罗斯方块游戏源代码,我们可以了解到Android应用程序的基本结构和开发流程。从方块状态管理到图像资源加载,再到音效和背景音乐的播放,每个环节都体现了Android开发的关键技术点。对于初学者来...

    android实验设计 俄罗斯方块完整版

    ### 关于Android实验设计——俄罗斯方块完整版的知识点总结 #### 一、设计目标与技术背景 在《Java程序设计》课程框架下,学生被要求设计并实现一款基于Android平台的“俄罗斯方块”游戏。此项目不仅旨在加深学生...

    android版俄罗斯方块

    总结,开发Android版俄罗斯方块需要理解游戏的基本机制,掌握Android开发技术,设计用户友好的界面,同时关注性能优化和错误处理。虽然描述中提到存在一些问题,但通过不断调试和改进,我们可以将这些问题转化为提升...

    Android 俄罗斯方块

    总结,Android版俄罗斯方块的开发涵盖了Android基础、图形绘制、游戏逻辑、事件处理、音效动画等多个方面,通过这个项目,开发者不仅能掌握Android开发的基本技能,也能锻炼到游戏开发的思维和实践能力。

    基于Android的俄罗斯方块的设计与实现完整版样本.doc

    "基于Android的俄罗斯方块的设计与实现完整版样本" 基于Android的俄罗斯方块游戏设计和实现需要结合Android操作系统的特点和俄罗斯方块游戏的规则来进行设计和实现。下面是相关的知识点: 一、Android操作系统概述...

    基于Android平台的手机俄罗斯方块分析设计

    总结,基于Android平台的手机俄罗斯方块游戏设计涵盖了移动应用开发的多个方面,包括图形界面设计、事件处理、游戏逻辑算法等,是Android开发初学者和爱好者理想的实践项目。通过这个项目,开发者不仅可以学习到...

    俄罗斯方块cocos2d-x_10831

    在cocos2d-x中实现“俄罗斯方块”,首要任务是创建游戏场景和游戏对象。我们可以使用cocos2d-x的精灵(Sprite)类来表示方块,每个单元块可以是一个单独的精灵。然后,我们需要一个游戏板(Grid)类来管理屏幕上的...

    android俄罗斯方块源码

    总结,这款Android版俄罗斯方块源码是学习Android游戏开发的好材料。通过研究源码,我们可以了解到游戏逻辑的实现、用户交互的设计、图形绘制的方法以及如何进行性能优化。这对于提升Android开发技能,特别是游戏...

    android俄罗斯方块

    总结,开发Android版的俄罗斯方块游戏是一个综合性的实践过程,涉及到Android基础、图形绘制、事件处理、性能优化等多个方面。通过这个项目,开发者不仅可以掌握Android应用开发技能,还能对游戏编程有更深入的理解...

    俄罗斯方块H5源码.zip

    总结来说,俄罗斯方块H5版利用Layabox引擎和TypeScript语言,实现了全平台适配和丰富的用户交互。通过对游戏逻辑的深入理解和源码的详细分析,开发者可以学习到如何构建一个跨平台的H5游戏,同时掌握到TypeScript在...

    cocos2d-x 游戏俄罗斯方块

    《cocos2d-x 游戏开发:打造经典俄罗斯方块》 在游戏开发领域,cocos2d-x 是一款广泛使用的开源游戏引擎,尤其适合2D游戏的开发。本项目是一个基于cocos2d-x 2.2.6版本实现的俄罗斯方块游戏,展现了cocos2d-x 引擎...

    俄罗斯方块 课程设计文档

    本文档主要讨论的是一个计算机科学与工程学院的课程设计项目——“俄罗斯方块”游戏的开发。该项目旨在利用VC++编程...通过完成这个项目,学生将能够深入理解游戏开发中的图形渲染、事件处理和游戏逻辑控制等关键概念。

    Qt跨平台编程——俄罗斯方块游戏的开发 毕业论文

    【Qt跨平台编程——俄罗斯方块游戏的开发】 这篇毕业论文的主题聚焦于使用Qt框架进行跨平台编程,以实现一款经典的俄罗斯方块游戏。Qt是一个强大的C++库,提供了丰富的功能,尤其在图形用户界面(GUI)开发方面,...

    android 俄罗斯方块

    总结,开发Android版的俄罗斯方块游戏,不仅有助于新手熟悉Android开发环境,也能深入理解游戏逻辑和图形处理。通过实践这个项目,开发者将能掌握从基础到进阶的Android编程技巧,并为未来更复杂的游戏开发打下坚实...

    unity-3D俄罗斯方块JS版

    总结,"unity-3D俄罗斯方块JS版"项目结合了Unity 3D的游戏开发能力与JavaScript的编程特性,展示了如何将经典游戏移植到3D环境中。通过学习和理解这个项目,开发者不仅可以掌握Unity的基础,还能深入了解3D游戏开发...

Global site tag (gtag.js) - Google Analytics