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