项目实战 --俄罗斯方块 主讲:贾宗维
程序演示 游戏01_功能演示与说明 游戏02_面向对象设计 游戏03_使用API类组装游戏 游戏04_编写各个类主体框架 游戏05_编写Controler类实现事件监听 游戏06_编写类测试代码 游戏07_图形设计与创建 游戏08_图形移动与显示 游戏09_处理游戏边界问题 游戏10_障碍物生成与显示 游戏11_消除满行的障碍物 游戏12_增加游戏结束 游戏13_定时下落
编写各个类主体框架-Shape类 private class ShapeDriver implements Runnable{ public void run() { // TODO Auto-generated method stub while(true){ moveDown(); //listener.shapeMoveDown(Shape.this); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); public class Shape { //private ShapeListener listener; public void moveLeft(){ System.out.println("shape's moveLeft"); } public void moveRight(){ System.out.println("shape's moveright"); public void moveDown(){ System.out.println("shape's moveDown"); public void rotate(){ System.out.println("shape's rotate"); public void drawMe(){ System.out.println("shape's drawme");
编写各个类主体框架-ShapeFactory类 public class ShapeFactory { public Shape getShape(ShapeListener listener){ System.out.println("ShapeFactory's getShape"); Shape shape=new Shape(); return shape; }
编写各个类主体框架-Ground类 package cn.tetris.entities; public class Ground { public void accept(){ System.out.println("Ground's accept"); } public void drawMe(){ System.out.println("Ground's drawMe");
编写各个类主体框架-GamePanel类 public class GamePanel extends JPanel { private Ground ground; private Shape shape; 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 arg0) { // TODO Auto-generated method stub //重新显示 if (ground!=null && shape!=null){ ground.drawMe(); shape.drawMe();
编写各个类主体框架-Controller类 public class Controller extends KeyAdapter { private Ground ground; private Shape shape; private ShapeFactory shapeFactory; private GamePanel gamePanel; public void keyPressed(KeyEvent e) { switch(e.getKeyCode()){ case KeyEvent.VK_UP: shape.rotate(); break; case KeyEvent.VK_LEFT: shape.moveLeft(); break; case KeyEvent.VK_RIGHT: shape.moveRight(); break; case KeyEvent.VK_DOWN: shape.moveDown(); break;} gamePanel.display(ground, shape); }
编写各个类主体框架-ShapeListener接口 public interface ShapeListener { void shapeMoveDown(Shape shape); }
Shape类增加监听器对象及下落后调用 listener.shapeMoveDown(Shape.this); private class ShapeDriver implements Runnable{ public void run() { // TODO Auto-generated method stub while(true){ moveDown(); listener.shapeMoveDown(Shape.this); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); public class Shape { private ShapeListener listener; public void moveLeft(){ System.out.println("shape's moveLeft"); } public void moveRight(){ System.out.println("shape's moveright"); public void moveDown(){ System.out.println("shape's moveDown"); public void rotate(){ System.out.println("shape's rotate"); public void drawMe(){ System.out.println("shape's drawme");
public void addShapeListener(ShapeListener l){ if(l!=null){ this.listener =l; }
new Thread(new ShapeDriver()).start(); } public Shape(){ new Thread(new ShapeDriver()).start(); }
Controller类实现ShapeListener接口 public class Controller extends KeyAdapter implements ShapeListener { public void shapeMoveDown(Shape shape) { // TODO Auto-generated method stub gamePanel.display(ground, shape); }
public class ShapeFactory { 生产图形时同时注册监听器 public class ShapeFactory { public Shape getShape(ShapeListener listener){ System.out.println("ShapeFactory's getShape"); Shape shape=new Shape(); shape.addShapeListener(listener); return shape; }
GamePanel类设置大小 public GamePanel(){ this.setSize(300,300); }
Controller类中增加开始新游戏方法 public void newGame(){ shape=shapeFactory.getShape(this); }
Controller类中如何接收外部控制的对象 public Controller(ShapeFactory shapeFactory,Ground ground, GamePanel gamePanel){ this.shapeFactory=shapeFactory; this.ground=ground; this.gamePanel=gamePanel; }
测试类Game public class Game { public static void main(String[] args) { // TODO Auto-generated method stub ShapeFactory shapeFactory=new ShapeFactory(); Ground ground=new Ground(); GamePanel gamePanel=new GamePanel(); Controller controller=new Controller(shapeFactory,ground,gamePanel); JFrame frame=new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(gamePanel.getSize().width+10, gamePanel.getSize().height+35); frame.add(gamePanel); gamePanel.addKeyListener(controller); frame.setVisible(true); controller.newGame(); }
程序步骤 游戏01_功能演示与说明 游戏02_面向对象设计 游戏03_使用API类组装游戏 游戏04_编写各个类主体框架 游戏05_编写Controler类实现事件监听 游戏06_编写类测试代码 游戏07_图形设计与创建 游戏08_图形移动与显示 游戏09_处理游戏边界问题 游戏10_障碍物生成与显示 游戏11_消除满行的障碍物 游戏12_增加游戏结束 游戏13_定时下落
Shape类,增加图形的描述 //二维变量用于保存图形的所有状态 private int[][] body; //用于保存图形当前的状态 private int status; //设置状态的方法 public void setBody(int body[][]){ this.body=body; } //设置当前是第几种状态 public void setStatus(int status){ this.status=status;
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,1,0,0, 0,1,0,0, 1,1,0,0, 0,0,0,0} }}; public Shape //生产一个随机数,用于表示图形的状态 int type=new Random().nextInt(shapes.length); //设置图形有几种状态 shape.setBody(shapes[type]); //设置默认状态 shape.setStatus(0); return shape; }
Shape类中增加图形的位置信息 //表示图形距离左侧的距离 private int left; //表示图形距离上边界的距离 private int top; public void moveLeft(){ left--; } public void moveRight(){ left++; public void moveDown(){ top++; public void rotate(){ //显示下一个状态,但得保证状态值不超过4,所以需处理 status=(status+1)%body.length;
Shape类中增加图形的绘制方法 public void drawMe(Graphics g){ System.out.println("shape's drawme"); g.setColor(Color.RED); //循环访问代表方正的数组 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); } } } } //获取方正中标志是1还是0,1表示要绘图0表示不绘图 private boolean getFlagByPoint(int x,int y){ return body[status][y*4+x]==1; }
public static final int CELL_SIZE=20; //表示图形面板有多少个格子宽和高 游戏常量的存放——Glaobal public class Global { //表示每个方格的像素值 public static final int CELL_SIZE=20; //表示图形面板有多少个格子宽和高 public static final int WIDTH=15; public static final int HEIGHT=15; }
在GamePanel类的paintComponent方法中增加如下代码:在填充一个与背景同色的区域 测试游戏,下落方块出现拖影 在GamePanel类的paintComponent方法中增加如下代码:在填充一个与背景同色的区域 g.setColor(new Color(0xcfcfcf)); g.fillRect(0, 0, Global.CELL_SIZE*Global.WIDTH, Global.CELL_SIZE*Global.HEIGHT); //填充一个灰色显示区域,避免图形拖影 修改此处的同时还需修改Shape的drawme方法中设置图形的颜色,以及给frame也注册监听器。
图形如何避免移出边界 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++; case Shape.DOWN: top++; break; } //依次取出图形中的每一个点,判断是否超出显示区域 for(int x=0;x<4;x++){ for(int y=0;y<4;y++){ //判断xy点是否是图形的成员 if(shape.isMember(x, y,action==Shape.ROTATE)){ if(top+y>=Global.HEIGHT|| left+x<0|| left+x>=Global.WIDTH) return false; } } } return true; }