Java 俄罗斯方 block 旋转错误

标签 java swing debugging rotation tetris

我在玩俄罗斯方 block 时遇到一些问题。首先,我有一个 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();
        }
    }
}

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

这应该是我的线条形状:

line

这是我的 L 形(黄色):

l

请注意,这不仅仅是一个图形错误,游戏将元素分别视为一个或两个方 block 。 我花了几个小时查看我的代码,看看问题出在哪里,但我没有运气。任何帮助将不胜感激

最佳答案

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

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;
}

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

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;
}

关于Java 俄罗斯方 block 旋转错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20309110/

相关文章:

java - 如何将按钮和 Canvas 放入jframe中? ( java Swing )

java - 调整 JFrame 大小时调整 JFrame 上的图像和 JPanel 大小

linux - 如何正确调试 bash 脚本

java - 将 commons DBCP 从 1.2 升级到 1.4,我应该害怕吗?

java - 如何使用JAVA编写更优化和通用而不是200个if条件?

java - SwingWorker 结束,PropertyChangeListener 监听,但我如何返回 EDT?

debugging - 如何以编程方式检测nodejs中的 Debug模式?

java - 如何在运行应用程序时修复 android studio 3.6.2 版中的 "Cannot parse result path string:"错误?

java - Hibernate 不连接 MySql

java - java for循环内递归的时间复杂度