俄罗斯方块游戏

如有疑问请查看:http://zh.wikipedia.org/zh-tw/%E4%BF%84%E7%BD%97%E6%96%AF%E6%96%B9%E5%9D%97

更多疑问请参考:http://java.itcast.cn/news/b4c1f433/34fd/4a7b/96bf/f1ae5e00ce70.shtml

游戏的运行结果如下:

代码的整体目录结构如下:

游戏发生的场地是在面板(panel)上,是JFrame框架把面板圈了起来

图形具有自己本身的特征,比如说形状,颜色,会定时落下一个单位,以及被触发的变幻,左移,右移,下移,

障碍物是图形落下后到底边框或其它图形产生的障碍物由图形生成的,

控制器负责接受按键事件来控制面板上的图形的移动和产生

这里是程序的入口处:

package com.kodoyang.tetris.test;

import javax.swing.JFrame;

import com.kodoyang.tetris.control.Controller;
import com.kodoyang.tetris.pojo.Ground;
import com.kodoyang.tetris.pojo.ShapeFactory;
import com.kodoyang.tetris.view.Panel;

public class Game {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        ShapeFactory shapeFactory = new ShapeFactory();
        Ground ground = new Ground();
        Panel panel = new Panel();

        Controller controller = new Controller(shapeFactory, ground, panel);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(panel.getSize().width + 10, panel.getSize().height + 35);
        frame.add(panel);
        panel.addKeyListener(controller);

        frame.addKeyListener(controller);
        frame.setVisible(true);
        controller.newGame();

    }

}

先来看看图形类:

图形的body回填上制造啊它的工厂传给它的参数,

以及它的移动方式,坐标,颜色,画自己的方法,不断下落的线程

package com.kodoyang.tetris.pojo;

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

import com.kodoyang.tetris.listen.ShapeListener;
import com.kodoyang.tetris.util.Global;

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 Color color;

    private int left;
    private int top;

    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;
    }

    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's drawMe");

        g.setColor(color);
        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);
                }
            }
        }

    }

    private boolean getFlagByPoint(int x, int y){
        /*boolean res = false;
        try {
            // return body[status][x + y * 4] == 1;
            res = body[status][x + y * 4] == 1;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            System.out.println("(x, y) = (" + x + ", " + y + ")");
            e.printStackTrace();
        }
        return res;*/
        return body[status][x + y * 4] == 1;
    }

    public boolean isMember(int x, int y, boolean rotate){
        int tempStatus = status;
        if(rotate){
            tempStatus = (status + 1) % body.length;
        }
        return body[tempStatus][x + y * 4] == 1;
    }

    private class ShapeDriver implements Runnable {

        @Override
        public void run() {
            while(listener.isShapeMoveDownable(Shape.this)) {
                moveDown();
                listener.shapeMoveDown(Shape.this);

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public Shape() {
        new Thread(new ShapeDriver()).start();
    }

    public void addShapeListenner(ShapeListener l) {
        if(l != null)
            this.listener = l;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

}

产生图形的工厂类如下:

shapes中定义了一些预置的图形,colors中定义了一些图形可以使用的颜色

package com.kodoyang.tetris.pojo;

import java.awt.Color;
import java.util.Random;

import com.kodoyang.tetris.listen.ShapeListener;

public class ShapeFactory {

    private int[][][] shapes = new int[][][]{
            {
                {
                    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
                },
                {
                    0, 1, 0, 0,
                    0, 1, 0, 0,
                    1, 1, 0, 0,
                    0, 0, 0, 0
                }
            },
            {
                {
                    1, 1, 1, 1,
                    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
                }
            },
            {
                {
                    1, 1, 0, 0,
                    1, 1, 0, 0,
                    0, 0, 0, 0,
                    0, 0, 0, 0
                }
            },
            {
                {
                    1, 1, 1, 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, 0
                },
                {
                    0, 0, 1, 0,
                    1, 1, 1, 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
                }
            },
            {
                {
                    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
                },
                {
                    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
                }
            },
            {
                {
                    1, 0, 0, 0,
                    1, 1, 0, 0,
                    1, 0, 0, 0,
                    0, 0, 0, 0
                },
                {
                    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, 1, 0,
                    1, 0, 0, 1,
                    1, 0, 0, 1,
                    0, 1, 1, 0
                },
                {
                    1, 0, 0, 1,
                    0, 1, 1, 0,
                    0, 1, 1, 0,
                    1, 0, 0, 1
                }
            },
            {
                {
                    0, 1, 0, 0,
                    1, 1, 1, 1,
                    0, 1, 0, 0,
                    0, 1, 0, 1
                },
                {
                    1, 0, 1, 0,
                    0, 0, 1, 0,
                    1, 1, 1, 1,
                    0, 0, 1, 0
                }
            },
            {
                {
                    0, 1, 0, 0,
                    1, 1, 1, 1,
                    1, 0, 0, 1,
                    1, 0, 0, 1
                },
                {
                    0, 1, 1, 0,
                    1, 0, 1, 0,
                    0, 1, 0, 1,
                    0, 1, 1, 0
                }
            }
    };

    private Color[] colors = new Color[]{
        Color.CYAN,
        Color.BLACK,
        Color.BLUE,
        Color.GREEN,
        Color.MAGENTA,
        Color.ORANGE,
        Color.PINK,
        Color.RED,
        Color.WHITE,
        Color.YELLOW
    };

    public Shape getShape(ShapeListener listener) {
        System.out.println("ShapeFactory's getShape");
        Shape shape = new Shape();
        shape.addShapeListenner(listener);

        int type = new Random().nextInt(shapes.length);
        shape.setBody(shapes[type]);
        shape.setStatus(0);
        shape.setColor(colors[new Random().nextInt(colors.length)]);

        return shape;
    }

}

图形监听器的接口类:

实现这个接口的类必须要实现两个方法,让图形下移,判断图形是否可以移动

package com.kodoyang.tetris.listen;

import com.kodoyang.tetris.pojo.Shape;

public interface ShapeListener {

    void shapeMoveDown(Shape shape);

    boolean isShapeMoveDownable(Shape shape);

}

接受图形的静寂大地类:

当图形不能移动时就变为寂静大地了,构成静寂大地的是一个个的障碍物,

它通过计算图形下一步的位置来得出图形能不能移动的信息

如果障碍物出现在面板的顶部,就表示已经满了,游戏结束

判断某一行满行就把满了的行消掉

package com.kodoyang.tetris.pojo;

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

import com.kodoyang.tetris.util.Global;

public class 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();
    }

    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");

        g.setColor(Color.DARK_GRAY);
        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;
    }

}

用于显示的面板类:

它的画图方法就是在清空整个面板后,调用图形和静寂大地的画图方法

它的构造方法会决定游戏界面的大小

package com.kodoyang.tetris.view;

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

import javax.swing.JPanel;

import com.kodoyang.tetris.pojo.Ground;
import com.kodoyang.tetris.pojo.Shape;
import com.kodoyang.tetris.util.Global;

public class Panel extends JPanel {

    private Ground ground;
    private Shape shape;

    public void display(Ground ground, Shape shape) {
        System.out.println("TetrisPanel's display");
        this.ground = ground;
        this.shape = shape;
        this.repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        // 重新显示

        g.setColor(Color.LIGHT_GRAY);
        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 Panel() {
        this.setSize(
                Global.WIDTH * Global.CELL_SIZE,
                Global.HEIGHT * Global.CELL_SIZE);
    }

}

常量定义在全局类中:

每一个正方形小块的大小,面板拥有多少个正方形的边长个单位

package com.kodoyang.tetris.util;

public class Global {

    public static final int CELL_SIZE = 20;
    public static final int WIDTH = 20;
    public static final int HEIGHT = 25;

}

控制它们的中央控制器:

它继承自按键事件的监听并实现了图形监听的接口

它控制当前活动图形以及产生它的工厂,障碍物,面板

产生一个新游戏的方法,判断图形是否可以下落,更新面板上的图形和障碍物,

package com.kodoyang.tetris.control;

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

import com.kodoyang.tetris.listen.ShapeListener;
import com.kodoyang.tetris.pojo.Ground;
import com.kodoyang.tetris.pojo.Shape;
import com.kodoyang.tetris.pojo.ShapeFactory;
import com.kodoyang.tetris.view.Panel;

public class Controller extends KeyAdapter implements ShapeListener {

    private Shape shape;
    private ShapeFactory shapeFactory;
    private Ground ground;
    private Panel panel;

    @Override
    public synchronized boolean isShapeMoveDownable(Shape shape) {
        // TODO Auto-generated method stub
        if(this.shape != shape){
            return false;
        }
        if( ground.isMoveable(shape, Shape.DOWN) )
            return true;
        ground.accept(this.shape);
        if(!ground.isFull()){
            this.shape = shapeFactory.getShape(this);
        }
        return false;
    }

    @Override
    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(ground.isMoveable(shape, Shape.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;
        }

        panel.display(ground, shape);
    }

    @Override
    public void shapeMoveDown(Shape shape) {
        panel.display(ground, shape);

    }

    public void newGame() {
        shape = shapeFactory.getShape(this);
    }

    public Controller(ShapeFactory shapeFactory,
            Ground ground, Panel panel) {
        this.shapeFactory = shapeFactory;
        this.ground = ground;
        this.panel = panel;

    }

}

跟多好文请查看:http://www.cnblogs.com/kodoyang/

俄罗斯方块游戏 --- java的更多相关文章

  1. java俄罗斯方块游戏代码

    java俄罗斯方块游戏代码: package com; import java.awt.Color; import java.awt.Graphics; import java.awt.event.K ...

  2. 经典 HTML5 & Javascript 俄罗斯方块游戏

    Blockrain.js 是一个使用 HTML5 & JavaScript 开发的经典俄罗斯方块游戏.只需要复制和粘贴一段代码就可以玩起来了.最重要的是,它是响应式的,无论你的显示屏多么宽都能 ...

  3. 从零开始---控制台用c写俄罗斯方块游戏(1)

    从零开始---控制台用c写俄罗斯方块游戏(1) 很少写博文,一来自身知识有限,二来自己知道,已经有很多这样的博文了,三就是因为懒,文笔也一般,四来刚出来工作,时间也不多 之所以写这篇博文,是因为应群里 ...

  4. 用C写的俄罗斯方块游戏 By: hoodlum1980 编程论坛

    /************************************ * Desc: 俄罗斯方块游戏 * By: hoodlum1980 * Email: jinfd@126.com * Dat ...

  5. 教你看懂网上流传的60行JavaScript代码俄罗斯方块游戏

    早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用C写一个功能基本齐全的俄罗斯方块的话,大 ...

  6. 俄罗斯方块游戏JavaScript代码

    JavaScript代码俄罗斯方块游戏 早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用 ...

  7. 使用JS实现俄罗斯方块游戏

    简单的JS俄罗斯方块游戏源码 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <meta charset=&q ...

  8. C++编写简单的俄罗斯方块游戏

    代码地址如下:http://www.demodashi.com/demo/14593.html C++编写简单的俄罗斯方块游戏 使用C++编写一个简单的俄罗斯方块游戏. 1 环境要求 使用C++图形库 ...

  9. electron写俄罗斯方块游戏(Tetris)

    背景 在折腾ES6,突然想起大学时用c语言写过俄罗斯方块,本项目中主要是利用ES6的Class特性进行面向对象编程.项目采用node.js v6.2.0 + electron v1.1.0 进行桌面开 ...

随机推荐

  1. C++时间戳转化(涉及GMT CST时区转化)

    问题由来 时间戳转换(时间戳:自 1970 年1月1日(00:00:00 )至当前时间的总秒数.) #include <stdio.h> #include <time.h> i ...

  2. Spring AOP术语

    1.AOP术语     1)连接点(Joinpoint)     程序执行的某个特定位置:如类开始初始化前.类初始化后.类某个方法调用前.调用后.方法抛出异常后.一个类或一段程序代码拥有一些具有边界性 ...

  3. CF 2013-2014CTS01E04(Killer Challenge-将质因数存在 进行Bitmask)

    首先,把P进行质因数分解,每一个不用的质因数压成1位 f[i][j]表示1前i位用j“拥有”的质因数表示. 然后都懂得... #include<cstdio> #include<cs ...

  4. java实现附件预览(openoffice+swftools+flexpaper)

    先附上本人参考的文章,基于的 flexpaper版本 为 1.5,本人由于使用的是 2.1.9 ,故之后说明: 已经支持加载中文文件名 代码下载 1.概述 主要原理 1.通过第三方工具openoffi ...

  5. dataguru试听课程

    http://www.dataguru.cn/article-5447-1.html#userconsent#

  6. [JWFD开源工作流]JWFD开源工作流官方下载内容更新

    在更新版的JWFD二次开发包中,我正在实现单线程的时钟控制器,动了下引擎的源代码,这个更新包主要是升级界面,内核代码,大家就不用升级了.. 代码提示: 请修改代码包中(org.jwfd.workflo ...

  7. svn版本库包含多个项目 ; git svn clone; 某一个子项目,有多个分支;

    情况描述: 公司的svn版本库,包含了多个项目,每个项目对应于1个文件夹 假设版本库名字为Main,其下的项目用 A项目,对应文件夹A B项目,对应文件夹B 通过git svn clone获取了svn ...

  8. [HIHO]hihoCoder太阁最新面经算法竞赛7

    题目链接:http://hihocoder.com/contest/hihointerview12 期末完事了,终于有时间成套刷题了.这套题比较简单,难度上感觉和上一套差不多.除了最后一个题是看了讨论 ...

  9. $.getJSON ashx 跨域

    context.Response.AddHeader("Access-Control-Allow-Origin", "*");

  10. WebView中Js与Android本地函数的相互调用

    介绍 随着Html5的普及,html在表现力上不一定比原生应用差,并且有很强的扩展兼容性,所以越来越多的应用是采用Html与Android原生混合开发模式实现. 既然要实现混合开发,那么Js与Andr ...