一、 實驗内容
(一)靈活開發與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(封裝)功能:
原圖:

(六)實踐項目
同伴郝爽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);
}
6.實驗感悟
本次實驗,我們沒有進入實驗樓完成,自己在電腦上自主做實驗,在遊戲設計的時候并不是一帆風順,有許多問題都咨詢了學長與同學。
在實驗中我們也有查閱網上有關的遊戲資料,增長了許多知識與見識,對我的程式設計有很大的幫助。