`

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

阅读更多



 

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

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


 分析:万物皆对象:
 有哪些对象

 

对类的详细分析: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;x<Global.WIDTH;x++){
 			if(obstacles[x][y]==0)
 				full=false;
 		}
 		if(full)
 			deleteLine(y);
 	}
}
private void deleteLine(int lineNum){
	for(int y=lineNum;y>0;y--){
		for(int x=0;x<Global.WIDTH;x++){
			obstacles[x][y]=obstacles[x][y-1];
		}
	}
	for(int x=0;x<Global.WIDTH;x++){
		obstacles[x][0]=0;
	}
}
public void drawMe(Graphics g)
{
	System.out.println("Ground's drawMe");
	for(int x=0;x<Global.WIDTH;x++){
		for(int y=0;y<Global.HEIGHT;y++){
			if(obstacles[x][y]==1){
				g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE,
					 Global.CELL_SIZE, Global.CELL_SIZE, true);
			}
		}
	}
}
public boolean isMoveable(Shape shape,int action)
{
	int left=shape.getLeft();
	int top=shape.getTop();
	switch(action){
	case Shape.LEFT:
		left--;
		break;
	case Shape.RIGHT:
	left++;
	break;
	case Shape.DOWN:
		top++;
		break;
	}
	for(int x=0;x<4;x++){
        for(int y=0;y<4;y++){
        	if(shape.isMember(x, y, action==shape.ROTATE)){
        	if(top+y>=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<Global.WIDTH;x++){
		if(obstacles[x][0]==1)
			return true;
	}
	return false;
}

}

 

 

 

最后需要在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用的比较少了

 

 

  • 大小: 16.1 KB
  • 大小: 23.6 KB
分享到:
评论

相关推荐

    俄罗斯方块面向对象版本 (JAVA版本)

    使用面向对象的思想实现了一次俄罗斯方块。有详细注释。大家一起学习一下经典吧。

    基于Java俄罗斯方块游戏的设计与开发大学毕业论文

    俄罗斯方块是一款非常经典的游戏,风靡全球,,经久不衰,是学习面向对象的编程思想的理想实例。本毕业设计论文介绍用JAVA语言设计一个“俄罗斯方块”游戏的过程,整个游戏系统是一个应用程序(Java Application),...

    Java俄罗斯方块的设计

    俄罗斯方块是一款非常经典的游戏,风靡全球,,经久不衰,是学习面向对象的编程思想的理想实例。本毕业设计论文介绍用JAVA语言设计一个“俄罗斯方块”游戏的过程,整个游戏系统是一个应用程序(Java Application),...

    这是一个使用 java 实现俄罗斯方块的小项目.rar

    java提倡的就是面向对象的思想。你最好能用面向对象的思想来设计这个游戏。 3、500行吧。这个不一定,关键看实现的思想。不用比行的多少。 4、c语言写俄罗斯方块高水平。根据查询相关资料信息显示,俄罗斯方块是一...

    VC++基于MFC的俄罗斯方块实验报告

    需求分析与概要设计 俄罗斯方块的功能需求 面向对象软件开发过程及思想 游戏具体实现

    J2ME课程设计论文 手机俄罗斯方块 面向对象程序设计

    本文给出了一个基于MIDP1.0的俄罗斯方块游戏的设计方案,并给出全部实现源代码。利用J2ME语言编程的思想来完成系统的设计,然后编写出程序设计代码进行界面设计,实现友好的界面交互,具有清晰的程序流程图,最后编程...

    C++实现俄罗斯方块

    本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下 工具:vc++2010,图库:EasyX 先看效果图片 纯手写,没有面向对象思想,看全部源码 #include #include #include #include #define ...

    俄罗斯方块游戏

    本游戏为俄罗斯方块,java版实现,并有详细代码注释,将其添加到eclipse中直接运行即可出现游戏界面,完整的学习了面向对象思想!

    基于Java 实现ME无线网络移动端的俄罗斯方块游戏的实现附项目源码+文档说明

    Java程序的编写需要遵循面向对象的编程思想,即将程序看作一组对象的集合,每个对象具有自己的属性和方法。Java程序中的对象可以通过类进行定义和创建,类是一种抽象的概念,它描述了一类具有相同属性和方法的对象。...

    C#俄罗斯方快

    一款简单的俄罗斯方块 基于C#实现的 初学者可以参考一下 有助于你理解面向对象思想

    C# 课程设计案例精编

    C# 是一种先进的、面向对象的语言,使用C# 语言可以让开发人员快速地建立大范围的基于MS网络平台的应用,并且提供大量的开发工具和服务,帮助开发人员开发基于计算和通信的各种应用。 本书精选了10个C# 开发案例,...

Global site tag (gtag.js) - Google Analytics