【Java遊戲】java俄羅斯方塊!

六星_研鑫發表於2020-07-31

目錄

            一 心得


           二、遊戲例項


           三、程式碼


一、心得

      在學習Java的過程中,難免會遇到很多的問題,這些問題可能會困擾你許久,為此我有個Java學習交流群( 925050116),裡面都是CSDN的小夥伴,大家互相學習互相交流共同進步,每日分享不同的學習資料。

點選獲取更多素材遊戲原始碼!!

百度盤連結

連結: 密碼:9ujo

 

二、遊戲例項

遊戲截圖

目錄結構

 

三、程式碼

1、主介面 Tetris.java

package com.hsj.tetris;
 
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
 
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
 * 俄羅斯方塊遊戲皮膚
 *
 */
public class Tetris extends JPanel {
    /** 正在下落方塊 */
    private Tetromino tetromino;
    /** 下一個下落方塊 */
    private Tetromino nextOne;
    /** 行數 */
    public static final int ROWS = 20;
    /** 列數 */
    public static final int COLS = 10;
    /** 牆 */
    private Cell[][] wall = new Cell[ROWS][COLS];
    /** 消掉的行數 */
    private int lines;
    /** 分數 */
    private int score;
 
    public static final int CELL_SIZE = 26;
 
    private static Image background;//背景圖片
    public static Image I;
    public static Image J;
    public static Image L;
    public static Image S;
    public static Image Z;
    public static Image O;
    public static Image T;
    static{//載入靜態資源的,載入圖片
        //建議將圖片放到 Tetris.java 同包中!
        //從包中載入圖片物件,使用Swing API實現
//        Toolkit toolkit = Toolkit.getDefaultToolkit();
//        background = toolkit.getImage(
//                Tetris.class.getResource("tetris.png"));
//        T = toolkit.getImage(Tetris.class.getResource("T.png"));
//        S = toolkit.getImage(Tetris.class.getResource("S.png"));
//        Z = toolkit.getImage(Tetris.class.getResource("Z.png"));
//        L = toolkit.getImage(Tetris.class.getResource("L.png"));
//        J = toolkit.getImage(Tetris.class.getResource("J.png"));
//        I = toolkit.getImage(Tetris.class.getResource("I.png"));
//        O = toolkit.getImage(Tetris.class.getResource("O.png"));
        //import javax.imageio.ImageIO;
        try{
            background = ImageIO.read(
                Tetris.class.getResource("tetris.png"));
            T=ImageIO.read(Tetris.class.getResource("T.png"));
            I=ImageIO.read(Tetris.class.getResource("I.png"));
            S=ImageIO.read(Tetris.class.getResource("S.png"));
            Z=ImageIO.read(Tetris.class.getResource("Z.png"));
            L=ImageIO.read(Tetris.class.getResource("L.png"));
            J=ImageIO.read(Tetris.class.getResource("J.png"));
            O=ImageIO.read(Tetris.class.getResource("O.png"));
        }catch(Exception e){
            e.printStackTrace();
        }
    }
 
    public void action(){
        //tetromino = Tetromino.randomTetromino();
        //nextOne = Tetromino.randomTetromino();
        //wall[19][2] = new Cell(19,2,Tetris.T);
        startAction();
        repaint();
        KeyAdapter l = new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                int key = e.getKeyCode();
                if(key == KeyEvent.VK_Q){
                    System.exit(0);//退出當前的Java程式
                }
                if(gameOver){
                    if(key==KeyEvent.VK_S){
                        startAction();
                    }
                    return;
                }
                //如果暫停並且按鍵是[C]就繼續動作
                if(pause){//pause = false
                    if(key==KeyEvent.VK_C){    continueAction();    }
                    return;
                }
                //否則處理其它按鍵
                switch(key){
                case KeyEvent.VK_RIGHT: moveRightAction(); break;
                case KeyEvent.VK_LEFT: moveLeftAction(); break;
                case KeyEvent.VK_DOWN: softDropAction() ; break;
                case KeyEvent.VK_UP: rotateRightAction() ; break;
                case KeyEvent.VK_Z: rotateLeftAction() ; break;
                case KeyEvent.VK_SPACE: hardDropAction() ; break;
                case KeyEvent.VK_P: pauseAction() ; break;
                }
                repaint();
            }
        };
        this.requestFocus();
        this.addKeyListener(l);
    }
 
    public void paint(Graphics g){
        g.drawImage(background, 0, 0, null);//使用this 作為觀察者
        g.translate(15, 15);//平移繪圖座標系
        paintTetromino(g);//繪製正在下落的方塊
        paintWall(g);//畫牆
        paintNextOne(g);
        paintScore(g);
    }
    public static final int FONT_COLOR = 0x667799;
    public static final int FONT_SIZE = 0x20;
    private void paintScore(Graphics g) {
        Font f = getFont();//獲取當前的 皮膚預設字型
        Font font = new Font(
                f.getName(), Font.BOLD, FONT_SIZE);
        int x = 290;
        int y = 162;
        g.setColor(new Color(FONT_COLOR));
        g.setFont(font);
        String str = "SCORE:"+this.score;
        g.drawString(str, x, y);
        y+=56;
        str = "LINES:"+this.lines;
        g.drawString(str, x, y);
        y+=56;
        str = "[P]Pause";
        if(pause){str = "[C]Continue";}
        if(gameOver){    str = "[S]Start!";}
        g.drawString(str, x, y);
    }
 
    private void paintNextOne(Graphics g) {
        Cell[] cells = nextOne.getCells();
        for(int i=0; i<cells.length; i++){
            Cell c = cells[i];
            int x = (c.getCol()+10) * CELL_SIZE-1;
            int y = (c.getRow()+1) * CELL_SIZE-1;
            g.drawImage(c.getImage(), x, y, null);
        }
    }
 
    private void paintTetromino(Graphics g) {
        Cell[] cells = tetromino.getCells();
        for(int i=0; i<cells.length; i++){
            Cell c = cells[i];
            int x = c.getCol() * CELL_SIZE-1;
            int y = c.getRow() * CELL_SIZE-1;
            //g.setColor(new Color(c.getColor()));
            //g.fillRect(x, y, CELL_SIZE, CELL_SIZE);
            g.drawImage(c.getImage(), x, y, null);
        }
    }
 
    //在 Tetris 類 中新增 方法 paintWall
    private void paintWall(Graphics g){
        for(int row=0; row<wall.length; row++){
            //迭代每一行, i = 0 1 2 ... 19
            Cell[] line = wall[row];
            //line.length = 10
            for(int col=0; col<line.length; col++){
                Cell cell = line[col];
                int x = col*CELL_SIZE;
                int y = row*CELL_SIZE;
                if(cell==null){
                    //g.setColor(new Color(0));
                    //畫方形
                    //g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
                }else{
                    g.drawImage(cell.getImage(), x-1, y-1, null);
                }
            }
        }
    }
    /**
     * 在 Tetris(俄羅斯方塊) 類中增加方法
     * 這個方法的功能是:軟下落的動作 控制流程
     * 完成功能:如果能夠下落就下落,否則就著陸到牆上,
     *   而新的方塊出現並開始落下。
     */
    public void softDropAction(){
        if(tetrominoCanDrop()){
            tetromino.softDrop();
        }else{
            tetrominoLandToWall();
            destroyLines();//破壞滿的行
            checkGameOver();
            tetromino = nextOne;
            nextOne = Tetromino.randomTetromino();
        }
    }
    /** 銷燬已經滿的行,並且計分
     * 1)迭代每一行
     * 2)如果(檢查)某行滿是格子了 就銷燬這行
     **/
    public void destroyLines(){
        int lines = 0;
        for(int row = 0; row<wall.length; row++){
            if(fullCells(row)){
                deleteRow(row);
                lines++;
            }
        }
        // lines = ?
        this.lines += lines;//0 1 2 3 4
        this.score += SCORE_TABLE[lines];
    }
    private static final int[] SCORE_TABLE={0,1,10,30,200};
    //                                      0 1  2  3  4
 
    public boolean fullCells(int row){
        Cell[] line = wall[row];
        for(int i=0; i<line.length; i++){
            if(line[i]==null){//如果有空格式就不是滿行
                return false;
            }
        }
        return true;
    }
    public void deleteRow(int row){
        for(int i=row; i>=1; i--){
            //複製 [i-1] -> [i]
            System.arraycopy(wall[i-1], 0, wall[i], 0, COLS);
        }
        Arrays.fill(wall[0], null);
    }
 
    /** 檢查當前的4格方塊能否繼續下落 */
    public boolean tetrominoCanDrop(){
        Cell[] cells = tetromino.getCells();
        for(int i = 0; i<cells.length; i++){
            Cell cell = cells[i];
            int row = cell.getRow(); int col = cell.getCol();
            if(row == ROWS-1){return false;}//到底就不能下降了
        }
        for(int i = 0; i<cells.length; i++){
            Cell cell = cells[i];
            int row = cell.getRow(); int col = cell.getCol();
            if(wall[row+1][col] != null){
                return false;//下方牆上有方塊就不能下降了
            }
        }
        return true;
    }
    /** 4格方塊著陸到牆上 */
    public void tetrominoLandToWall(){
        Cell[] cells = tetromino.getCells();
        for(int i=0; i<cells.length; i++){
            Cell cell = cells[i];
            int row = cell.getRow();
            int col = cell.getCol();
            wall[row][col] = cell;
        }
    }
 
    public void moveRightAction(){
        tetromino.moveRight();
        if(outOfBound() || coincide()){
            tetromino.moveLeft();
        }
    }
    public void moveLeftAction(){
        tetromino.moveLeft();
        if(outOfBound() || coincide()){
            tetromino.moveRight();
        }
    }
    /** ... */
    private boolean outOfBound(){
        Cell[] cells = tetromino.getCells();
        for(int i=0; i<cells.length; i++){
            Cell cell = cells[i];
            int col = cell.getCol();
            if(col<0 || col>=COLS){
                return true;//出界了
            }
        }
        return false;
    }
    private boolean coincide(){
        Cell[] cells = tetromino.getCells();
        //for each 迴圈、迭代,簡化了"陣列迭代書寫"
        for(Cell cell: cells){//Java 5 以後提供增強版for迴圈
            int row = cell.getRow();
            int col = cell.getCol();
            if(row<0 || row>=ROWS || col<0 || col>=COLS ||
                    wall[row][col]!=null){
                return true; //牆上有格子物件,發生重合
            }
        }
        return false;
    }
    /** 向右旋轉動作 */
    public void rotateRightAction(){
        //旋轉之前
        //System.out.println(tetromino);
        tetromino.rotateRight();
        //System.out.println(tetromino);
        //旋轉之後
        if(outOfBound() || coincide()){
            tetromino.rotateLeft();
        }
    }
 
    /** Tetris 類中新增的方法 */
    public void rotateLeftAction(){
        tetromino.rotateLeft();
        if(outOfBound() || coincide()){
            tetromino.rotateRight();
        }
    }
    public void hardDropAction(){
        while(tetrominoCanDrop()){
            tetromino.softDrop();
        }
        tetrominoLandToWall();
        destroyLines();
        checkGameOver();
        tetromino = nextOne;
        nextOne = Tetromino.randomTetromino();
    }
 
    private boolean pause;
    private boolean gameOver;
    private Timer timer;
    /** Tetris 類中新增的方法, 用於啟動遊戲 */
    public void startAction(){
        clearWall();
        tetromino = Tetromino.randomTetromino();
        nextOne = Tetromino.randomTetromino();
        lines = 0; score = 0;    pause=false; gameOver=false;
        timer = new Timer();
        timer.schedule(new TimerTask(){
            public void run() {
                softDropAction();
                repaint();
            }
        }, 700, 700);
    }
 
    private void clearWall(){
        //將牆的每一行的每個格子清理為null
        for(int row=0; row<ROWS; row++){
            Arrays.fill(wall[row], null);
        }
    }
 
    /** 在Tetris 類中新增方法  */
    public void pauseAction(){
        timer.cancel(); //停止定時器
        pause = true;
        repaint();
    }
    public void continueAction(){
        timer = new Timer();
        timer.schedule(new TimerTask() {
            public void run() {
                softDropAction();
                repaint();
            }
        }, 700, 700);
        pause = false;
        repaint();
    }
    /** 在 Tetris 類中新增 方法 */
    public void checkGameOver(){
        if(wall[0][4]==null){
            return;
        }
        gameOver = true;
        timer.cancel();
        repaint();
    }
 
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Tetris tetris = new Tetris();
        frame.add(tetris);
        frame.setSize(525, 550);
        frame.setUndecorated(false);//true去掉視窗框!
        frame.setTitle("俄羅斯方塊");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //Location 位置 RelativeTo相對於
        frame.setLocationRelativeTo(null);//使當前視窗居中
        frame.setVisible(true);
        tetris.action();
    }
}


二、Cell.java

package com.fry.tetris;
 
import java.awt.Image;
 
/**
 * 格子
 * 每一個小格子,就有所在的行 列 和圖片
 */
public class Cell {
    private int row;
    private int col;
    //private int color;
    private Image image;//格子的貼圖
 
    public Cell() {
    }
 
    public Cell(int row, int col, Image image) {
        super();
        this.row = row;
        this.col = col;
        this.image = image;
    }
 
    public int getRow() {
        return row;
    }
 
    public void setRow(int row) {
        this.row = row;
    }
 
    public int getCol() {
        return col;
    }
 
    public void setCol(int col) {
        this.col = col;
    }
 
 
    public Image getImage() {
        return image;
    }
 
    public void setImage(Image image) {
        this.image = image;
    }
 
    public void moveRight(){
        col++;
        //System.out.println("Cell moveRight()" + col);
    }
 
    public void moveLeft(){
        col--;
    }
 
    public void moveDown(){
        row++;
    }
 
    @Override
    public String toString() {
        return "["+row+","+col+"]";
    }
}


三、功能實現 Tetromino.java

package com.fry.tetris;
 
import java.util.Arrays;
import java.util.Random;
 
/**
 * 4格方塊 
 */
public class Tetromino {
    protected Cell[] cells = new Cell[4];
    /** 儲存旋轉的相對於軸位置狀態 */
    protected State[] states;
    
    /** 隨機生成 4格方塊, 使用簡單工廠方法模式! 
     * randomTetromino 隨機生成一個四格方塊 
     * 這個方面的返回值是多型的!
     * */
    public static Tetromino randomTetromino(){
        Random r = new Random();
        int type = r.nextInt(7);
        switch(type){
        case 0: return new T();
        case 1: return new I();
        case 2: return new J();
        case 3: return new L();
        case 4: return new O();
        case 5: return new S();
        case 6: return new Z();
        }
        return null;
    }
    
    public Cell[] getCells() {
        return cells;
    }
 
    /** 下落 */
    public void softDrop(){
        for(int i=0; i<cells.length; i++){
            cells[i].moveDown();
        }
    }
    public void moveRight(){
        //System.out.println("moveRight()");
        for(int i=0; i<cells.length; i++){
            this.cells[i].moveRight();
        }
    } 
    public void moveLeft(){
        for(int i=0; i<cells.length; i++){
            cells[i].moveLeft();
        }
    }
    private int index = 100000;
    /** 在 Tetromino 上新增方法  */
    public void rotateRight() {
        index++;//index = 10001
        // index % states.length = 10001 % 4 = 1
        State s = states[index%states.length];//s1
        // [0] + s1 = [1]
        Cell o = cells[0];//獲取當前的軸
        //軸與相對位置的和作為旋轉以後的格子位置
        cells[1].setRow(o.getRow()+s.row1);
        cells[1].setCol(o.getCol()+s.col1);
        cells[2].setRow(o.getRow()+s.row2);
        cells[2].setCol(o.getCol()+s.col2);
        cells[3].setRow(o.getRow()+s.row3);
        cells[3].setCol(o.getCol()+s.col3);
    }
    /** 在 Tetromino 上新增方法  */
    public void rotateLeft() {
        index--;//index = 10001
        // index % states.length = 10001 % 4 = 1
        State s = states[index%states.length];//s1
        // [0] + s1 = [1]
        Cell o = cells[0];//獲取當前的軸
        cells[1].setRow(o.getRow()+s.row1);
        cells[1].setCol(o.getCol()+s.col1);
        cells[2].setRow(o.getRow()+s.row2);
        cells[2].setCol(o.getCol()+s.col2);
        cells[3].setRow(o.getRow()+s.row3);
        cells[3].setCol(o.getCol()+s.col3);
    }
    
    @Override
    public String toString() {
        return Arrays.toString(cells); 
    }
    
    /** Tetromino 類中新增的 內部類 用於記錄旋轉狀態 */
    protected class State{
        int row0,col0,row1,col1,row2,col2,row3,col3;
 
        public State(int row0, int col0, int row1, int col1,
                int row2, int col2,
                int row3, int col3) {
            this.row0 = row0;
            this.col0 = col0;
            this.row1 = row1;
            this.col1 = col1;
            this.row2 = row2;
            this.col2 = col2;
            this.row3 = row3;
            this.col3 = col3;
        }      
    }
    
}//Tetromino 類的結束
class T extends Tetromino{
    public T() {
        cells[0] = new Cell(0, 4, Tetris.T);
        cells[1] = new Cell(0, 3, Tetris.T);
        cells[2] = new Cell(0, 5, Tetris.T);
        cells[3] = new Cell(1, 4, Tetris.T);
        states = new State[]{
                new State(0,0, 0,-1, 0,1, 1, 0),
                new State(0,0, -1,0, 1,0, 0,-1),
                new State(0,0, 0,1,  0,-1, -1,0),
                new State(0,0, 1,0, -1,0, 0,1)};
    }
}
class I extends Tetromino{
    public I() {
        cells[0] = new Cell(0, 4, Tetris.I);
        cells[1] = new Cell(0, 3, Tetris.I);
        cells[2] = new Cell(0, 5, Tetris.I);
        cells[3] = new Cell(0, 6, Tetris.I);
        states = new State[]{
                new State(0,0, 0,1, 0,-1, 0,-2),
                new State(0,0, -1,0, 1,0,2,0)};
    }
}
class L extends Tetromino {
    public L() {
        cells[0] = new Cell(0, 4, Tetris.L);
        cells[1] = new Cell(0, 3, Tetris.L);
        cells[2] = new Cell(0, 5, Tetris.L);
        cells[3] = new Cell(1, 3, Tetris.L);
        states = new State[]{
                new State(0,0, 0,-1, 0,1, 1,-1 ),
                new State(0,0, -1,0, 1,0, -1,-1),
                new State(0,0, 0,1, 0,-1, -1,1),
                new State(0,0, 1,0, -1,0, 1,1)};    
    }
}
 
class J extends Tetromino {
    public J() {
        cells[0] = new Cell(0, 4, Tetris.J);
        cells[1] = new Cell(0, 3, Tetris.J);
        cells[2] = new Cell(0, 5, Tetris.J);
        cells[3] = new Cell(1, 5, Tetris.J);
        states = new State[]{
                new State(0,0, 0,-1, 0,1, 1,1),
                new State(0,0, -1,0, 1,0, 1,-1),
                new State(0,0, 0,1, 0,-1, -1,-1),
                new State(0,0, 1,0, -1,0, -1,1 )};
    }
}
 
class S extends Tetromino {
    public S() {
        cells[0] = new Cell(0, 4, Tetris.S);
        cells[1] = new Cell(0, 5, Tetris.S);
        cells[2] = new Cell(1, 3, Tetris.S);
        cells[3] = new Cell(1, 4, Tetris.S);
        states = new State[]{
            new State(0,0, 0,1, 1,-1, 1,0 ),
            new State(0,0, -1,0, 1,1, 0,1 )};
    }
}
 
class Z extends Tetromino {
    public Z() {
        cells[0] = new Cell(1, 4, Tetris.Z);
        cells[1] = new Cell(0, 3, Tetris.Z);
        cells[2] = new Cell(0, 4, Tetris.Z);
        cells[3] = new Cell(1, 5, Tetris.Z);
        states = new State[]{
                new State(0,0, -1,-1, -1,0, 0,1 ),
                new State(0,0, -1,1, 0,1, 1,0 )};
    }
}
 
class O extends Tetromino {
    public O() {
        cells[0] = new Cell(0, 4, Tetris.O);
        cells[1] = new Cell(0, 5, Tetris.O);
        cells[2] = new Cell(1, 4, Tetris.O);
        cells[3] = new Cell(1, 5, Tetris.O);
        states = new State[]{
                new State(0,0, 0,1, 1,0, 1,1 ),
                new State(0,0, 0,1, 1,0, 1,1 )};
    }
}



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69977571/viewspace-2708520/,如需轉載,請註明出處,否則將追究法律責任。

相關文章