天天看點

實驗3 --俄羅斯方塊 with 20135335郝爽

一、   實驗内容

(一)靈活開發與XP

内容:1.靈活開發(Agile Development)是一種以人為核心、疊代、循序漸進的開發方法。

2.極限程式設計(eXtreme Programming,XP)是一種全新而快捷的軟體開發方法。

要點: 1. XP軟體開發的基石是XP的活動,包括:編碼、測試、傾聽、設計。

2. 我們關注其中的編碼标準,結對程式設計,代碼集體所有,測試,重構等實踐。(如實驗二中的TDD)

(二)編碼标準

内容:程式設計标準使代碼更容易閱讀和了解,甚至可以保證其中的錯誤更少。程式設計标準包含:具有說明性的名字、清晰的表達式、直截了當的控制流、可讀的代碼和注釋,以及在追求這些内容時一緻地使用某些規則和慣用法的重要性。

學習:

1. 軟體輔助修改:在eclipse中,用source->Format進行格式規範;

2. 自己命名:包名全部小寫,如: io ;類名第一個字母要大寫,如:HelloWorldApp;等

(三)結對程式設計

内容:在結對程式設計模式下,一對程式員肩并肩、平等地、互補地進行開發工作。其中的角色配置設定為駕駛員(控制鍵盤輸入),領航人(起到領航、提醒作用)。

(四)版本控制

摘要:版本控制提供項目級的 undo(撤銷) 功能;•   版本控制允許多人在同一代碼上工作;•  版本控制系統儲存了過去所作的修改的曆史記錄;具體步驟如下——

# 添加修改檔案

$ git add 所有修改的檔案

# 送出到環境中本地代碼倉庫

$ git commit -m '本次修改的描述'

# push到git.shiyanlou.com,無需輸入密碼

$ git push

學習:按照要求指導,逐漸在實驗樓中完成,截圖如下:

(五)重構

摘要:重構(Refactor),就是在不改變軟體外部行為的基礎上,改變軟體内部的結構,使其更加易于閱讀、易于維護和易于變更 。學習:嘗試Encapsulate Field(封裝)功能:

原圖:

實驗3 --俄羅斯方塊 with 20135335郝爽

(六)實踐項目

同伴郝爽20135335部落格位址http://www.cnblogs.com/20135335hs

1.綜述

我們采取“先學習,後操作;邊操作,邊變通”的實驗思路。具體方法是:研讀要求—學習代碼要素—複習TDD内容—建構測試程式—檢查測試程式—測試産品代碼—修改産品代碼—重新檢查産品代碼—完成實驗報告。在這一過程中,我們對各方面内容都進行了詳細記錄(未在實驗樓中進行托管和git)

團隊由兩名成員組成,詳細分工為:

20135335郝爽:負責前期學習的整理工作,将java代碼進行必要注釋,并對TDD内容進行補充;進行後期測試

20135233楊光:負責中期的測試代碼開發;進行後期測試

2.研讀要求與自我學習(20135211)

1.TDD(Test Driven Development, 測試驅動開發),

TDD的一般步驟如下:

  • 明确目前要完成的功能,記錄成一個測試清單
  • 快速完成編寫針對此功能的測試用例
  • 測試代碼編譯不通過(沒産品代碼呢)
  • 編寫産品代碼
  • 測試通過
  • 對代碼進行重構,并保證測試通過(重構下次實驗練習)
  • 循環完成所有功能的開發

2. 測試類具體操作:把滑鼠放到項目名上,單擊右鍵,在彈出的菜單中標明New->Source Folder建立一個測試目錄test;把滑鼠放到test目錄上,單擊右鍵,在彈出的菜單中標明New->JUnit Test Case建立一個測試用例類

3.實驗要求要點為:程式要有GUI界面,參考使用者界面和使用者體驗;記錄TDD和重構的過程,測試代碼不要少于業務代碼

package game;

import java.awt.Button; 

import java.awt.Canvas; 

import java.awt.Color; 

import java.awt.Dimension; 

import java.awt.Frame; 

import java.awt.Graphics; 

import java.awt.GridLayout; 

import java.awt.Insets; 

import java.awt.Label; 

import java.awt.Panel; 

import java.awt.TextField; 

import java.awt.event.ActionEvent; 

import java.awt.event.ActionListener; 

import java.awt.event.KeyEvent; 

import java.awt.event.KeyListener; 

import java.awt.event.WindowAdapter; 

import java.awt.event.WindowEvent; 

import java.awt.event.WindowListener;

//俄羅斯方塊類  

public class ERS_Block extends Frame { 

    public static boolean isPlay = false; 

    public static int level = 1, score = 0; 

    public static TextField scoreField, levelField; 

    public static MyTimer timer; 

    GameCanvas gameScr; 

    public static void main(String[] argus) { 

        ERS_Block ers = new ERS_Block( 

                "俄羅斯方塊遊戲  V1.0                   Author:Vincent"); 

        WindowListener win_listener = new WinListener(); 

        ers.addWindowListener(win_listener); 

    } 

    // 俄羅斯方塊類的構造方法 

    ERS_Block(String title) { 

        super(title); 

        setSize(600, 480); 

        setLayout(new GridLayout(1, 2)); 

        gameScr = new GameCanvas(); 

        gameScr.addKeyListener(gameScr); 

        timer = new MyTimer(gameScr); 

        timer.setDaemon(true); 

        timer.start(); 

        timer.suspend(); 

        add(gameScr); 

        Panel rightScr = new Panel(); 

        rightScr.setLayout(new GridLayout(2, 1, 0, 30)); 

        rightScr.setSize(120, 500); 

        add(rightScr); 

        // 右邊資訊窗體的布局 

        MyPanel infoScr = new MyPanel(); 

        infoScr.setLayout(new GridLayout(4, 1, 0, 5)); 

        infoScr.setSize(120, 300); 

        rightScr.add(infoScr); 

        // 定義标簽和初始值 

        Label scorep = new Label("分數:", Label.LEFT); 

        Label levelp = new Label("級數:", Label.LEFT); 

        scoreField = new TextField(8); 

        levelField = new TextField(8); 

        scoreField.setEditable(false); 

        levelField.setEditable(false); 

        infoScr.add(scorep); 

        infoScr.add(scoreField); 

        infoScr.add(levelp); 

        infoScr.add(levelField); 

        scorep.setSize(new Dimension(20, 60)); 

        scoreField.setSize(new Dimension(20, 60)); 

        levelp.setSize(new Dimension(20, 60)); 

        levelField.setSize(new Dimension(20, 60)); 

        scoreField.setText("0"); 

        levelField.setText("1"); 

        // 右邊控制按鈕窗體的布局 

        MyPanel controlScr = new MyPanel(); 

        controlScr.setLayout(new GridLayout(5, 1, 0, 5)); 

        rightScr.add(controlScr); 

        // 定義按鈕play 

        Button play_b = new Button("開始遊戲"); 

        play_b.setSize(new Dimension(50, 200)); 

        play_b.addActionListener(new Command(Command.button_play, gameScr)); 

        // 定義按鈕Level UP 

        Button level_up_b = new Button("提進階數"); 

        level_up_b.setSize(new Dimension(50, 200)); 

        level_up_b.addActionListener(new Command(Command.button_levelup, 

                gameScr)); 

        // 定義按鈕Level Down 

        Button level_down_b = new Button("降低級數"); 

        level_down_b.setSize(new Dimension(50, 200)); 

        level_down_b.addActionListener(new Command(Command.button_leveldown, 

        // 定義按鈕Level Pause 

        Button pause_b = new Button("遊戲暫停"); 

        pause_b.setSize(new Dimension(50, 200)); 

        pause_b.addActionListener(new Command(Command.button_pause, gameScr)); 

        // 定義按鈕Quit 

        Button quit_b = new Button("退出遊戲"); 

        quit_b.setSize(new Dimension(50, 200)); 

        quit_b.addActionListener(new Command(Command.button_quit, gameScr)); 

        controlScr.add(play_b); 

        controlScr.add(level_up_b); 

        controlScr.add(level_down_b); 

        controlScr.add(pause_b); 

        controlScr.add(quit_b); 

        setVisible(true); 

        gameScr.requestFocus(); 

// 重寫MyPanel類,使Panel的四周留白間 

class MyPanel extends Panel { 

    public Insets getInsets() { 

        return new Insets(30, 50, 30, 50); 

// 遊戲畫布類 

class GameCanvas extends Canvas implements KeyListener { 

    final int unitSize = 30; // 小方塊邊長 

    int rowNum; // 正方格的行數 

    int columnNum; // 正方格的列數 

    int maxAllowRowNum; // 允許有多少行未削 

    int blockInitRow; // 新出現塊的起始行坐标 

    int blockInitCol; // 新出現塊的起始列坐标 

    int[][] scrArr; // 螢幕數組 

    Block b; // 對方快的引用 

    // 畫布類的構造方法 

    GameCanvas() { 

        rowNum = 15; 

        columnNum = 10; 

        maxAllowRowNum = rowNum - 2; 

        b = new Block(this); 

        blockInitRow = rowNum - 1; 

        blockInitCol = columnNum / 2 - 2; 

        scrArr = new int[32][32]; 

    // 初始化螢幕,并将螢幕數組清零的方法 

    void initScr() { 

        for (int i = 0; i < rowNum; i++) 

            for (int j = 0; j < columnNum; j++) 

                scrArr[i][j] = 0; 

        b.reset(); 

        repaint(); 

    // 重新重新整理畫布方法 

    public void paint(Graphics g) { 

                drawUnit(i, j, scrArr[i][j]); 

    }  

    // 畫方塊的方法 

    public void drawUnit(int row, int col, int type) { 

        scrArr[row][col] = type; 

        Graphics g = getGraphics(); 

        switch (type) { // 表示畫方快的方法 

        case 0: 

            g.setColor(Color.black); 

            break; // 以背景為顔色畫 

        case 1: 

            g.setColor(Color.blue); 

            break; // 畫正在下落的方塊 

        case 2: 

            g.setColor(Color.magenta); 

            break; // 畫已經落下的方法 

        } 

        g.fill3DRect(col * unitSize, getSize().height - (row + 1) * unitSize, 

                unitSize, unitSize, true); 

        g.dispose(); 

    public Block getBlock() { 

        return b; // 傳回block執行個體的引用 

    // 傳回螢幕數組中(row,col)位置的屬性值 

    public int getScrArrXY(int row, int col) { 

        if (row < 0 || row >= rowNum || col < 0 || col >= columnNum) 

            return (-1); 

        else 

            return (scrArr[row][col]); 

    // 傳回新塊的初始行坐标方法 

    public int getInitRow() { 

        return (blockInitRow); // 傳回新塊的初始行坐标 

    // 傳回新塊的初始列坐标方法 

    public int getInitCol() { 

        return (blockInitCol); // 傳回新塊的初始列坐标 

    // 滿行删除方法 

    void deleteFullLine() { 

        int full_line_num = 0; 

        int k = 0; 

        for (int i = 0; i < rowNum; i++) { 

            boolean isfull = true; 

            L1: for (int j = 0; j < columnNum; j++) 

                if (scrArr[i][j] == 0) { 

                    k++; 

                    isfull = false; 

                    break L1;  

                } 

            if (isfull) 

                full_line_num++; 

            if (k != 0 && k - 1 != i && !isfull) 

                for (int j = 0; j < columnNum; j++) { 

                    if (scrArr[i][j] == 0) 

                        drawUnit(k - 1, j, 0); 

                    else 

                        drawUnit(k - 1, j, 2); 

                    scrArr[k - 1][j] = scrArr[i][j]; 

        for (int i = k - 1; i < rowNum; i++) { 

            for (int j = 0; j < columnNum; j++) { 

                drawUnit(i, j, 0); 

            } 

        ERS_Block.score += full_line_num; 

        ERS_Block.scoreField.setText("" + ERS_Block.score); 

    // 判斷遊戲是否結束方法 

    boolean isGameEnd() { 

        for (int col = 0; col < columnNum; col++) { 

            if (scrArr[maxAllowRowNum][col] != 0) 

                return true; 

        return false; 

    public void keyTyped(KeyEvent e) { 

    public void keyReleased(KeyEvent e) { 

    // 處理鍵盤輸入的方法 

    public void keyPressed(KeyEvent e) { 

        if (!ERS_Block.isPlay) 

            return; 

        switch (e.getKeyCode()) { 

        case KeyEvent.VK_DOWN: 

            b.fallDown(); 

            break; 

        case KeyEvent.VK_LEFT: 

            b.leftMove(); 

        case KeyEvent.VK_RIGHT: 

            b.rightMove(); 

        case KeyEvent.VK_SPACE: 

            b.leftTurn(); 

// 處理控制類 

class Command implements ActionListener { 

    static final int button_play = 1; // 給按鈕配置設定編号 

    static final int button_levelup = 2; 

    static final int button_leveldown = 3; 

    static final int button_quit = 4; 

    static final int button_pause = 5; 

    static boolean pause_resume = true; 

    int curButton; // 目前按鈕 

    GameCanvas scr; 

    // 控制按鈕類的構造方法 

    Command(int button, GameCanvas scr) { 

        curButton = button; 

        this.scr = scr; 

    // 按鈕執行方法 

    public void actionPerformed(ActionEvent e) { 

        switch (curButton) { 

        case button_play: 

            if (!ERS_Block.isPlay) { 

                scr.initScr(); 

                ERS_Block.isPlay = true; 

                ERS_Block.score = 0; 

                ERS_Block.scoreField.setText("0"); 

                ERS_Block.timer.resume(); 

            scr.requestFocus(); 

        case button_levelup: 

            if (ERS_Block.level < 10) { 

                ERS_Block.level++; 

                ERS_Block.levelField.setText("" + ERS_Block.level); 

                ERS_Block.scoreField.setText("" + ERS_Block.score); 

        case button_leveldown: 

            if (ERS_Block.level > 1) { 

                ERS_Block.level--; 

        case button_pause: 

            if (pause_resume) { 

                ERS_Block.timer.suspend(); 

                pause_resume = false; 

            } else { 

                pause_resume = true; 

        case button_quit: 

            System.exit(0); 

// 方塊類 

class Block { 

    static int[][] pattern = { 

            { 0x0f00, 0x4444, 0x0f00, 0x4444 },// 用十六進至表示,本行表示長條四種狀态 

            { 0x04e0, 0x0464, 0x00e4, 0x04c4 }, 

            { 0x4620, 0x6c00, 0x4620, 0x6c00 }, 

            { 0x2640, 0xc600, 0x2640, 0xc600 }, 

            { 0x6220, 0x1700, 0x2230, 0x0740 }, 

            { 0x6440, 0x0e20, 0x44c0, 0x8e00 }, 

            { 0x0660, 0x0660, 0x0660, 0x0660 } }; 

    int blockType; // 塊的模式号(0-6) 

    int turnState; // 塊的翻轉狀态(0-3) 

    int blockState; // 快的下落狀态 

    int row, col; // 塊在畫布上的坐标 

    // 塊類的構造方法 

    Block(GameCanvas scr) { 

        blockType = (int) (Math.random() * 1000) % 7; 

        turnState = (int) (Math.random() * 1000) % 4; 

        blockState = 1; 

        row = scr.getInitRow(); 

        col = scr.getInitCol(); 

    // 重新初始化塊,并顯示新塊 

    public void reset() { 

        blockType = (int) (Math.random() * 1000) % 7; 

        dispBlock(1); 

    // 實作“塊”翻轉的方法 

    public void leftTurn() { 

        if (assertValid(blockType, (turnState + 1) % 4, row, col)) { 

            dispBlock(0); 

            turnState = (turnState + 1) % 4; 

            dispBlock(1); 

    // 實作“塊”的左移的方法 

    public void leftMove() { 

        if (assertValid(blockType, turnState, row, col - 1)) { 

            col--; 

    // 實作塊的右移 

    public void rightMove() { 

        if (assertValid(blockType, turnState, row, col + 1)) { 

            col++; 

    // 實作塊落下的操作的方法 

    public boolean fallDown() { 

        if (blockState == 2) 

            return (false); 

        if (assertValid(blockType, turnState, row - 1, col)) { 

            row--; 

            return (true); 

        } else { 

            blockState = 2; 

            dispBlock(2); 

    // 判斷是否正确的方法 

    boolean assertValid(int t, int s, int row, int col) { 

        int k = 0x8000; 

        for (int i = 0; i < 4; i++) { 

            for (int j = 0; j < 4; j++) { 

                if ((int) (pattern[t][s] & k) != 0) { 

                    int temp = scr.getScrArrXY(row - i, col + j); 

                    if (temp < 0 || temp == 2) 

                        return false; 

                k = k >> 1; 

        return true; 

    // 同步顯示的方法 

    public synchronized void dispBlock(int s) { 

                if (((int) pattern[blockType][turnState] & k) != 0) { 

                    scr.drawUnit(row - i, col + j, s); 

// 定時線程 

class MyTimer extends Thread { 

    public MyTimer(GameCanvas scr) { 

    public void run() { 

        while (true) { 

            try { 

                sleep((10 - ERS_Block.level + 1) * 100); 

            } catch (InterruptedException e) { 

            if (!scr.getBlock().fallDown()) { 

                scr.deleteFullLine(); 

                if (scr.isGameEnd()) { 

                    ERS_Block.isPlay = false; 

                    suspend(); 

                } else 

                    scr.getBlock().reset(); 

class WinListener extends WindowAdapter { 

    public void windowClosing(WindowEvent l) { 

        System.exit(0); 

}

實驗3 --俄羅斯方塊 with 20135335郝爽
實驗3 --俄羅斯方塊 with 20135335郝爽

6.實驗感悟

本次實驗,我們沒有進入實驗樓完成,自己在電腦上自主做實驗,在遊戲設計的時候并不是一帆風順,有許多問題都咨詢了學長與同學。

在實驗中我們也有查閱網上有關的遊戲資料,增長了許多知識與見識,對我的程式設計有很大的幫助。