1

我在使用俄罗斯方块时遇到了一些问题。所以首先,我有一个 Shape 类,然后是每个形状类型的 Shape 子类。这是 Shape 子类的样子:

public class SquareShape extends Shape {
    public SquareShape(){
        coords = squareShapeCoords;
        shape = SQUARESHAPE;
    }
}

在 Shape 类中,我有一个旋转方法,如下所示:

protected void setX(int i, int x) { coords[i][0] = x; }
protected void setY(int i, int y) { coords[i][1] = y; }
public int x(int i) { return coords[i][0]; }
public int y(int i) { return coords[i][1]; }

public Shape rotate(){
        if (this.getShape().equals(SQUARESHAPE)) return this;
        Shape newShape = new Shape();
        newShape.shape = this.shape;
        for (int i = 0; i < 4; i++) {
            newShape.setX(i, y(i));
            newShape.setY(i, -x(i));
        }
        return newShape;
}

请注意,我将每个形状的坐标存储在二维数组中。另外,这是我的游戏引擎类:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GameEngine extends JPanel implements ActionListener{

    private final int HEIGHT = 15;
    private final int WIDTH = 10;
    private int score;
    int coordX = 0;
    int coordY = 0;
    Timer timer;
    boolean isFinishedFalling = false;
    boolean isRunning = false;
    boolean isPaused = false;
    Shape block;
    String[] shapes;


    public GameEngine(){
        setFocusable(true);
        block = new Shape();
        timer = new Timer(600, this);
        timer.start();
        addMouseListener(new MAdapter());
        addMouseWheelListener(new WheelAdapter());
        addKeyListener(new KAdapter());
        setBackground(Color.BLACK);
        shapes = new String[WIDTH * HEIGHT];
        clearShapes();
    }

    int squareWidth() { return (int) getSize().getWidth() / WIDTH; }
    int squareHeight() { return (int) getSize().getHeight() / HEIGHT; }
    String shapeAt(int x, int y) { return shapes[(y * WIDTH) + x]; }
    public int getScore() {return score;}

    public void actionPerformed(ActionEvent e){
        if(isFinishedFalling){
            isFinishedFalling = false;
            newBlock();
        } else moveDown();
    }

    private boolean move(Shape newShape, int newCoordX, int newCoordY)
    {
        for (int i = 0; i < 4; ++i) {
            int x = newCoordX + newShape.x(i);
            int y = newCoordY - newShape.y(i);
            if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) return false;
            if (!shapeAt(x, y).equals(Shape.DEFAULTSHAPE)) return false;
        }

        block = newShape;
        coordX = newCoordX;
        coordY = newCoordY;
        repaint();
        return true;
    }

    private boolean moveLeft() { return move(block, coordX-1, coordY);}
    private boolean moveRight() { return move(block, coordX+1, coordY);}
    private boolean moveDown(){
        if(!move(block, coordX, coordY-1)){
            blockIsDown();
            return false;
        } else return true;
    }

    private void dropDown(){
        int y = coordY;
        while(y>0){
            if(!move(block, coordX, y-1)) break;
            y -= 1;
        }
        blockIsDown();
    }

    private boolean rotate() { return move(block.rotate(), coordX, coordY);}

    private void blockIsDown(){
        for(int i=0; i<4; i++){
            int a = coordX + block.x(i);
            int b = coordY - block.y(i);
            shapes[b * WIDTH + a] = block.getShape();
        }
        clearFullLines();
        if(!isFinishedFalling) newBlock();
    }

    private void clearFullLines(){
        int fullLines = 0;
        for(int i = HEIGHT-1; i>=0; i--){
            boolean lineFull = true;
            for(int j=0; j<WIDTH; j++){
                if(shapeAt(j, i).equals(Shape.DEFAULTSHAPE)){
                    lineFull = false;
                    break;
                }
            }
            if(lineFull){
                fullLines++;
                for(int m=i; m<HEIGHT-1; m++){
                    for(int n=0; n<WIDTH; n++)
                        shapes[(m*WIDTH) + n] = shapeAt(n, m+1);
                }
            }
        }
        if(fullLines>0){
            score += fullLines*100;
            isFinishedFalling = true;
            block.setShape(Shape.DEFAULTSHAPE);
            repaint();
        }

    }

    private void newBlock()
    {
        block = new RandomShape();
        coordX = WIDTH / 2 + 1;
        coordY = HEIGHT - 1 + block.minY();

        if (!move(block, coordX, coordY)) {
            block.setShape(Shape.DEFAULTSHAPE);
            timer.stop();
            isRunning = false;
        }
    }

    private void clearShapes(){
        for(int i=0; i< WIDTH * HEIGHT; i++) shapes[i] = Shape.DEFAULTSHAPE;
    }

    private void drawSquare(Graphics g, int x, int y, String shape){
        Color color = Color.BLACK;
        if(shape.equals(Shape.ZSHAPE)) color = Color.GREEN;
        if(shape.equals(Shape.SSHAPE)) color = Color.RED;
        if(shape.equals(Shape.LINESHAPE)) color = Color.CYAN;
        if(shape.equals(Shape.TSHAPE)) color = Color.BLUE;
        if(shape.equals(Shape.SQUARESHAPE)) color = Color.YELLOW;
        if(shape.equals(Shape.LSHAPE)) color = Color.MAGENTA;
        if(shape.equals(Shape.MIRROREDLSHAPE)) color = Color.ORANGE;

        g.setColor(color);
        g.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2);
        g.setColor(color.brighter());
        g.drawLine(x, y + squareHeight() - 1, x, y);
        g.drawLine(x, y, x + squareWidth() - 1, y);

        g.setColor(color.darker());
        g.drawLine(x + 1, y + squareHeight() - 1,  x + squareWidth() - 1, y + squareHeight() - 1);
        g.drawLine(x + squareWidth() - 1, y + squareHeight() - 1, x + squareWidth() - 1, y + 1);
    }

    public void paint(Graphics g){
        super.paint(g);
        Dimension size = getSize();
        int top = (int) size.getHeight() - HEIGHT * squareHeight();
        for(int i=0; i<HEIGHT; i++){
            for(int j=0; j<WIDTH; j++){
                String s = shapeAt(j, HEIGHT-i-1);
                if(!s.equals(Shape.DEFAULTSHAPE))
                    drawSquare(g, j * squareWidth(), top + i * squareHeight(), s);
            }
        }
        if(!block.getShape().equals(Shape.DEFAULTSHAPE)){
            for(int i=0; i<4; i++){
                int x = coordX + block.x(i);
                int y = coordY - block.y(i);
                drawSquare(g, x * squareWidth(), top + (HEIGHT - y - 1) * squareHeight(), block.getShape());
            }
        }
    }

    public void start(){
        if(isPaused) return;
        isRunning = true;
        isFinishedFalling = false;
        score = 0;
        clearShapes();
        newBlock();
        timer.start();
    }

    private void pause(){
        if(!isRunning) return;
        isPaused = !isPaused;
        if(isPaused){
            timer.stop();

        } else{
            timer.start();

        }
        repaint();
    }

    class MAdapter extends MouseAdapter{
        public void mouseClicked(MouseEvent e){
            if (!isRunning || block.getShape().equals(Shape.DEFAULTSHAPE) || isPaused) return;
            int buttonPressed = e.getButton();
            if(buttonPressed == MouseEvent.BUTTON1) moveLeft();
            if(buttonPressed == MouseEvent.BUTTON2) rotate();
            if(buttonPressed == MouseEvent.BUTTON3) moveRight();
        }
    }

    class WheelAdapter implements MouseWheelListener{
        public void mouseWheelMoved(MouseWheelEvent e){
            if (!isRunning || block.getShape().equals(Shape.DEFAULTSHAPE) || isPaused) return;
            int wheelRotation = e.getWheelRotation();
            if(wheelRotation == 1) moveDown();
            if(wheelRotation == -1) dropDown();
        }
    }

    class KAdapter extends KeyAdapter{
        public void keyPressed(KeyEvent e){
            if (!isRunning || block.getShape().equals(Shape.DEFAULTSHAPE) || isPaused) return;
            int key = e.getKeyCode();
            if(key == KeyEvent.VK_SPACE) pause();
        }
    }
}

我的问题如下:当我尝试旋转积木时,第一次效果很好,但如果我第二次尝试旋转它们,它就会完全混乱。

这应该是我的线条形状:

线

这是我的 L 形(黄色):

l

请注意,这不仅仅是一个图形错误,游戏将元素分别视为一个或两个正方形。我一直在寻找我的代码几个小时来查看问题可能是什么,但我没有运气。任何帮助,将不胜感激

4

2 回答 2

2

谢谢大家的回复,但是经过进一步的调查,我发现了问题所在。问题出在旋转方法上:

public Shape rotate(){
        if (this.getShape().equals(SQUARESHAPE)) return this;
        Shape newShape = new Shape();
        newShape.shape = this.shape;
        for (int i = 0; i < 4; i++) {
            newShape.setX(i, -y(i));
            newShape.setY(i, x(i));
        }
        return newShape;
}

我向鼠标适配器添加了以下代码,以查看当前块的坐标会发生什么情况:

if(buttonPressed == MouseEvent.BUTTON2) {
                System.out.println(Arrays.deepToString(block.getCoords()));
                rotate();
            }

这是 SShape 的输出:

[[0, -1], [0, 0], [1, 0], [1, 1]]
[[1, 0], [0, 0], [0, 1], [-1, 1]]
[[0, 0], [0, 0], [-1, -1], [-1, -1]]
[[0, 0], [0, 0], [1, 1], [1, 1]]
[[0, 0], [0, 0], [-1, -1], [-1, -1]]
[[0, 0], [0, 0], [1, 1], [1, 1]]
[[0, 0], [0, 0], [-1, -1], [-1, -1]]

第一行包含我为 SShape 提供的初始坐标。在 rotate() 方法之后,第二行包含修改后的坐标。如您所见,X 采用 -Y 值,Y 采用 X 值。然而,在第三行中,X 采用 -Y 值,但 Y 采用更新后的 X 值而不是前一个值,因此从第三行开始 X = Y。为了解决这个问题,我在更新之前创建了一个数组来保存 X 的值,如下所示:

public Shape rotate(){
        if (this.getShape().equals(SQUARESHAPE)) return this;
        Shape newShape = new Shape();
        newShape.shape = this.shape;
        int[] oldX = {this.x(0), this.x(1), this.x(2), this.x(3)};
        for (int i = 0; i < 4; i++) {
            newShape.setX(i, -y(i));
            newShape.setY(i, oldX[i]);
        }
        return newShape;
}
于 2013-12-01T18:24:29.450 回答
0

删除 rotate 方法,为每个形状和所有 4 个旋转添加一个硬编码的旋转数组。第一个索引应该是旋转索引(0-3)

然后将成员变量添加到形状基类并将旋转更改为:

public void rotate(Boolean rotateRight) {
  if (rotateRight) {
    rotation++;
  else { 
    rotation--;
  }
  if (rotation < 0) {
    rotation = 3;
  }
  if (rotation > 3) {
    rotation = 0;
  }
}

然后做一些新的功能,比如

public int[][] getCurrentRotation() {
  return shapeMatrix[rotation];
}

并使用这个 int[][] (或 int[] 如果你想展平数组)来绘制适当的正方形

于 2013-12-01T08:50:38.420 回答