如何在窗口打开后立即播放我的俄罗斯方块游戏

时间:2015-12-07 05:19:51

标签: java

我有一个功能齐全的俄罗斯方块游戏,以前有开始和暂停按钮。我现在已经删除了它们,但我正在努力使游戏自动运行。 目前这个游戏根本没有开始。

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


public class Tetris extends JPanel {

    //
    // STATIC MEMBERS
    //

    private final static int INITIAL_DELAY = 1000;
    private final static byte ROWS = 20;
    private final static byte COLUMNS = 10;
    private final static int EMPTY = -1;
    private final static int DELETED_ROWS_PER_LEVEL = 5;

    private final static Color PIECE_COLORS[] = {
            new Color(0xFF00FF), // fucia
            new Color(0xDC143C), // crimson
            new Color(0x00CED1), // dark turquoise
            new Color(0xFFD700), // gold
            new Color(0x32CD32), // lime green
            new Color(0x008080), // teal
            new Color(0xFFA500), // orange
    };

    private final static Color BACKGROUND_COLORS[] = {
            new Color(0xFFDAB9), // peachpuff
            new Color(0xFFC0CB), // pink
            new Color(0xFF99CC), // hot pink
            new Color(0x0099CC), // sky blue
            new Color(0x9966CC), // lavender
    };

    private final static Color BACKGROUND_COLOR = new Color(0x99FFCC);

    //   *    **   *    *    *    *
    //   *    *    *    **   **   **   **
    //   *    *    **    *   *    *    **
    //   *
    //   0    1    2    3    4    5    6
    private final static boolean PIECE_BITS[][][] = {

            {
                    {false, true, false, false},
                    {false, true, false, false},
                    {false, true, false, false},
                    {false, true, false, false},
            },
            {
                    {false, false, false, false},
                    {false, true, true, false},
                    {false, true, false, false},
                    {false, true, false, false},
            },
            {
                    {false, false, false, false},
                    {false, true, false, false},
                    {false, true, false, false},
                    {false, true, true, false},
            },
            {
                    {false, false, false, false},
                    {false, true, false, false},
                    {false, true, true, false},
                    {false, false, true, false},
            },
            {
                    {false, false, false, false},
                    {false, false, true, false},
                    {false, true, true, false},
                    {false, true, false, false},
            },
            {
                    {false, false, false, false},
                    {false, true, false, false},
                    {false, true, true, false},
                    {false, true, false, false},
            },
            {
                    {false, false, false, false},
                    {false, false, false, false},
                    {false, true, true, false},
                    {false, true, true, false},
            },
    };

    private static boolean tmp_grid[][] = new boolean[4][4]; // scratch space
    private static Random random = new Random();

    private static class TetrisLabel extends Label {
        private final static Font LABEL_FONT = new Font("Serif", Font.BOLD, 18);
        private TetrisLabel(String text) {
            super(text);
            setFont(LABEL_FONT);
        }
        private void addValue(int val) {
            setText(Integer.toString((Integer.parseInt(getText())) + val ));
        }
    }

    //
    // INSTANCE DATA
    //

    private int grid[][] = new int[ROWS][COLUMNS];
    private int next_piece_grid[][] = new int[4][4];
    private int num_rows_deleted = 0;
    private GridCanvas game_grid = new GridCanvas(grid, true);
    private GridCanvas next_piece_canvas = new GridCanvas(next_piece_grid, false);
    private Timer timer;
    private TetrisPiece cur_piece;
    private TetrisPiece next_piece = randomPiece();
    private TetrisLabel rows_deleted_label = new TetrisLabel("0");
    private TetrisLabel level_label = new TetrisLabel("1");
    private TetrisLabel score_label = new TetrisLabel("0");
    private TetrisLabel high_score_label = new TetrisLabel("");

    //
    // INNER CLASSES
    //

    private class TetrisButton extends Button {
        public TetrisButton(String label) {
            super(label);
        }
        public Dimension getPreferredSize() {
            return new Dimension(120, super.getPreferredSize().height);
        }
    }

    public class TetrisPiece {

        private boolean squares[][];
        private int type;
        private Point position = new Point(3, -4); // -4 to start above top row
        public int getX() { return position.x; }
        public int getY() { return position.y; }
        public void setX(int newx) { position.x = newx; }
        public void setY(int newy) { position.y = newy; }
        public void setPosition(int newx, int newy) { setX(newx); setY(newy);

        }

        public TetrisPiece(int type) {
            this.type = type;
            this.squares = new boolean[4][4];
            for(int i=0; i<4; i++)
                for(int j=0; j<4; j++)
                    this.squares[i][j] = PIECE_BITS[type][i][j];
        }

        public boolean canStepDown() {
            synchronized(timer) {
                cut();
                position.y++;
                boolean OK = canPaste();
                position.y--;
                paste();
                return OK;
            }
        }

        public boolean canPaste() {
            for(int i=0; i<4; i++) {
                for(int j=0; j<4; j++) {
                    int to_x = j + position.x;
                    int to_y = i + position.y;
                    if(squares[i][j]) { // piece contains this square?
                        if(0 > to_x || to_x >= COLUMNS // square too far left or right?
                                || to_y >= ROWS) // square off bottom?
                        {
                            return false;
                            // note: it's always considered OK to paste a square
                            // *above* the grid though attempting to do so does nothing.
                            // This allows the user to move a piece before it drops
                            // completely into view.
                        }
                        if(to_y >= 0 && grid[to_y][to_x] != EMPTY)
                            return false;
                    }
                }
            }
            return true;
        }

        public void stepDown() {
            position.y++;
        }

        public void cut() {
            for(int i=0; i<4; i++)
                for(int j=0; j<4; j++)
                    if(squares[i][j] && position.y+i>=0)
                        grid[position.y + i][position.x + j] = EMPTY;
        }

        /**
         * Paste the color info of this piece into the given grid
         */
        public void paste(int into[][]) {
            for(int i=0; i<4; i++)
                for(int j=0; j<4; j++)
                    if(squares[i][j] && position.y+i>=0)
                        into[position.y + i][position.x + j] = type;
        }

        /**
         * No argument version assumes pasting into main game grid
         */
        public void paste() {
            paste(grid);
        }

        public void rotate() {
            // copy the piece's data into a temp array
            for(int i=0; i<4; i++)
                for(int j=0; j<4; j++)
                    tmp_grid[i][j] = squares[i][j];
            // copy back rotated 90 degrees
            for(int i=0; i<4; i++)
                for(int j=0; j<4; j++)
                    squares[j][i] = tmp_grid[i][3-j];
        }
        public void rotateBack() {
            // copy originally saved version back
            // this of course assumes this call was preceeded by
            // a call to rotate() for the same piece
            for(int i=0; i<4; i++)
                for(int j=0; j<4; j++)
                    squares[i][j] = tmp_grid[i][j];
        }

        // this method is a bit of a hack to check for the case
        // where a piece may be safely on the grid but have one or more
        // rows of empty squares that are above the grid and therefore OK
        public boolean isTotallyOnGrid() {
            for(int i=0; i<4; i++) {
                if(position.y + i >= 0)
                    return true; //everything from here down is on grid
                // this row is above grid so look for non-empty squares
                for(int j=0; j<4; j++)
                    if(squares[i][j])
                        return false;
            }
            System.err.println("TetrisPiece.isTotallyOnGrid internal error");
            return false;
        }
    } // end class TetrisPiece


    private class Timer extends Thread {
        private long m_delay;
        private boolean m_paused = true;
        private boolean m_fast = false;
        private ActionListener m_cb;
        public Timer(long delay, ActionListener cb) {
            setDelay(delay);
            m_cb = cb;
        }

        public void setPaused(boolean pause) {
            m_paused = pause;
            if(m_paused) {
            }
            else {
                synchronized(this) {
                    this.notify();
                }
            }
        }
        public boolean isPaused() { return m_paused; }
        public void setDelay(long delay) { m_delay = delay; }
        public boolean isRunning() { return !m_paused; }
        public void setFast(boolean fast) {
            m_fast = fast;
            if(m_fast) {
                try {
                    this.checkAccess();
                    this.interrupt(); // no exception, so OK to interrupt
                } catch(SecurityException se) {}
            }
        }
        public boolean isFast() { return m_fast; }
        public void faster() {
            m_delay = (int)(m_delay * .9); //increase the speed exponentially in reverse
        }
        public void run() {
            while(true) {
                try {
                    sleep(m_fast ? 30 : m_delay);
                } catch (Exception e) {}
                if(m_paused) {
                    try {
                        synchronized(this) {
                            this.wait();
                        }
                    } catch(InterruptedException ie) {}
                }
                synchronized(this) {
                    m_cb.actionPerformed(null);
                }
            }
        }
    } // end class Timer

    private class GridCanvas extends DoubleBufferedCanvas {
        private int grid[][];
        private boolean paint_background;
        public GridCanvas(int[][] grid, boolean do_background) {
            this.grid = grid;
            paint_background = do_background;
            clear();
        }

        private void clear() {
            for(int i=0; i<grid.length; i++)
                for(int j=0; j<grid[0].length; j++)
                    grid[i][j] = EMPTY;
        }
        public Dimension getPreferredSize() {
            return new Dimension(grid[0].length * 30, grid.length * 30);
        }
        public void paint(Graphics g) {
            g = this.startPaint(g); // returned g paints into offscreen image
            int width = this.getSize().width;
            int height = this.getSize().height;
            g.clearRect(0, 0, width, height);
            int cell_size, xstart, ystart;
            double panel_aspect_ratio = (double)width/height;
            double grid_aspect_ratio = (double)grid[0].length/grid.length;
            if(panel_aspect_ratio > grid_aspect_ratio) {
                // extra space on sides
                cell_size = (int)((double)height/grid.length + 0.5);
                xstart = (int)(width/2 - (grid[0].length/2.0 * cell_size + 0.5));
                ystart = 0;
            }
            else {
                // extra vertical space
                cell_size = (int)((double)width/grid[0].length + 0.5);
                xstart = 0;
                ystart = (int)(height/2 - (grid.length/2.0 * cell_size + 0.5));
            }
            if(paint_background) {
                g.setColor(BACKGROUND_COLORS[(num_rows_deleted / DELETED_ROWS_PER_LEVEL) % BACKGROUND_COLORS.length]);
                g.fillRect(xstart, ystart, COLUMNS*cell_size, ROWS*cell_size);
            }
            for(int i=0; i<grid.length; i++) {
                for(int j=0; j<grid[0].length; j++) {
                    if(grid[i][j] != EMPTY) {
                        g.setColor(PIECE_COLORS[grid[i][j]]);
                        int x = xstart + j*cell_size;
                        int y = ystart + i*cell_size;
                        g.fill3DRect(x, y, cell_size, cell_size, true);
                    }
                }
            }
            this.endPaint(); // paints accumulated image in one shot
        }
    } // end class GridCanvas



    //
    // INSTANCE METHODS
    //

    private TetrisPiece randomPiece() {
        int rand = Math.abs(random.nextInt());
        return new TetrisPiece(rand % (PIECE_COLORS.length));
    }

    private void installNewPiece() {
        next_piece_canvas.clear();
        cur_piece = next_piece;
        cur_piece.setPosition(3, -4); //-4 to start above top of grid
        if(cur_piece.canPaste()) {
            next_piece = randomPiece();
            next_piece.setPosition(0, 0);
            next_piece.paste(next_piece_grid);
            next_piece_canvas.repaint();
        }
        else
            gameOver();
    }

    private void gameOver() {
        System.out.println("Game Over!");
        timer.setPaused(true);
        int score = Integer.parseInt(score_label.getText());
        int high_score = high_score_label.getText().length() > 0 ?
                Integer.parseInt(high_score_label.getText()) : 0;
        if(score > high_score)
            high_score_label.setText("" + score);

    }

    private boolean rowIsFull(int row) {
        for(int i=0; i<COLUMNS; i++)
            if(grid[row][i] == EMPTY)
                return false;
        return true;
    }

    private int countFullRows() {
        int n_full_rows = 0;
        for(int i=0; i<ROWS; i++)
            if(rowIsFull(i))
                n_full_rows++;
        return n_full_rows;
    }

    private void removeRow(int row) {
        for(int j=0; j<COLUMNS; j++)
            grid[row][j] = EMPTY;
        for(int i=row; i>0; i--) {
            for(int j=0; j<COLUMNS; j++) {
                grid[i][j] = grid[i-1][j];
            }
        }
    }

    private void removeFullRows() {
        int n_full = countFullRows();
        score_label.addValue((int) (10 * Math.pow(2, n_full) - 10)); //give points exponentially
        if(n_full == 0)
            return;
        if(num_rows_deleted / DELETED_ROWS_PER_LEVEL != (num_rows_deleted+n_full) / DELETED_ROWS_PER_LEVEL) {
            timer.faster();
            level_label.addValue(n_full / DELETED_ROWS_PER_LEVEL + 1);
            level_label.repaint();
        }
        rows_deleted_label.addValue(n_full);
        num_rows_deleted += n_full;
        for(int i=ROWS-1; i>=0; i--)
            while(rowIsFull(i))
                removeRow(i);
        game_grid.repaint();
    }

    public void start() {
        timer = new Timer(INITIAL_DELAY, new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                synchronized(timer) {
                    if(cur_piece.canStepDown()) {
                        cur_piece.cut();
                        cur_piece.stepDown();
                        cur_piece.paste();
                    }
                    else { // it hit something
                        timer.setFast(false);
                        if( ! cur_piece.isTotallyOnGrid())
                            gameOver();
                        else {
                            removeFullRows();
                            installNewPiece();
                        }
                    }
                }
                game_grid.repaint();
            }
        });
        timer.start(); // pauses immediately
    }



    public void init() {

        installNewPiece();


        //create key listener for rotating, moving left, moving right
        KeyListener key_listener = new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if(timer.isPaused()) //don't do anything if game is paused
                    return;
                if (e.getKeyCode() == 37 || e.getKeyCode() == 39) { //left or right arrow pressed
                    int dir = e.getKeyCode() == 37 ? -1 : 1;
                    synchronized(timer) {
                        cur_piece.cut();
                        cur_piece.setX(cur_piece.getX() + dir); // try to move
                        if( ! cur_piece.canPaste())
                            cur_piece.setX(cur_piece.getX() - dir); // undo move
                        cur_piece.paste();
                    }
                    game_grid.repaint();
                }
                else if (e.getKeyCode() == 38) { //rotate
                    synchronized(timer) {
                        cur_piece.cut();
                        cur_piece.rotate();
                        if( ! cur_piece.canPaste())
                            cur_piece.rotateBack();
                        cur_piece.paste();
                    }
                    game_grid.repaint();
                }
                if (e.getKeyCode() == 40) { //down arrow pressed; drop piece
                    timer.setFast(true);
                }
            }
        };

        // add the key listener to all components that might get focus
        // so that it'll work regardless of which has focus
        //start_newgame_butt.addKeyListener(key_listener);
        //pause_resume_butt.addKeyListener(key_listener);



        // finaly, add all the main panels to the applet panel
        this.setLayout(new GridLayout(1, 2));
        this.add(game_grid);
        this.setBackground(BACKGROUND_COLOR);
        this.validate();
    }


    public static void main(String[] args) {

        Frame frame = new Frame("Joshua Ogunnote - 1404528");
        Tetris tetris = new Tetris();
        frame.add(tetris);
        tetris.init();
        tetris.start();


        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        frame.setSize(250,500);
        frame.setResizable(false);
        frame.setVisible(true);
    }
} // end class Tetris


class DoubleBufferedCanvas extends Canvas {
    private Image mActiveOffscreenImage = null;
    private Dimension mOffscreenSize = new Dimension(-1,-1);
    private Graphics mActiveOffscreenGraphics = null;
    private Graphics mSystemGraphics = null;

    DoubleBufferedCanvas() {
        /*
        this.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                repaint();
            }
        });*/
    }

    /**
     * NOTE: when extending applets:
     * this overrides update() to *not* erase the background before painting
     */
    public void update(Graphics g) {
        paint(g);
    }

    public Graphics startPaint (Graphics sysgraph) {
        mSystemGraphics = sysgraph;
        // Initialize if this is the first pass or the size has changed
        Dimension d = getSize();
        if ((mActiveOffscreenImage == null) ||
                (d.width != mOffscreenSize.width) ||
                (d.height != mOffscreenSize.height))
        {
            mActiveOffscreenImage = createImage(d.width, d.height);
            mActiveOffscreenGraphics = mActiveOffscreenImage.getGraphics();
            mOffscreenSize = d;
            mActiveOffscreenGraphics.setFont(getFont());
        }
        //mActiveOffscreenGraphics.clearRect(0, 0, mOffscreenSize.width, mOffscreenSize.height);
        return mActiveOffscreenGraphics;
    }

    public void endPaint () {
        // Start copying the offscreen image to this canvas
        // The application will begin drawing into the other one while this happens
        mSystemGraphics.drawImage(mActiveOffscreenImage, 0, 0, null);
    }
}

1 个答案:

答案 0 :(得分:0)

您的问题在于事件调度线程。 Swing不是线程安全的,所以为了确保在应用程序启动时一切顺利,请尝试使用runnables的run()方法将框架显示代码包含在主体中,如下所示:

public static void main(String[]args){

        javax.swing.SwingUtilities.invokeLater(){

               @Override
               public void run(){
                     Frame frame = new Frame("Joshua Ogunnote - 1404528");
                     Tetris tetris = new Tetris();
                     frame.add(tetris);
                     frame.setVisible(true);
               }

        }
}