当前位置:编程学习 > JAVA >>

学习写俄罗斯方块出现的问题



主窗口:测试类
package cn.liyan.tetris.game;

import java.awt.Toolkit;

import javax.swing.JFrame;

import cn.liyan.tetris.controller.Controller;
import cn.liyan.tetris.entities.Ground;
import cn.liyan.tetris.entities.Shape;
import cn.liyan.tetris.entities.ShapeFactory;
import cn.liyan.tetris.util.Global;
import cn.liyan.tetris.view.GamePanel;

public class MainFrame extends JFrame {
public void showMe() {
this.setTitle("我的俄罗斯方块游戏");
this.setSize(Global.WIDTH*Global.CELL_SIZE+6, Global.HEIGHT*Global.CELL_SIZE+28);
this.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width-Global.WIDTH*Global.CELL_SIZE)/2,
(Toolkit.getDefaultToolkit().getScreenSize().height-Global.HEIGHT*Global.CELL_SIZE)/2);
this.setVisible(true);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}


public static void main(String[] args) {
MainFrame mainFrame = new MainFrame();
Ground ground = new Ground();
GamePanel gamepanel = new GamePanel();
ShapeFactory shapefactory = new ShapeFactory();
Controller controller = new Controller(ground, shapefactory, gamepanel);
mainFrame.add(gamepanel);
gamepanel.addKeyListener(controller);
mainFrame.addKeyListener(controller);

mainFrame.showMe();
controller.newGame();

}
}



障碍物类:
package cn.liyan.tetris.entities;

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

import cn.liyan.tetris.util.Global;

public class Ground {

private int[][] obstacle = new int[Global.WIDTH][Global.HEIGHT];



public void acceptShape(Shape shape) {
System.out.println("Ground......acceptShape");
for(int x=0; x<4; x++) {
for(int y=0; y<4; y++) {
if(shape.isMember(x, y, false)) {
obstacle[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(obstacle[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++) {
obstacle[x][y] = obstacle[x][y-1];
}
}
for(int x=0; x<Global.WIDTH; x++) {
obstacle[x][0] = 0;
}
}

public void drawMe(Graphics g) {
System.out.println("Ground.....drawMe");
g.setColor(Color.GREEN);
for(int x=0; x<Global.WIDTH; x++) {
for(int y=0; y<Global.HEIGHT; y++) {
if (obstacle[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.RIGHT:
left++;
break;
case Shape.LEFT:
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 || obstacle[left+x][top+y] == 1 ) 
return false;
}
}
}
return true;

}

public boolean isFull() {
for(int x=0; x<Global.WIDTH; x++) {
if(obstacle[x][0]==1) {
return true;
}
}
return false;
}



}



图形类:
package cn.liyan.tetris.entities;

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

import cn.liyan.tetris.listener.ShapeListener;
import cn.liyan.tetris.util.Global;

public class Shape {
private ShapeListener listener;

private int[][] body;//存储图形状态的二维数组
private int status;//图形第几种状态

private int left;  //x轴方向位置变化
private int top;   //y轴方向位置变化


public static final int ROTATE = 0;
public static final int LEFT = 1;
public static final int RIGHT = 2;
public static final int DOWN = 3;


public void moveRight() {
System.out.println("shape.....moveRight");
this.left++;
}
public void moveLeft() {
System.out.println("shape.....moveLeft");
this.left--;
}
public void moveDown() {
System.out.println("shape.....moveDown");
this.top++;
}

public void  rotate() {
System.out.println("shape.....rotate");
this.status = (status+1)%body.length;
}

//绘制图形
public void drawMe(Graphics g) {
System.out.println("shape.....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);
}
}
}




}
//更具图形形状数组确定标记,是否绘制
private boolean getFlagByPoint(int x, int y) {
return body[status][y*4+x]==1;
}
//判断是否是该图形的一部分
public boolean isMember(int x, int y, boolean rotate) {
int tempstatus = status;
if(rotate) {
tempstatus = (status+1)%body.length;//如果旋转了,那么就取下一个状态
}
return body[tempstatus][y*4+x] == 1;
}

/*
 * 内部类,shape自动下落线程
 */
private class ShapeDriver implements Runnable {

@Override
public void run() {
while(listener.isShapeMoveDownable(Shape.this)) {
moveDown();
listener.ShapeMoveDown(Shape.this);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}
}
//构造方法启动线程
public Shape() {
new Thread(new ShapeDriver()).start();
}

//提供注册监听器的方法
public void addKeyListener(ShapeListener listener) {
if( listener != null) 
this.listener = listener;

}
//向图形工场提供设置图形形状的方法
public void setBody(int[][] body) {
this.body = body;
}
//设置状态方法
public void setStatus(int status) {
this.status = status;
}

public int getLeft() {
return left;
}
public int getTop() {
return top;
}

}


图形工厂类:
package cn.liyan.tetris.entities;

import java.util.Random;

import cn.liyan.tetris.listener.ShapeListener;

public class ShapeFactory {

//三维数组存储图形的不同形状和状态
private int[][][] shapes = new int[][][]{
{
{ 0, 1, 0, 0, 1, 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 },

{ 1, 1, 1, 0, 0, 1, 0, 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 } 
}
};



/*
 * 生产一个图形
 */
public Shape getShape(ShapeListener listener) {
System.out.println("ShapeFactory......getShape");
Shape shape = new Shape();
shape.addKeyListener(listener);//注册监听
int type = new Random().nextInt(shapes.length);
shape.setBody(shapes[type]);
shape.setStatus(0);
return shape;
}
}
图形监听接口:
package cn.liyan.tetris.listener;

import cn.liyan.tetris.entities.Shape;

public interface ShapeListener {
void ShapeMoveDown(Shape shape);
boolean isShapeMoveDownable(Shape shape);
}


常量类:
package cn.liyan.tetris.util;

public class Global {
public static final int CELL_SIZE = 40;

public static final int WIDTH = 10;
public static final int HEIGHT = 13;
}


游戏panel:
package cn.liyan.tetris.view;

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

import javax.swing.JPanel;

import cn.liyan.tetris.entities.Ground;
import cn.liyan.tetris.entities.Shape;
import cn.liyan.tetris.util.Global;

public class GamePanel extends JPanel {
private Ground ground;
private Shape shape;

public void disPlay(Ground ground,Shape shape) {
System.out.println("GamePanel.....dispaly");
this.ground = ground;
this.shape = shape;
this.repaint();//实际上调用paintComponent();

}



@Override
protected void paintComponent(Graphics g) {
//重新显示
g.setColor(Color.BLACK);
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 GamePanel() {
this.setSize(Global.WIDTH*Global.CELL_SIZE, Global.HEIGHT*Global.CELL_SIZE);
}

}

控制器类:
package cn.liyan.tetris.controller;

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

import cn.liyan.tetris.entities.Ground;
import cn.liyan.tetris.entities.Shape;
import cn.liyan.tetris.entities.ShapeFactory;
import cn.liyan.tetris.listener.ShapeListener;
import cn.liyan.tetris.view.GamePanel;

public class Controller extends KeyAdapter implements ShapeListener {
private Ground ground;
private Shape shape;
private ShapeFactory shapefactory;
private GamePanel gamepanel;


@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))
shape.moveDown();
break;
case KeyEvent.VK_RIGHT:
if(ground.isMoveable(shape, Shape.RIGHT))
shape.moveRight();
break;
case KeyEvent.VK_LEFT:
if(ground.isMoveable(shape, Shape.LEFT))
shape.moveLeft();
break;
}

gamepanel.disPlay(ground, shape);

}

public Controller(Ground ground, ShapeFactory shapefactory,
GamePanel gamepanel) {
this.ground = ground;
this.shapefactory = shapefactory;
this.gamepanel = gamepanel;
}



public synchronized boolean isShapeMoveDownable(Shape shape) {
if(ground.isMoveable(shape, Shape.DOWN))
return true;
ground.acceptShape(this.shape);//如果不能再往下移动了,就变为障碍物
if(!ground.isFull())
this.shape = shapefactory.getShape(this);
return false;
}


@Override
//重新绘制面板内容
public void ShapeMoveDown(Shape shape) {
gamepanel.disPlay(ground, shape);
}

//开始新游戏 图形工场生产一个图形
public void newGame() {
shape = shapefactory.getShape(this);
}



}



以就是这个俄罗斯方块游戏的全部代码,运行的时候有时候会出现Exception in thread "Thread-3" java.lang.NullPointerException at cn.liyan.tetris.entities.Shape$ShapeDriver.run(Shape.java:80)
at java.lang.Thread.run(Unknown Source)
但是有时候就运行正常,出错的是shape类里的内部类run方法
while(listener.isShapeMoveDownable(Shape.this))


希望大侠帮忙看看
补充:Java ,  Java SE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,