面向对象思想实现俄罗斯方块

阅读更多



 

 今天是2015年6月18号,写博客的习惯也已经有了一年多的时间了,记得2014年初,刚开始接触

java语言那种兴奋和激动,看到面向对象设计语言如此美妙现实的作用,就暗地下给自己鼓劲一定要
把java语言学好。2014年暑假在家看了俄罗斯方块的视频,虽然线程和设计模式都不是很懂,但是还
是觉得很有感触。现在马上要大四了,也面临毕业就业的问题,看到市面上五花八门的项目,自己以
前的高中同学现在都在公司搞得有声有色,发现自己平常也有学习啊,怎么做不出来商业项目呢?现在
还是要静下心来学习巩固好以前的知识,体会编程的魅力。
   
 上面都是题外话,只是发表一下自己的感受。现在开始步入正题:
 
 步骤一:
 预期:
 俄罗斯方块都玩过,

面向对象思想实现俄罗斯方块_第1张图片
 分析:万物皆对象:
 有哪些对象

 

面向对象思想实现俄罗斯方块_第2张图片

对类的详细分析:java设计的原则,尽量在拥有数据的类里面定义好方法来操作数据。比如在黑板上画圆,要让圆来提供画圆的方法。

 

ShapeFactory.java

如何来描述六种不同的形状呢?不管是哪一种形状,都是在一个4*4的网格中。因此,我们可以用一个二维数组,用0表示4*4网格的某一个点没有被绘制,用1表示被绘制了。由于一共有六种图形是多个二维数组的组合,所以最外层是三维数组。

  private int shapes[][][]=new int [][][]{
  { {1,0,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0},//00
    {1,1,0,0,1,0,0,0, 1,0,0,0, 0,0,0,0}, // 0
    {1,1,1,0, 0,0,1,0, 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}
  },
表示一竖一横
  {
    { 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 },

	{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }
	},
  {
	  {1,1,0,0, 1,1,0,0, 0,0,0,0, 0,0,0,0}//00
表示正方形  },//                                      00 
  {
	  {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,0} //0
//                                        0 
  //                                      0
  },
  {
	  {1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},//0
	  {0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},//00
	  {0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0},//0
	  {1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0}
  },
  {
	  {1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},//0
	  {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0}
  },//00
表示树状	
  {
	  {0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},// 0
	  {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}
  }
     };

 

 

ShapeFactory生产各式各样的Shape

public Shape getShape(ShapeListener listener)
	{
		System.out.println("ShapeFactory's getShape");
		Shape shape=new Shape();
		shape.addShapeListener(listener);
		int type=new Random().nextInt(shapes.length);
		shape.setBody(shapes[type]);
		shape.setStatus(new Random().nextInt(shapes[type].length));
		return  shape;
	}

 实例化shape,添加监听器,产生6种形状里的一种。设置具体形状的状态,返回。

 

 

ShapeListener.java

package Listener;

import entities.Shape;

public interface ShapeListener {
    void shapeMoveDown(Shape shape);
    boolean isShapeMoveDownable(Shape shape);
}

 给形状设定的监听器,一个接口。类似于在android开发里有一个OnItemClickListener,表示组件的单击事件,组件比如button调用setOnItemClickListener(new OnItemClickListener()).最后调用onclick方法,

 

ShapeListener主要有ShapeMoveDown(),形状移动,isShapeMoveDownable()方法,形状能否移动(碰到障碍物了吗)。

 

这样理解:形状是一个”抽象“的,里面有具体的哪一种形状(柱状,正方形),所以用了接口。

                 组件是一个“抽象的”,具体有哪一种组件(TextView,ImageView,Button),所以也使用接口。

 

接下来就是Shape类了

Shape.java

package entities;

import java.awt.Color;
import java.awt.Graphics;

import until.Global;
import Listener.ShapeListener;

public class Shape {
         //常量,不能改变,属性共有,静态的,表示是变形还是左右下
	public static final int ROTATE=0;
	public static final int LEFT=1;
	public static final int  RIGHT=2;
	public static final int  DOWN=3;
//每一种形状又有多种摆放的方法,比如柱体可以横或竖着放
	private int[][]body;
//	private int status;
	private int left;
	private int top;

	private ShapeListener listener;
	public void moveLeft()
{
 	System.out.println("shape's moveleft");
    left--;
}
public void moveRight()
{
 	System.out.println("shape's moveright");
    left++;
}
public void moveDown()
{
 	System.out.println("shape's moveDown");
    top++;
}
public void rotate()
{
 	System.out.println("shape's rotate");
//同时状态要改变
    status=(status+1)%body.length;
//}
public void drawMe(Graphics g)
{
 	System.out.println("shape'drawme");
 	g.setColor(Color.BLUE);
 	for(int x=0;x<4;x++){
 	for(int y=0;y<4;y++){
        if(getFlagByPoint(x,y)) 	
        {
        	g.fill3DRect((left+x)*Global.CELL_SIZE, (top+y)*Global.CELL_SIZE,
        			Global.CELL_SIZE, Global.CELL_SIZE, true);
        }
 	}
 	}
 	
}
//如果在4*4网格里有,就返回为true
private boolean getFlagByPoint(int x,int y)
{
	return body[status][y*4+x]==1;
}
public boolean isMember(int x,int y,boolean rotate)
{
	int tempStatus=status;
	if(rotate){
		
		tempStatus=(status+1)%body.length;
	}
	return body[tempStatus][y*4+x]==1;
}

private class ShapeDriver implements Runnable
{
public void run()
{
	while(listener.isShapeMoveDownable(Shape.this))
	{
		moveDown();
		listener.shapeMoveDown(Shape.this);
		try{
		Thread.sleep(400);
		} catch(InterruptedException e)
		{
			e.printStackTrace();
		}
	}
}
}
public Shape(){
  new Thread(new ShapeDriver()).start();
}

public void addShapeListener( ShapeListener l){
if(l!=null)
listener=l;
}
public void setBody(int body[][])
{
	this.body=body;
}
public void setStatus(int status)
{
	this.status=status;
}
public int getTop()
{
	return top;
}
public int getLeft()
{
	return left;
}
}

 

 

考虑到Shape是动一下休息一下在动这样主键下降的,因此我们要开启线程来控制这个,动完了以后休息一下再动。最后在构造方法里(最先被调用的方法里)来开辟这个线程。

 

现在有了工厂并且生产了Shape,接下来就要关心Ground类了

Ground.java

 

package entities;

import java.awt.Graphics;

import until.Global;

public class Ground {
//长宽分别为Global.HEIGHT,Global.WIDTH的Ground,如果
//被占据,是一个障碍,则设为一
private int[][] obstacles=new int[Global.WIDTH][Global.HEIGHT];
public void accept(Shape shape)
{
	
	System.out.println("Ground's accept");
	for(int x=0;x<4;x++){
		for(int y=0;y<4;y++){
			if(shape.isMember(x, y, false)){
				obstacles[shape.getLeft()+x][shape.getTop()+y]=1;
			}
		}
	}
	deleteFullLine();
}
//一行全为1才删
private void deleteFullLine()
{
 	for(int y=Global.HEIGHT-1;y>=0;y--){
 		boolean full=true;
 		for(int x=0;x0;y--){
		for(int x=0;x=Global.HEIGHT
        			||left+x<0||left+x>=Global.WIDTH||
        			obstacles[left+x][top+y]==1
        			)
        	
        		return false;
        	}
        	
        }
	}
	return true;
	
}
public boolean isFull(){
	for(int x=0;x 
  

 

 

 

最后需要在GamePanel里面会好Ground和Shape

 

 

package view;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

import until.Global;
import entities.Ground;
import entities.Shape;

public class GamePanel extends JPanel
{
	private Ground ground;
	private Shape shape;
	//private GamePanel gamepanel;
	public void display(Ground ground,Shape shape)
	{
		System.out.println("GamePanel's display");
		this.ground=ground;
		this.shape=shape;
		this.repaint();
	}

	@Override
	protected void paintComponent(Graphics g) {
		// TODO Auto-generated method stub
		g.setColor(new Color(0xAABBEE));
		g.fillRect(0,0,Global.WIDTH*Global.CELL_SIZE,Global.HEIGHT*Global.CELL_SIZE);
		if(shape!=null&&ground!=null)
		 shape.drawMe(g);
		 ground.drawMe(g);
	}
 public GamePanel(){
     this.setSize(Global.WIDTH*Global.CELL_SIZE,Global.HEIGHT*Global.CELL_SIZE);
 }
 
}

 

最后就是逻辑处理了

按键逻辑

 

package Controller;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import Listener.ShapeListener;
import view.GamePanel;
import entities.Ground;
import entities.Shape;
import entities.ShapeFactory;

public class Controller extends KeyAdapter implements ShapeListener {
	private Shape shape;
	private ShapeFactory shapeFactory;
	private Ground ground;
	private GamePanel gamePanel;
       public void keyPressed(KeyEvent e){
           switch(e.getKeyCode()){
           case KeyEvent.VK_UP:
        	   if(ground.isMoveable(shape, Shape.ROTATE))
        	   shape.rotate();
        	   break;
           case KeyEvent.VK_DOWN:
        	   if( isShapeMoveDownable(shape))
        	   shape.moveDown();
        	   break;
           case KeyEvent.VK_LEFT:
        	   if(ground.isMoveable(shape, Shape.LEFT))
        	    shape.moveLeft();
        	   break;
           case KeyEvent.VK_RIGHT:
        	   
        	   if(ground.isMoveable(shape, Shape.RIGHT))
        		   shape.moveRight();
        	   break;
        	   }
           gamePanel.display(ground,shape);
           }
     
public void shapeMoveDown(Shape shape){
	gamePanel.display(ground,shape);
}
public synchronized boolean isShapeMoveDownable(Shape shape)
{
	if(this.shape!=shape)
		return false;
	boolean result=ground.isMoveable(shape, Shape.DOWN);
	if(result)
		return true;
	ground.accept(this.shape);
	if(!ground.isFull())
	this.shape=shapeFactory.getShape(this);
	return false;
}
public void newGame(){
	shape=shapeFactory.getShape(this);
}
public Controller( ShapeFactory shapeFactory,Ground ground,GamePanel gamePanel)
{
	this.shapeFactory=shapeFactory;
	this.ground=ground;
	this.gamePanel=gamePanel;
}
}


 

Panel逻辑

 

package Controller;

import java.awt.Color;

import javax.swing.*;

import until.Global;

public class ControlPanel extends JPanel{
public ControlPanel(){
	this.setVisible(true);
	this.setSize(2*Global.WIDTH*(Global.CELL_SIZE),Global.HEIGHT*Global.CELL_SIZE);
	this.setBackground(Color.gray);
	
}
}

 

 

 

主方法

package test;


import javax.swing.JFrame;

import Controller.ControlPanel;
import Controller.Controller;
import until.Global;
import view.GamePanel;
import entities.Ground;
import entities.ShapeFactory;

public class Game {
	public static void main(String args[])
	{
ShapeFactory shapeFactory=new ShapeFactory();
Ground ground=new Ground();
GamePanel gamePanel=new GamePanel();
ControlPanel controlpanel=new ControlPanel();
 Controller controller=new Controller(shapeFactory,ground,gamePanel);
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(2*Global.WIDTH*Global.CELL_SIZE+10 , Global.HEIGHT*Global.CELL_SIZE+35);
frame.add(gamePanel);
frame.add(controlpanel);
gamePanel.addKeyListener(controller);
frame.addKeyListener(controller);
frame.setVisible(true);
controller.newGame();
	}
}

 

工具类

package until;

public class Global {
public static final int CELL_SIZE=20;
public static final int WIDTH=15;
public static final int HEIGHT=25;
}

 

 

其实游戏开发不是很难吧,还挺有趣的,现在awt用的比较少了

 

 

  • 面向对象思想实现俄罗斯方块_第3张图片
  • 大小: 16.1 KB
  • 面向对象思想实现俄罗斯方块_第4张图片
  • 大小: 23.6 KB
  • 查看图片附件

你可能感兴趣的:(设计模式,thread,游戏,android,编程)