下面是我的源代码:问题是:程序有时可以正常运行,但有时无法正常运行,无法正常运行的时候就会抛出空指针异常!可以正常运行时当方块运行到边界底部时就会出现数组角标越界异常!!!真心是无奈了,求哪位大神不吝赐教,感激不尽!!!
package com.mytetris.model;
import java.awt.Color;
import java.awt.Graphics;
import com.mytetris.listener.ShapeListener;
import com.mytetris.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 ShapeListener listener;
private int[][] body;
private int status;
private int left;
private int top;
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.blue);
for(int x = 0;x < 4;x++){
for(int y = 0;y < 4;y++){
if(isFlagByPoint(x,y)){
g.fill3DRect((left+x)*Global.CELL_SIZE,
(top+y)*Global.CELL_SIZE,
Global.CELL_SIZE,
Global.CELL_SIZE,
true);
}
}
}
}
private boolean isFlagByPoint(int x,int y){
return body[status][y*4+x] == 1;
}
public boolean isNumber(int x,int y,boolean isRotate){
int tempStatus = status;
if(isRotate){
tempStatus = (tempStatus+1) % body.length;
}
return body[tempStatus][y*4+x]==1;
}
//自动下落的属性
private class ShapeDriver implements Runnable{
public void run(){
while(listener.isShapeMoveDownable(Shape.this)){
moveDown();
listener.shapeMoveDown(Shape.this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public Shape(ShapeListener listener){
this.listener = listener;
new Thread(new ShapeDriver()).start();
}
/*public void addShapeListener(ShapeListener l){
if(l != null)
this.listener = l;
}*/
//设置图形的种类
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;
}
}
package com.mytetris.model;
import java.util.Random;
import com.mytetris.listener.ShapeListener;
/**
* 方块工厂类
*/
public class ShapeFactory {
private int[][][] shapes = new int[][][]{
/*L型方块*/{
{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,0,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,0 },
{1,1,1,1, 0,0,0,0,
0,0,0,0, 0,0,0,0 }
},
/*N型方块*/{
{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 }
},
/*山形方块*/{
{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 },
{0,1,0,0, 1,1,1,0,
0,0,0,0, 0,0,0,0 }
},
/*田字形方块*/{
{1,1,0,0, 1,1,0,0,
0,0,0,0, 0,0,0,0 }
}
};
//生产方块的方法
public Shape getShape(ShapeListener listener){
System.out.println("ShapeFactory's getShape()");
Shape shape = new Shape(listener);
//shape.addShapeListener(listener);
int type = new Random().nextInt(shapes.length);
shape.setBody(shapes[type]);
int status = new Random().nextInt(shapes[type].length);
shape.setStatus(status);
return shape;
}
}
package com.mytetris.model;
import java.awt.Graphics;
import com.mytetris.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++){
//先判断原先那个方块数组哪些坐标下的值为1
if(shape.isNumber(x, y, false)){
//然后再将obstacles数组中的相同位置的值置为1
obstacles[shape.getLeft()+x][shape.getTop()+y] = 1;
}
}
}
isFullLine();
}
//将障碍物显示出来
public void drawMe(Graphics g){
System.out.println("Ground's drawMe");
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.isNumber(x,y,action==Shape.ROTATE)){
if(top+y >= Global.HEIGHT||left+x < 0||
left+x >= Global.WIDTH||
obstacles[left+x][top+y]==1)//obstacles[left+x][top+y]==1 判断是否为障碍物
return false;
}
}
}
return true;
}
//判断是否出现满行
private void isFullLine(){
//从最底下那一行开始判断
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){
delecFull(y);
}
}
}
//删除满行
private void delecFull(int line){
for(int y = line;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;
}
}
package com.mytetris.view;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import com.mytetris.model.Ground;
import com.mytetris.model.Shape;
import com.mytetris.util.Global;
/**
* 显示区域
*/
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 g) {
// TODO Auto-generated method stub
g.setColor(new Color(0xcfcfcf));
g.fillRect(0, 0, getSize().width, getSize().height);
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 com.mytetris.control;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import com.mytetris.listener.ShapeListener;
import com.mytetris.model.Ground;
import com.mytetris.model.Shape;
import com.mytetris.model.ShapeFactory;
import com.mytetris.view.GamePanel;
/**
* 控制类
*/
public class Controller extends KeyAdapter implements ShapeListener{
private Shape shape;
private ShapeFactory shapeFactory;
private Ground ground;
private GamePanel gamePanel;
@Override//键盘被按下
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
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_LEFT:
if(ground.isMoveable(shape, Shape.LEFT))
shape.moveLeft();
break;
case KeyEvent.VK_RIGHT:
if(ground.isMoveable(shape, Shape.RIGHT))
shape.moveRight();
break;
}
gamePanel.display(ground, shape);
}
public void shapeMoveDown(Shape shape){
gamePanel.display(ground, shape);
}
public void newGame(){
shape = shapeFactory.getShape(this);
}
public Controller(ShapeFactory shapeFactory,Ground ground,GamePanel gamePanel){
this.shapeFactory = shapeFactory;
this.ground = ground;
this.gamePanel = gamePanel;
}
public synchronized boolean isShapeMoveDownable(Shape shape){
boolean result = ground.isMoveable(shape, Shape.DOWN);
if(!result){
ground.accept(shape);
newGame();
}
return result;
}
}
package com.mytetris.util;
public class Global {
public static final int CELL_SIZE = 20;
public static final int WIDTH = 30;
public static final int HEIGHT = 30;
}
package com.mytetris.test;
import javax.swing.JFrame;
import com.mytetris.control.Controller;
import com.mytetris.model.Ground;
import com.mytetris.model.ShapeFactory;
import com.mytetris.view.GamePanel;
public class Game {
public static void main(String[] args){
ShapeFactory shapeFactory = new ShapeFactory();
Ground ground = new Ground();
GamePanel gamePanel = new GamePanel();
Controller controller = new Controller(shapeFactory,
ground,gamePanel);
JFrame frame = new JFrame();
frame.setSize(gamePanel.getSize().width+15,
gamePanel.getSize().height+35);
frame.add(gamePanel);
frame.setLocationRelativeTo(null);//将窗体至于屏幕的中央位置
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gamePanel.addKeyListener(controller);
frame.addKeyListener(controller);
frame.setVisible(true);
/* 获取输入焦点JPanel添加键盘监听器及鼠标监听器都是需要获取焦点的
* (但是有时候又不行)*/
//gamePanel.requestFocusInWindow();
controller.newGame();
}
}
package com.mytetris.listener;
import com.mytetris.model.Shape;
public interface ShapeListener {
void shapeMoveDown(Shape shape);
boolean isShapeMoveDownable(Shape shape);
}