俄罗斯方块游戏

如有疑问请查看: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. 配置VNCserver

    翻译:yunqing原作者:Thomas Chung出处:http://fedoranews.org/tchung/vnc/ 声明: 版权属原作者Thomas Chung所有,转载请注明出处. 再说一 ...

  2. OpenGL基础知识

    基本概念 透视(Perspective)变换(Transformation)投影矩阵(Projection Matrix):用于将3D坐标转换为2D屏幕坐标光栅化(Rasterization): 实际 ...

  3. Case 架构的实际应用-2

    Test Plan in TestLink 1. For new release, we will create 2 test plans for each project 2. 1st test p ...

  4. Spring Injection with @Resource, @Autowired and @Inject

    August 1st, 2011 by David Kessler Overview I’ve been asked several times to explain the difference b ...

  5. MTK android flash配置

    关于6573集成MCP nandflash的方法,driver_allinone 和Memory Customer Document pdf的说明里面漏了很多细节.在此补上. 1.首先确认flash型 ...

  6. Introducing Microsoft Sync Framework: Sync Services for File Systems

    https://msdn.microsoft.com/en-us/sync/bb887623 Introduction to Microsoft Sync Framework File Synchro ...

  7. BISTU-(1)-4-17-2016

    A:贪心,遍历每次维护一个最便宜的价格,假如当前价格不如此前价格,就用此前价格购买当前数量的肉,每次更新最便宜的价格. #include <algorithm> #include < ...

  8. java生成随机序列号

    1.java生成随机序列号 String deleteUuid = UUID.randomUUID().toString(); 引用Jar包 //java-uuid-generator-3.1.3.j ...

  9. Qt之Tab键切换焦点顺序

    简介 Qt的窗口部件按用户的习惯来处理键盘焦点.也就是说,其出发点是用户的焦点能定向到任何一个窗口,或者窗口中任何一个部件. 焦点获取方式比较多,例如:鼠标点击.Tab键切换.快捷键.鼠标滚轮等. 习 ...

  10. HDu 3449 (有依赖的01背包) Consumer

    题意: 有n件物品,对应有不同的价格和价值,这是典型的01背包.但现在有了一个限制,要买物品先买能装这件物品的特定的盒子,盒子的价值为0 代码理解得还不是太好,感觉这是一个“二重”的01背包.首先假设 ...