`

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

阅读更多



 

 今天是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
分享到:
评论

相关推荐

    使用面向对象设计的俄罗斯方块源码

    在"使用面向对象设计的俄罗斯方块源码"中,我们可以深入理解如何运用OOP原则来构建一个经典的游戏。 首先,我们来探讨OOP的基本概念: 1. 类(Class):类是对象的模板,定义了对象的属性(数据成员)和行为(成员...

    用C#中的面向对象的思想开发的俄罗斯方块

    《C#面向对象思想开发俄罗斯方块》 在软件开发领域,C#是一种广泛使用的编程语言,尤其在Windows平台上的应用程序开发中。本项目利用C#的面向对象编程(Object-Oriented Programming, OOP)特性,实现了经典游戏...

    面向对象俄罗斯方块

    在这个“面向对象俄罗斯方块”项目中,我们可以深入探讨如何使用面向对象技术来实现经典游戏俄罗斯方块。 1. **类定义**: 在面向对象编程中,我们首先需要定义类,这是构建对象的基础。对于俄罗斯方块,可能有...

    C#面向对象编程俄罗斯方块(代码较简)

    本项目以经典游戏“俄罗斯方块”为例,展示了如何运用面向对象编程思想来实现游戏逻辑。 首先,我们要理解面向对象编程的基本概念。类是OOP中的蓝图,用于定义具有相似属性和行为的对象。在“俄罗斯方块”游戏中,...

    采用c++面向对象的思想开发俄罗斯方块

    《采用C++面向对象的思想开发俄罗斯方块》 在C++编程中,面向对象的思想是一种强大的工具,尤其在开发复杂游戏如俄罗斯方块时。本文将深入探讨如何利用C++的面向对象特性来构建俄罗斯方块游戏,并分享相关源码供...

    BORLAND C++编写的面向对象的俄罗斯方块程序

    《BORLAND C++实现的面向对象俄罗斯方块程序解析》 在编程的世界里,经典游戏总是能成为学习新技术的绝佳示例。其中,俄罗斯方块以其简洁的规则和丰富的策略性,深受程序员们的喜爱,被广泛用于教学和实践。本文将...

    js版俄罗斯方块设计思想及实现

    总之,用JavaScript实现俄罗斯方块是一个很好的学习项目,它涵盖了基础的数据结构、逻辑控制、事件处理和动画实现等多个方面的知识。通过这样的实践,开发者不仅能掌握编程技能,还能培养出良好的编程思维,为未来更...

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

    【俄罗斯方块面向对象版本 (JAVA版本)】是一款基于JAVA编程语言实现的、采用面向对象设计思想的游戏程序。在这个项目中,开发者通过类和对象来抽象游戏中的各个元素,如方块、游戏区域、游戏控制等,使得代码结构...

    俄罗斯方块的java实现源代码

    首先,Java作为一种面向对象的编程语言,它的类和对象概念在实现俄罗斯方块中起到了核心作用。我们可以将每个方块看作一个对象,拥有形状、颜色、旋转状态等属性,以及移动、下落、旋转等行为。通过定义基类Block,...

    俄罗斯方块,用C#语言写的,使用面向对象的编程方法

    总结来说,通过C#语言实现的面向对象版俄罗斯方块,不仅展示了C#语言的语法特性和面向对象编程的思想,还涵盖了游戏设计、用户交互、事件处理等多个方面。这种实践有助于开发者提升编程技能,同时加深对面向对象编程...

    基于MFC的俄罗斯方块游戏

    通过学习和实践基于MFC的俄罗斯方块游戏开发,不仅可以深入了解MFC框架,还能提升游戏编程的技能,理解面向对象的设计思想,以及如何将复杂的游戏逻辑转化为简单的代码结构。对于初学者来说,这是一个很好的学习项目...

    flag_面向对象_俄罗斯方块_outerdju_vc++_

    总的来说,这个项目展示了如何用面向对象的思想和VC++来实现一个经典游戏,通过类的设计和C++的特性,实现了俄罗斯方块的逻辑和用户交互,让玩家可以在命令行界面中享受游戏的乐趣。这种实践有助于提升开发者的设计...

    java 俄罗斯方块 毕业设计 开题报告

    通过这个项目,学生可以深入理解Java语言的编程思想,熟练掌握JDK和Eclipse等开发工具,以及Java的面向对象编程方法。此外,项目实践还能培养独立思考、问题解决和工程实践能力,为未来职业生涯奠定基础。

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

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

    俄罗斯方块2.0面向对象方式写的,彩色俄罗斯方块游戏

    《面向对象编程实现的彩色俄罗斯方块2.0——JavaScript篇》 俄罗斯方块,这款经典的游戏自1984年诞生以来,以其简洁而富有挑战性的玩法深受全球玩家喜爱。随着技术的发展,游戏的呈现形式也在不断进化,从最初的...

    js做的俄罗斯方块

    通过学习和实践这个项目,开发者不仅可以掌握JavaScript的基本语法,还能深入理解面向对象编程的思想,提升动态网页开发技能。同时,这也是一个很好的练习,用于提高问题解决能力、逻辑思维能力和代码组织能力。

    C#写的简单俄罗斯方块游戏

    它是一个很好的实践项目,可以帮助开发者提升编程技巧,理解面向对象编程思想,并对游戏开发有初步的认识。无论你是编程新手还是有一定经验的开发者,都可以从这个项目中受益,体验到编程的乐趣和挑战。

    java版本俄罗斯方块课设报告

    总体而言,这份报告通过实现俄罗斯方块游戏,让学生深入理解JAVA语言的核心特性和面向对象编程的实践应用,同时鼓励他们进行创新,提升编程和设计能力。设计模式的引入则进一步强调了在实际项目中借鉴和应用成熟设计...

    使用C++实现的俄罗斯方块代码

    在编程领域,用C++实现经典游戏俄罗斯方块是一项常见的学习任务,它能帮助开发者深入理解面向对象编程、事件处理、图形绘制等核心概念。以下是对这个项目的详细解读: 1. **C++语言基础**:C++是一种静态类型、编译...

    java俄罗斯方块的逐步实现

    开发者需要熟悉面向对象编程思想,理解类的定义、对象的创建以及方法的调用。 2. **Swing或JavaFX库**:为了构建游戏的图形界面,开发者可能使用了Java的Swing或JavaFX库。Swing是Java的标准GUI工具包,提供了丰富...

Global site tag (gtag.js) - Google Analytics