Android版俄罗斯方块的实现

学习Android的基本开发也有一段时间了,可是由于没有常常使用Android渐渐的也就忘记了。

Android编程学的不深,不过为了对付逆向,可是有时还是会感到力不从心的。毕竟不是一个计算机专业毕业的Coder,相对来说编程的基础对于以后非常多方面的学习都是非常重要的,特别是想在软件安全或软件的企业开发的过程中有所进步,必需要计算机专业知识扎实。

 

不多说了,发个Android版的俄罗斯方块,当然基本框架是參照之前的学的C语言版的俄罗斯方块的。俄罗斯方块程序的开发方法比較多,感觉使用数组的方法去实现还是非常方便的。以下看代码的详细实现。


俄罗斯方块界面显示代码的实现:

//俄罗斯方块界面的显示

package com.example.mytetris;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;

public class GameUI extends View
{
	public Game m_Game = null;
    private byte[][] m_Groundback = null;
    
    private Paint m_Paint = new Paint(); //画刷
    private final int PADDING = 2;   
    private int m_TetrisWidth = 0;
    
    @Override
    protected void onDraw(Canvas canvas) 
    { 
		//设置背景颜色
		setBackgroundColor(Color.BLACK);
		
		//画背景
		drawGoundback(canvas);
		
		//画方块
		int nX = m_Game.m_nX;
		int nY = m_Game.m_nY;
		
		if (m_Game.m_CurrBlock == null)
			return;
		
		byte[][] data = m_Game.m_CurrBlock;
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (data[i][j] == Game.ISWALL)	
				{
					int nLeft = nX * m_TetrisWidth  + j * m_TetrisWidth;
					int nTop = nY * m_TetrisWidth +  i * m_TetrisWidth;
					
					//外框
					m_Paint.setColor(Color.WHITE);
					canvas.drawRect(nLeft, nTop, nLeft + m_TetrisWidth, 
									nTop + m_TetrisWidth, m_Paint);
					
					//内框
					m_Paint.setColor(Color.GREEN);
					canvas.drawRect(nLeft + PADDING, nTop + PADDING, 
									nLeft + m_TetrisWidth - PADDING, nTop +m_TetrisWidth - PADDING, m_Paint);
				}
			}
		}
    }

    private void drawGoundback(Canvas canvas)
    {
    	//获取背景
		m_Groundback = m_Game.getGroundback();
		
		for (int i = 0; i < Game.NROWS; i++) 
		{
		    for (int j = 0; j < Game.NCOLS; j++) 
		    {
			if (m_Groundback[i][j] == Game.ISWALL)
				{
				    //画白色的方块--外框
				    m_Paint.setColor(Color.WHITE);
				    canvas.drawRect(j*m_TetrisWidth, i*m_TetrisWidth, 
					    	   (j+1)*m_TetrisWidth, (i+1)*m_TetrisWidth, m_Paint);
				    
				    //画绿色的方块--内框
				    m_Paint.setColor(Color.GREEN);
				    canvas.drawRect(j*m_TetrisWidth + PADDING, i*m_TetrisWidth + PADDING,
					           (j+1)*m_TetrisWidth - PADDING, (i+1)*m_TetrisWidth - PADDING, m_Paint);
				}
		    }
		}
    }
    
    public GameUI(Context context, AttributeSet attrs, int defStyleAttr)
    {
    	super(context, attrs, defStyleAttr);
    	
    }
    
    //自己定义view组件。构造调用该函数
    public GameUI(Context context, AttributeSet attrs)
    {
    	super(context, attrs);
    	
    	//创建Game
    	m_Game = new Game();
    	
    	//获取手机分辨率
    	WindowManager wmgr = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		wmgr.getDefaultDisplay().getMetrics(outMetrics);
		//手机屏幕宽度
		int nTetrisWidth = outMetrics.widthPixels;
    	
    	//依据手机分辨率。设置方块宽度
    	m_TetrisWidth = nTetrisWidth/Game.NCOLS*3/4;
    	
    }
    
    public GameUI(Context context)
    {
    	super(context);
    	
    }

}


俄罗斯方块详细的逻辑的实现:

package com.example.mytetris;

import java.util.Arrays;
import java.util.Random;

import android.R.integer;

public class Game 
{
	public static final byte ISWALL = 1; //墙
	public static final int NROWS = 20;  //18行
	public static final int NCOLS = 12;  //12列
	public byte[][] m_Groundback = null;
	
	public int m_nX = 0;   //方块x坐标
	public int m_nY = 0;   //方块y坐标
	private Random m_Random = new Random(); //产生随机对象
	
	private byte[][][] m_Tetris = null;  //方块的各种变化
	public byte[][] m_CurrBlock = new  byte[4][4]; //当前方块
	private byte[][] m_NextBlock = new  byte[4][4]; //下一个方块
	
	public Game()
	{
		m_Groundback = new byte[NROWS][NCOLS];	
		
		initGroundback();
		initTetris();
	}
	
	//初始化背景
	public void initGroundback()
	{
		for (int i = 0; i < NROWS; i++)
		{
			for (int j = 0; j < NCOLS; j++)
			{
				if (i == NROWS - 1 || j == 0 || j == NCOLS - 1)
				{
				    //设置墙
				    m_Groundback[i][j] = ISWALL;
				}
			}
		}
	}
	
	//初始化变换方块的类型
	public void initTetris()
	{
		//这样的初始化不能给维数
	    m_Tetris = new byte [][][]
		{
	    	/*1*/
			{
				{1, 1, 1, 1},
				{0, 0, 0, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*2*/
			{
				{1, 0, 0, 0},
				{1, 0, 0, 0}, 
				{1, 0, 0, 0},
				{1, 0, 0, 0}
			},
			
			/*3*/
			{
				{1, 0, 0, 0},
				{1, 1, 0, 0}, 
				{0, 1, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*4*/
			{
				{0, 1, 0, 0},
				{1, 1, 0, 0}, 
				{1, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*5*/
			{
				{1, 1, 0, 0},
				{0, 1, 1, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*6*/
			{
				{0, 1, 1, 0},
				{1, 1, 0, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*7*/
			{
				{0, 1, 0, 0},
				{1, 1, 1, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*8*/
			{
				{1, 1, 1, 0},
				{0, 1, 0, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*9*/
			{
				{1, 0, 0, 0},
				{1, 1, 0, 0}, 
				{1, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*10*/
			{
				{0, 1, 0, 0},
				{1, 1, 0, 0}, 
				{0, 1, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*11*/
			{
				{1, 1, 0, 0},
				{0, 1, 0, 0}, 
				{0, 1, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*12*/
			{
				{1, 1, 0, 0},
				{1, 0, 0, 0}, 
				{1, 0, 0, 0},
				{0, 0, 0, 0}
			},
	    		
			/*13*/
			{
				{1, 0, 0, 0},
				{1, 1, 1, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
			
			/*14*/
			{
				{1, 1, 1, 0},
				{0, 0, 1, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
	    		
			/*15*/
			{
				{1, 1, 0, 0},
				{1, 1, 0, 0}, 
				{0, 0, 0, 0},
				{0, 0, 0, 0}
			},
	    };
	    
	}
	
	//获取背景
	public byte[][] getGroundback()
	{
	    return m_Groundback;
	}

	//開始游戏
	public void startGame()
	{
		m_nX = NCOLS / 2 - 2;
		m_nY = 0;

		// 产生方块
		m_CurrBlock = RandomBlock();
		m_NextBlock = RandomBlock();
	}
	
	//结束游戏
	public void stopGame()
	{
	    
	}
	
	//左移
	public void moveLeft()
	{
		if (IsCanMove(m_nX - 1, m_nY))
		{
			m_nX--;
		}
	}
	
	//右移
	public void moveRight()
	{
		if (IsCanMove(m_nX + 1, m_nY))
		{
			m_nX++;
		}
	}
	
	//方块变换时,变换方块--这个产生的问题还没解决?

public byte[][] getNextBlock() { //产生一个随机数 int nLen = m_Tetris.length; //右移高位补0--去掉符号位 int nIndex = (m_Random.nextInt() >>> 1) % nLen; return m_Tetris[(nIndex+2)%15]; } //变换 public void moveChange() { byte[][] oldBlock = m_CurrBlock; m_CurrBlock = getNextBlock(); if (!IsCanMove(m_nX, m_nY)) { m_CurrBlock = oldBlock; } } //下移 public void moveDown() { if (IsCanMove(m_nX, m_nY + 1)) { m_nY++; } else { Fixbircks(); } } //随机产生方块 public byte[][] RandomBlock() { //产生一个随机数 int nLen = m_Tetris.length; //右移高位补0--去掉符号位 int nIndex = (m_Random.nextInt() >>> 1) % nLen; return m_Tetris[nIndex]; } //产生方块 private void CreateBircks() { m_nX = NCOLS / 2 - 2; m_nY = 0; // 产生方块 m_CurrBlock = m_NextBlock; m_NextBlock = RandomBlock(); } //下移究竟 public void MoveFix() { while (IsCanMove(m_nX, m_nY + 1)) { m_nY++; } Fixbircks(); } //推断方块是否能移动 private boolean IsCanMove(int x, int y) { byte[][] data = m_CurrBlock; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (data[i][j] == ISWALL && m_Groundback[y + i][x + j] == ISWALL) { return false; } } } return true; } //固定方块 private void Fixbircks() { byte[][] data = m_CurrBlock; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { //填充背景 if (data[i][j] == ISWALL) { m_Groundback[m_nY + i][m_nX + j] = ISWALL; } } } int nRows = ReleaseRows(); //产生新方块 CreateBircks(); //新方块不能移动,结束游戏 } //消除方块 private int ReleaseRows() { int nReleaseRows = 0; for (int nRow = NROWS - 2; nRow > 0; nRow--) { if (IsCanRelease(nRow)) { //消除方块 nReleaseRows++; //调整方块--下移 MoveRows(nRow); //又一次推断本行是否能够消行 nRow++; } } return nReleaseRows; } //是否能消除方块 private boolean IsCanRelease(int nRow) { for (int nCol = 1; nCol < NCOLS - 1; nCol++) { if (m_Groundback[nRow][nCol] == 0) { return false; } } return true; } //消除方块以后,下移方块 private void MoveRows(int nRow) { for (int i = nRow; i > 0; i--) { for (int j = 1; j < NCOLS - 1; j++) { m_Groundback[i][j] = m_Groundback[i - 1][j]; } } } }


俄罗斯方块主体的控制流程的代码实现:


package com.example.mytetris;

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


import android.media.MediaPlayer;
import android.os.Bundle;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener
{
	private GameUI m_GameUi = null;
	private Game   m_Game   = null;
	
	private Button btnLeft = null;
	private Button btnRight = null;
	private Button btnDown = null;
	private Button btnChange = null;
	
	private MediaPlayer mp2 = null;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		//设置全屏无标题显示
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				     WindowManager.LayoutParams.FLAG_FULLSCREEN);
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.linearlayout);
		
		//获取组件
		m_GameUi = (GameUI)findViewById(R.id.GameUI);
		m_Game   = m_GameUi.m_Game;
		
		btnLeft = (Button)findViewById(R.id.button1_left);
		btnRight = (Button)findViewById(R.id.button2_right);
		btnDown = (Button)findViewById(R.id.button3_down);
		btnChange = (Button)findViewById(R.id.button4_change);
		
		//设置监听
		btnLeft.setOnClickListener(this);
		btnRight.setOnClickListener(this);
		btnDown.setOnClickListener(this);
		btnChange.setOnClickListener(this);
		
		//
		mp2 = MediaPlayer.create(this, R.raw.action);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
	{
		getMenuInflater().inflate(R.menu.gamemenu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		int nIndex = item.getItemId();
		switch (nIndex) 
		{
		case R.id.item1_startgame:
			{
				//開始游戏
				m_Game.startGame();
				m_GameUi.invalidate();
				
				//播放音效
				MediaPlayer mp = MediaPlayer.create(this, R.raw.ready_go);
				mp.start();
				//mp.release();
				
				//定时器
				new Timer().schedule(new TimerTask()
				{
					@Override
					public void run() 
					{
						m_GameUi.m_Game.moveDown();
						m_GameUi.invalidate();
						
						mp2.start();
					}
				}, 0, 2000);
				
				//线程
//				new Thread(new Runnable()
//				{
//					@Override
//					public void run()
//					{
//						try
//						{
//							Thread.sleep(1000);
//						} 
//						catch (InterruptedException e)
//						{
//							e.printStackTrace();
//						}
//						
//						m_GameUi.m_Game.moveDown();
//						m_GameUi.invalidate();
//						
//					}
//				}).start();
				
			}
			break;
		case R.id.item2_restartgame:
			{
				
			}
			break;
		case R.id.item3_stopgame:
		{
			
		}
		break;
		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}
	@Override
	public void onClick(View v) 
	{
		int nId = v.getId();
		switch (nId)
		{
		case R.id.button1_left:
			{
				m_Game.moveLeft();
			}
			break;
		case R.id.button2_right:
			{
				m_Game.moveRight();
			}
			break;
		case R.id.button3_down:
			{
				m_Game.MoveFix();
			}
			break;
		case R.id.button4_change:
			{
				m_Game.moveChange();
			}
			break;
		default:
			break;
		}
		
		//重绘
		m_GameUi.invalidate();
	}

}



执行效果图,界面做的比較挫:






Android俄罗斯方块的代码实现还不全,有兴趣的Coder能够完好一下。网上Android版俄罗斯方块代码到处都是,可是我认为这份代码给出了俄罗斯方块编写的基本框架,依照这个框架。能够写出非常多语言版本号的俄罗斯方块。



代码下载地址:http://download.csdn.net/detail/qq1084283172/9037683



posted @ 2017-08-05 10:51  yxysuanfa  阅读(947)  评论(0编辑  收藏  举报