俄罗斯方块游戏 --- java

时间:2022-12-29 12:01:11

俄罗斯方块游戏

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

游戏的运行结果如下:

俄罗斯方块游戏 --- java

俄罗斯方块游戏 --- java俄罗斯方块游戏 --- java

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

俄罗斯方块游戏 --- java

游戏发生的场地是在面板(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 &amp&semi; Javascript 俄罗斯方块游戏

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

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

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

  4. 用C写的俄罗斯方块游戏 By&colon; 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&plus;&plus;编写简单的俄罗斯方块游戏

    代码地址如下: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. Java 前后端分离研究

    https://github.com/ulyn/eos https://github.com/lenbo-ma/jfinal-api-scaffold/

  2. GridView--scroolview嵌套listview和gridview

    我们在真实项目中通常会遇到ListView或者GridView嵌套在ScrollView中问题.但是做的时候会发现,一旦两者进行嵌套,即会发生冲突.得不到我们希望的效果.由于ListView和Grid ...

  3. SE 2014年4月3日

    一  OSPF协议都支持哪些特殊区域?每种特殊区域都有什么特点. OSPF协议支持的特殊区域主要有stub区域.totally stub区域以及nssa区域,其中stub区域一般出现在末梢网络,即它的 ...

  4. wpf CollectionViewSource的运用

    实体类: 员工类: public class Department : ObservableCollection<Employee> { public string DepName { g ...

  5. piwik安装部署最佳实践

    1.piwik介绍 Piwik是一个PHP和MySQL的开放源代码的Web统计软件,它给你一些关于你的网站的实用统计报告,比如网页浏览人数,访问最多的页面,搜索引擎关键词等等. Piwik拥有众多不同 ...

  6. idea Artifact mdn&colon;war exploded&colon; Server is not connected&period; Deploy is not available&period;

    idea 启动tomcat报的错误,启动tomcat无效 看了网上的好几种说发 说删除tomcat/bin/catalina.bat  里的JAVA_OPTS= -Xms512M -Xmx512M - ...

  7. 我的第一个python web开发框架(37)——职位管理功能

    对于职位管理,我们可以理解它为角色权限的管理,就像前面所说的一样,有了职位管理,后台管理系统绑定好对应的权限以后,新进员工.离职或岗位调整,管理员操作起来就非常的便捷了,只需要重新绑定对应职位就可以做 ...

  8. 初次接触Java

    今天初次接触Eclipse,学着用他来建立java工程,话不多说,来看看今天的成果! 熟悉自己手中的开发工具,热热身 刚上手别慌,有问题找度娘 刚刚拿到这个软件的安装包我是一脸懵逼的,因为是从官网下载 ...

  9. Django学习手册 - ORM 单表数据获取

    Django 单表数据的获取: 先建立数据表格 from django.db import models # Create your models here. class userinfo(model ...

  10. ES系列四、ES6&period;3常用api之文档类api

    1.Index API: 创建并建立索引 PUT twitter/tweet/ { "user" : "kimchy", "post_date&quo ...