Adding additional shapes in a tetris project. loop logic assistance

后端 未结 1 524
不思量自难忘°
不思量自难忘° 2021-01-27 10:39

I am creating a tetris clone as a personal project to help me get better at drawing images, moving them, and to learn collision detection.

Everything is going fine but I

相关标签:
1条回答
  • 2021-01-27 11:27

    I just can't figure out how to loop it so that once that shape stops moving it adds another shape at the top of the screen.

    Well in your Timer logic you have:

    component.moveRectangleBy(dx,dy);
    

    So this assumes you always have an "active" component. You need the ability to determine when the component is at the bottom so you can reset the component.

    So you might restructure your listener code to look something like:

    if (component == null)
        component = // a new random shape
    else
    {
        component.moveRectangleBy(...);
    
        if (component.isAtBottom()) // a method you will need to write
            component == null;
    }
    

    For what its worth, I have also played with my own Tetris game. It currently:

    1. adds random pieces
    2. moves pieces down the board
    3. usees the 4 arrow keys to move/rotate a tetris piece
    4. removes full lines

    The basic design is in 4 classes:

    1. TetrisIcon - paints a square with a border
    2. TetrisPiece - a 4x4 array representation of a tetris piece. A value of 1 indicates the TetricIcon should be painted.
    3. TetrisBoard - Contains a List of TetrisIcons to be painted as well as the current TetrisPiece that moves down the board. When the TetrisPiece reaches the bottom, its individual TetrisIcons are moved to the board.
    4. Tetris - builds the frame and starts the game.

    If you want to play with it, have fun:

    Tetris:

    import java.awt.*;
    import java.awt.event.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import javax.swing.*;
    import javax.swing.event.*;
    import javax.swing.border.*;
    import java.awt.geom.*;
    
    public class Tetris extends JPanel
    {
        private final static int TETRIS_ICON_SIZE = 20;
    
        private List<TetrisPiece> tetrisPieces = new ArrayList<TetrisPiece>();
        private TetrisBoard board;
        private Random random = new Random();
    
        public Tetris()
        {
            setLayout( new BorderLayout() );
    
            createTetrisPieces();
    
            board = new TetrisBoard(20, 10, 20);
            add(board, BorderLayout.LINE_START);
    /*
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 5, 5);
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 5, 6);
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 6, 5);
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 0, 0);
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 0, 19);
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 9, 0);
            board.setTetrisIconAt(new TetrisIcon(Color.RED, TETRIS_ICON_SIZE), 9, 19);
    
            board.setTetrisPiece( tetrisPieces.get(1) );
    */
            JButton start = new JButton( new StartAction() );
            add(start, BorderLayout.PAGE_END);
        }
    
        private void createTetrisPieces()
        {
            int[][] shape =
            {
                {0, 1, 0, 0},
                {0, 1, 0, 0},
                {0, 1, 0, 0},
                {0, 1, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.RED, TETRIS_ICON_SIZE)) );
    
            shape = new int[][]
            {
                {0, 1, 0, 0},
                {0, 1, 0, 0},
                {0, 1, 1, 0},
                {0, 0, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.YELLOW, TETRIS_ICON_SIZE)) );
    
            shape = new int[][]
            {
                {0, 0, 1, 0},
                {0, 0, 1, 0},
                {0, 1, 1, 0},
                {0, 0, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.MAGENTA, TETRIS_ICON_SIZE)) );
    
            shape = new int[][]
            {
                {0, 0, 0, 0},
                {0, 1, 1, 0},
                {0, 1, 1, 0},
                {0, 0, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.CYAN, TETRIS_ICON_SIZE)) );
    
            shape = new int[][]
            {
                {0, 0, 0, 0},
                {0, 1, 0, 0},
                {1, 1, 1, 0},
                {0, 0, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.WHITE, TETRIS_ICON_SIZE)) );
    
            shape = new int[][]
            {
                {0, 0, 0, 0},
                {0, 1, 1, 0},
                {1, 1, 0, 0},
                {0, 0, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.BLUE, TETRIS_ICON_SIZE)) );
    
            shape = new int[][]
            {
                {0, 0, 0, 0},
                {1, 1, 0, 0},
                {0, 1, 1, 0},
                {0, 0, 0, 0}
            };
    
            tetrisPieces.add( new TetrisPiece(shape, new TetrisIcon(Color.GREEN, TETRIS_ICON_SIZE)) );
        }
    
        class StartAction extends AbstractAction
        {
            public StartAction()
            {
                super("Start Game");
            }
    
            @Override
            public void actionPerformed(ActionEvent e)
            {
                new Timer(1000, new AbstractAction()
                {
                    @Override
                    public void actionPerformed(ActionEvent e2)
                    {
                        if (board.getTetrisPiece() == null)
                        {
                            int piece = random.nextInt( tetrisPieces.size() );
                            board.setTetrisPiece( tetrisPieces.get( piece ) );
                        }
                        else
                        {
                            board.moveShapeDown();
                        }
                    }
                }).start();
            }
        }
    
    
        private static void createAndShowGUI()
        {
    
            JFrame frame = new JFrame("Tetris");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new Tetris());
            frame.setLocationByPlatform( true );
            frame.pack();
            frame.setVisible( true );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater( () -> createAndShowGUI() );
    /*
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowGUI();
                }
            });
    */
        }
    }
    

    TetrisBoard:

    import java.awt.*;
    import java.awt.event.*;
    import java.util.List;
    import java.util.ArrayList;
    import javax.swing.*;
    
    class TetrisBoard extends JPanel
    {
        private List<TetrisIcon[]> board;
    
        private int rows;
        private int columns;
        private int size;
    
        private TetrisPiece tetrisPiece;
    
        public TetrisBoard(int rows, int columns, int size)
        {
            this.rows = rows;
            this.columns = columns;
            this.size = size;
    
            board = new ArrayList<TetrisIcon[]>(rows);
    
            for (int i = 0; i < rows; i++)
                board.add( new TetrisIcon[columns] );
    
            setBackground( Color.BLACK );
    
            addKeyBindings();
        }
    
        private void addKeyBindings()
        {
            InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap();
    
            String leftName = "LEFT";
            KeyStroke leftKeyStroke = KeyStroke.getKeyStroke( leftName );
            inputMap.put(leftKeyStroke, leftName);
            actionMap.put(leftName, new AbstractAction()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    moveShapeLeft();
                }
            });
    
            String rightName = "RIGHT";
            KeyStroke rightKeyStroke = KeyStroke.getKeyStroke( rightName );
            inputMap.put(rightKeyStroke, rightName);
            actionMap.put(rightName, new AbstractAction()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    moveShapeRight();
                }
            });
    
            String downName = "DOWN";
            KeyStroke downKeyStroke = KeyStroke.getKeyStroke( downName );
            inputMap.put(downKeyStroke, downName);
            actionMap.put(downName, new AbstractAction()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
    //              moveShapeDown();
                    dropShape();
                }
            });
    
            String upName = "UP";
            KeyStroke upKeyStroke = KeyStroke.getKeyStroke( upName );
            inputMap.put(upKeyStroke, upName);
            actionMap.put(upName, new AbstractAction()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    rotateShape();
                }
            });
        }
    
        public TetrisPiece getTetrisPiece()
        {
            return tetrisPiece;
        }
    
        public void setTetrisPiece(TetrisPiece tetrisPiece)
        {
            this.tetrisPiece = new TetrisPiece(tetrisPiece.getShape(), tetrisPiece.getIcon());
            this.tetrisPiece.setLocation( new Point(4, 0) );
            repaint();
        }
    
        public void setTetrisIconAt(TetrisIcon icon, int x, int y)
        {
            TetrisIcon[] row = board.get(y);
            row[x] = icon;
        }
    
        public TetrisIcon getTetrisIconAt(int x, int y)
        {
            TetrisIcon[] row = board.get(y);
    
            return row[x];
        }
    
        public void moveShapeLeft()
        {
            if (tetrisPiece == null) return;
    
            Point possibleLocation = new Point(tetrisPiece.getX() - 1, tetrisPiece.getY());
    
            if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
            {
                tetrisPiece.setLocation( possibleLocation );
                repaint();
            }
        }
    
        public void moveShapeRight()
        {
            if (tetrisPiece == null) return;
    
            Point possibleLocation = new Point(tetrisPiece.getX() + 1, tetrisPiece.getY());
    
            if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
            {
                tetrisPiece.setLocation( possibleLocation );
                repaint();
            }
        }
    
        public void dropShape()
        {
            if (tetrisPiece == null) return;
    
            Point possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
    
            while ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
            {
                moveShapeDown();
                possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
            }
    
    //      addTetrisPieceToBoard();
    //      tetrisPiece = null;
        }
    
        public void moveShapeDown()
        {
            if (tetrisPiece == null) return;
    
            Point possibleLocation = new Point(tetrisPiece.getX(), tetrisPiece.getY() + 1);
    
            if ( canMoveShape(possibleLocation, tetrisPiece.getShape()) )
            {
                tetrisPiece.setLocation( possibleLocation );
                repaint();
            }
            else
            {
                tetrisPieceAtBottom();
            }
        }
    
        private void tetrisPieceAtBottom()
        {
            Point location = tetrisPiece.getLocation();
            int row = Math.min(rows, location.y + 4);
            row--;
    
            addTetrisPieceToBoard();
    
            int rowsRemoved = 0;
    
    
            for (; row >= location.y; row--)
            {
    //          System.out.println(row);
                TetrisIcon[] icons = board.get(row);
    
                if ( fullRow(row) )
                {
                    board.remove(row);
                    rowsRemoved++;
                }
            }
    
            for (int i = 0; i < rowsRemoved; i++)
                board.add(0, new TetrisIcon[columns]);
    
            if (rowsRemoved > 0)
                repaint();
        }
    
        private boolean fullRow(int row)
        {
            for (int column = 0; column < columns; column++)
            {
    //          System.out.println(row + " : " + column);
                if ( getTetrisIconAt(column, row) == null)
                    return false;
            }
    
            return true;
        }
    
        private void addTetrisPieceToBoard()
        {
            int x = tetrisPiece.getX();
            int y = tetrisPiece.getY();
    
            for (int r = 0; r < tetrisPiece.getRows(); r++)
            {
                for (int c = 0; c < tetrisPiece.getColumns(); c++)
                {
                    TetrisIcon icon = tetrisPiece.getIconAt(r, c);
    
                    if (icon != null)
                    {
                        setTetrisIconAt(icon, x, y);
                    }
    
                    x++;
                }
    
                x = tetrisPiece.getX();
                y++;
            }
    
            tetrisPiece = null;
        }
    
        public void rotateShape()
        {
            if (tetrisPiece == null) return;
    
            int[][] rotatedShape = tetrisPiece.getRotatedShape();
    
            if ( canMoveShape(tetrisPiece.getLocation(), rotatedShape) )
            {
                tetrisPiece.setShape( rotatedShape );
                repaint();
            }
        }
    
        private boolean canMoveShape(Point location, int[][] shape)
        {
            for (int r = 0; r < shape.length; r ++)
            {
                for (int c = 0; c < shape.length; c++)
                {
                    if (shape[r][c] == 1)
                    {
                        int x = location.x + c;
                        int y = location.y + r;
    
                        //  Past left edge
    
                        if (x < 0) return false;
    
                        //  Past right edge
    
                        if (x >= columns) return false;
    
                        //  Past bottom edge
    
                        if (y >= rows) return false;
    
                        //  Collision with TetrisIcon
    
                        if (getTetrisIconAt(x, y) != null) return false;
                    }
                }
            }
    
            return true;
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            int width = (columns * size) + columns - 1;
            int height = (rows * size) + rows - 1;
    
            return new Dimension(width, height);
        }
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent( g );
    
            int x = 0;
            int y = 0;
            int offset = size + 1;
    
            for (int r = 0; r < rows; r++)
            {
                TetrisIcon[] row = board.get(r);
    
                for (int c = 0; c < row.length; c++)
                {
                    TetrisIcon icon = row[c];
    
                    if (icon != null)
                    {
                        icon.paintIcon(this, g, x, y);
                    }
    
                    x += offset;
                }
    
                x = 0;
                y += offset;
            }
    
            // paint shape
    
            if (tetrisPiece != null)
            {
                paintShape(g, offset);
            }
        }
    
        private void paintShape(Graphics g, int offset)
        {
            int x = tetrisPiece.getX() * offset;
            int y = tetrisPiece.getY() * offset;
    
            for (int r = 0; r < tetrisPiece.getRows(); r++)
            {
                for (int c = 0; c < tetrisPiece.getColumns(); c++)
                {
                    TetrisIcon icon = tetrisPiece.getIconAt(r, c);
    
                    if (icon != null)
                    {
                        icon.paintIcon(this, g, x, y);
                    }
    
                    x += offset;
                }
    
                x = tetrisPiece.getX() * offset;
                y += offset;
            }
        }
    }
    

    TetrisPiece:

    import java.awt.Point;
    
    public class TetrisPiece
    {
        private int[][] shape;
        private TetrisIcon icon;
        private Point location = new Point();
    
        public TetrisPiece(int[][] shape, TetrisIcon icon)
        {
            setShape(shape);
            this.icon = icon;
        }
    
        public TetrisIcon getIcon()
        {
            return icon;
        }
    
        public int[][] getShape()
        {
            return shape;
        }
    
        public void setShape(int[][] shape)
        {
            this.shape = shape;
        }
    
        public TetrisIcon getIconAt(int x, int y)
        {
            return  (shape[x][y] == 1) ? icon : null;
        }
    
        public Point getLocation()
        {
            return location;
        }
    
        public void setLocation(Point location)
        {
            this.location = location;
        }
    
        public int getX()
        {
            return location.x;
        }
    
        public int getY()
        {
            return location.y;
        }
    
        public int getRows()
        {
            return shape.length;
        }
    
        public int getColumns()
        {
            return shape[0].length;
        }
    
        public int[][] getRotatedShape()
        {
            int[][] rotatedShape = new int[shape.length][shape[0].length];
    
            int x = 0;
            int y = 0;
    
            for (int c = shape.length - 1; c >= 0; c--)
            {
                for (int r = 0; r < shape[0].length; r++)
                {
                    rotatedShape[x][y] = shape[r][c];
                    y++;
                }
    
                x++;
                y = 0;
            }
    
            return rotatedShape;
        }
    
    }
    

    TetrisIcon:

    import java.awt.*;
    import javax.swing.*;
    
    public class TetrisIcon implements Icon
    {
        private Color color;
        private int size;
    
        public TetrisIcon(Color color, int size)
        {
            this.color = color;
            this.size = size;
        }
    
        public int getIconWidth()
        {
            return size;
        }
    
        public int getIconHeight()
        {
            return size;
        }
    
        public void paintIcon(Component c, Graphics g, int x, int y)
        {
            int width = getIconWidth() - 1;
            int height = getIconHeight() - 1;
    
            g.translate(x, y);
    
            g.setColor(color);
            g.fillRect(0, 0, width, height);
    
            g.setColor(Color.LIGHT_GRAY);
            g.drawLine(0, 0, width, 0);
            g.drawLine(0, 0, 0, height);
    
            g.setColor(Color.DARK_GRAY);
            g.drawLine(width, 0, width, height);
            g.drawLine(0, height, width, height);
    
            g.translate(-x, -y);
        }
    }
    
    0 讨论(0)
提交回复
热议问题