美国上市公司

亿元级外企IT培训企业

  • 全国服务监督电话400-827-0010
IT培训 > 学习笔记 > 我的俄罗斯方块项目总结1
  • 我的俄罗斯方块项目总结1

    发布:IT培训 来源:达内 时间:2014-12-29

  • 我的俄罗斯方块项目总结

  • 获奖学员:陈启壮

    所获奖项:三等奖

    内容

    俄罗斯方块一共三个类中间用等号隔开

    软件的开发过程

    1 明确业务需求

    用自然语言,将业务功能描述清楚

    ...

    2 业务分析

    找到有哪些业务对象,和图片的分析

    tetris(俄罗斯方块)

        |-- score 累计分数
        |-- lines 销毁的行数
        |-- Wall(墙 20行x10列)
               |-- 20row(行)
                      |--10 col cell(列)
        |-- tetromino(4格方块,有7种形态)   
               |-- 4 cell
        |--nextOne 下一个准备下落的方块
              |-- 4 cell

    3 数据模型,一切业务对象转换为数字表示

    场地按照行列划分为20x10格子

    格子有属性row,col,color

    4 类 设计

    Tetris
        |-- int score
        |-- int lines
        |-- Cell[20][10] wall
        |-- Tetromino tetromino
        |     |--Cell[4] cells
                 |-- row
                 |-- col
                 |-- color
    

    5 算法设计,就是如何利用数据的计算实现软件的功能

    4格方块的初始形态: I S Z J L T O

    就在初始数据的数值状态设计

    四格方块的下落计算:就是将每个格子的row+1

    就是将下落的业务功能,转换为数字计算实现

    左右移动

    下落流程控制:控制方块下落与墙之间的控制关系

    1 合理的文字流程描述

    2 分析文字描述中的功能(动作)为方法

    3 用流程控制语句连接方法实现功能

    4 严格测试结果!TestCase

    左右移动流程控制

    分数计算

    界面的绘制

    键盘事件控制

    旋转流程控制

    加速下降流程控制

    开始流程控制(Timer)

    暂停流程控制

    继续流程控制

    结束流程控制

    首先是Cell类,最基本的类包含3个私有属性和get,set方法,重写Object类的toString输出方法,并规定格子所具有的3个移动功能

    package com.tarena.tetris;

    //包:小写英文字母,域名倒写.项目名

    /**

    * 最小的格子

     */
    public class Cell{
        private int row;
        private int col;
        private int color;
        public Cell(int row, int col, int color) {
            super();
            this.row = row;
            this.col = col;
            this.color = color;
        }
        public int getCol() {
            return col;
        }
        public void setCol(int col) {
            this.col = col;
        }
        public int getColor() {
            return color;
        }
        public void setColor(int color) {
            this.color = color;
        }
        public int getRow() {
            return row;
        }
        public void setRow(int row) {
            this.row = row;
        }
       public void left(){
            col--;
        }
       public void right(){
            col++;
        }
        public void drop(){
            row++;
        }
        public String toString(){
            return row+","+col;
        }
    }
    ===============================================================
    package com.tarena.tetris;
    import java.util.Arrays;
    import java.util.Timer;
    import java.util.TimerTask;
    
    import javax.swing.JPanel;//是能够显示的矩形面板区域
    import javax.swing.JFrame;//窗口框
    import javax.swing.border.LineBorder;//实现边框
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyListener;
    import java.awt.event.KeyEvent;
    /*
    

    * 俄罗斯方块类

    * 俄罗斯方块 扩展了(extends)系统的显示面板,增加了墙和

    * 正在下落的方块

     * */
    public class Tetris extends JPanel{
        public static final int ROWS = 20;
        public static final int COLS= 10;
        /*代表方块下落着陆的墙*/
        private Cell[][] wall = new Cell[ROWS][COLS];
        /*是正在下落的方块*/
        private Tetromino tetromino;
        /*下一个进入的方块*/
        private Tetromino nextOne;
        private static int score;
        private int lines;
        Timer timer;
        private boolean gameOver = false;
        private boolean pause = false;//暂停
        private static final int[] SCORE_LEVEL={0,1,4,10,100};
        private static final Graphics Graphics = null;
        /*销毁(destory)满行*/             //     0 1 2  3  4
        /*在Tetris中添加方法,检查游戏是否结束*/
        public void rotateRightAction(){
            tetromino.rotateRight();
            if(outOfBounds()||coincide()){
                tetromino.rotateLeft();
            }
        }
        public void rotateLeftAction(){
            tetromino.rotateLeft();
            if(outOfBounds()||coincide()){
                tetromino.rotateRight();
            }
        }
        /*在Tetris中添加方法,检查游戏是否结束*/
        private boolean gameOver(){
            gameOver = wall[0][4]!=null;
            return gameOver;
        }
        /*在Tetris中添加方法*/
        public void hardDropAction(){
            while(canDrop()){
                tetromino.softDrop();
                }
            tetrominoLandToWall();
            destroy();
            if(gameOver()){
                gameOverAction();
            }
            nextTetromino();
        }
        public void destroy(){
            int lines = 0;//统计本次销毁的行数
            for(int row = 0 ;row<wall.length;row++){
                Cell[] line = wall[row];
                if(fullCell(line)){
                    clearLine(row,wall);
                    lines++;//每消除一行就累计加1
                }
            }
            score += SCORE_LEVEL[lines];
            this.lines +=lines;
        }
        public static void clearLine(int row,Cell[][] wall ){
            for(int i=row;i>1;i--){
                System.arraycopy(wall[i-1],0,wall[i],0,wall[i].length);
            }
            Arrays.fill(wall[0],null);
        }
        public static boolean fullCell(Cell []line){
            for(int col = 0;col<line.length;col++){
                if(line[col]==null) {
                    return false;//找到空格子,这行没有满
                }
            }
            return true;
        }
        public String toString(){//显示全部的墙
            String str = "";
            for(int row = 0;row<ROWS;row++){
                Cell[] line = wall[row];
                for(int col = 0;col<COLS;col++){
                    Cell cell = line[col];
                    if(tetromino.contains (row,col)){
                        str +=row+","+col+"  ";
                    }else{
                        str = str + cell + " ";
                        }
                }
                str +="\n";
            }
            return str;
        }
        /*4格方块下降流程
         * 方块移动到区域最下方或是着地到其他方块上无法移动时,
         * 就会固定到该处,而新的方法快出现在区域上方开始下落。
         * 如果能下降就继续下降,
         * 否则就着陆到墙上,并且生成(随机)下一个方块
         * */
        public void softDropAction(){
            if(canDrop()){//如果能下降
                tetromino.softDrop();//方块继续下降
            }else{
                tetrominoLandToWall();//着陆到墙上
                destroy();//
                if(gameOver()){
                    gameOverAction();
                }
                nextTetromino();//生产(随机)下一个方块
            }
        }
        private void startGameAction(){
            gameOver = false;
            pause = false;
            score = 0;
            lines = 0;
            emptyWall();
            nextTetromino();
            repaint();
            timer = new Timer();
            timer.schedule(new TimerTask(){
                public void run(){
                    softDropAction();
                    repaint();
                 }
             }, 500, 500);
        }
        private void emptyWall() {
            for(int row=0;row<ROWS;row++){
                Arrays.fill(wall[row],null);
            }
            
        }
        /*清理游戏结束现场,如:停止定时器等*/
        private void gameOverAction() {
                timer.cancel();//停止定时器
        }
        /*检查 方块 是否能够继续下落:到底最低部,或者墙上
         * 的下方有方块,返回false不能下降,返回true可以下降
         * */
        public boolean canDrop(){
            //检查到底部
            Cell[] cells = tetromino.getCells();
            for(Cell cell:cells){
                if(cell.getRow()==ROWS-1){
                    return false;
                }
            }
            //检查墙上下方是否有方块
            for(Cell cell:cells){
                int row = cell.getRow();
                int col = cell.getCol();
                Cell block = wall[row+1][col];
                if(block!=null){
                    return false;
                }
            }
            return true;
        }
        /*方块“着陆”到墙上,
         * 取出每个小cell
         * 找到cell的行号row和列号col
         * 将cell放置到wall[row][col]位置上
         * */
        public void tetrominoLandToWall(){
            Cell[] cells = tetromino.getCells();
            for(Cell cell:cells){
                int row = cell.getRow();
                int col = cell.getCol();
                wall[row][col] = cell;
            }
        }
        /*生产(随机)下一个方块
         * 1 下一个变为当前的
         * 2 随机产生下一个
         * */
        public void nextTetromino(){
            if(nextOne==null){//第一次nextOne是null时候先生产一个
                nextOne = Tetromino.randomTetromino();
            }
            tetromino = nextOne;//下一个变为当前的
            nextOne = Tetromino.randomTetromino();//随机产生下一个
            if(tetromino==null){//处理第一次使用时候下一个是null
                tetromino=Tetromino.randomTetromino();
            }
        }
        /*以格子为单位左右移动方块
         * 1)如果遇到左右边界就不能移动了
         * 2)如果与墙上的格子相撞就不能移动了
         * 变通为:
         * 1)先将方块左移动,
         * 2)检查(移动结果是否出界),或者(重合)
         * 3)如果检查失败,就右移的回来
         *
         * */
        public void moveLeftAction(){
            tetromino.moveLeft();
            if(outOfBounds() || coincide()){
                tetromino.moveRight();
                
            }
        }
        private boolean outOfBounds() {
            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||col<0||col>=COLS){
                    return true;
                }
            }
            return false;
        }
        private boolean coincide() {
            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 >0&&row<ROWS&&col<COLS&&col>0
                        &&wall[row][col]!=null){
                    return true;//重合
                }
            }
            return false;
        }
        public void moveRightAction(){
            tetromino.moveRight();
            if(outOfBounds() || coincide()){
                tetromino.moveLeft();
            }
        }
        public static final int CELL_SIZE = 25;
        /*在Tetris.java中添加main方法 作为软件的启动方法*/
        public static void main(String []args){
            JFrame frame = new JFrame("俄罗斯方块");
            int wigth =(COLS+8)*CELL_SIZE +100;
            int height =ROWS*CELL_SIZE +100;
            frame.setSize(wigth,height);
            frame.setLocationRelativeTo(null);//居中
            frame.setDefaultCloseOperation(
                JFrame.EXIT_ON_CLOSE);//设置关闭窗口就关闭软件
            frame.setLayout(null);//取消默认布局,取消自动充满
            Tetris panel = new Tetris();
            panel.setLocation(45,25);
            panel.setSize((COLS+8)*CELL_SIZE,ROWS*CELL_SIZE);
            panel.setBorder(new LineBorder(Color.black));
            frame.add(panel);//窗口中添加面板
            frame.setVisible(true);//显示窗口时候调用paint()
            panel.action();
        }
        /*动作方法,这里是让软件开始动作,*/
        public void action(){
            //wall[18][2] = new Cell(18,2,0xff0000);
            startGameAction();
            
            //重绘方法->尽快调用paint()
            //startGameAction();
            //this 是当前Tetris面板
            this.requestFocus();//为当前面板请求获得输入焦点
            //this对象就获得了输入焦点,以后任何的
            //键盘输入(包括左右方向键)目标就是这个面板对象了!
            //addKeyLIstener添加键盘监听,监听那些按键输入了
            this.addKeyListener(new KeyAdapter(){
                public void keyPressed(KeyEvent e) {
                    int key = e.getKeyCode();//key按键
                    if(gameOver){
                        if(key==KeyEvent.VK_S){
                            startGameAction();//启动游戏开始流程
                        }
                        return;
                    }
                    if(pause){
                        if(key==KeyEvent.VK_C){
                            continueAction();
                        }return;
                    }
                    //System.out.println("Type:"+e.getKeyCode());
                    
                    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_SPACE :hardDropAction();break;
                    case KeyEvent.VK_P :pasueAction();break;
                    }
                    //按键->方块移动方法->改变方块数据->repaint()
                    //->尽快调用paint()->利用新数据绘制
                    repaint();
                }
    
                private void continueAction() {
                    pause = false;
                    timer = new Timer();
                    timer.schedule(new TimerTask(){
                        public void run(){
                            softDropAction();
                            repaint();
                         }
                     }, 500, 500);
                }
                private void pasueAction() {
                    pause = true;
                    timer.cancel();
                    
                }
             });    
        }
        
    
        //JPanel 类利用paint(涂画)方法绘制界面
        //子类重写paint方法可以修改绘图逻辑
        public static final int BORDER_COLOR = 0x667799;
        public static final int BG_COLOR = 0xC3D5EA;
        public static final int FONT_COLOR = 0;
        public void paint(Graphics g) {
            //g 代表绑定在当前面板上的画笔
            //利用画笔在当前 面板上 绘制了一串字符!
            paintBackground(g);//填充背景
            paintWall(g);//绘制墙
            paintTetromino(g);//绘制当前方块
            paintNextOne(g);//绘制下一个方块
            paintScore(g);//绘制分数
            paintTetrisBorder(g);//绘制边线
            
        }
        
        private void paintScore(Graphics g) {
            int x = 12 * CELL_SIZE;
            int y = 5 * CELL_SIZE;
            Font font = new Font(getFont().getName(),Font.BOLD,25);
            String str = "分数: "+score;
            g.setColor(new Color(FONT_COLOR));
            g.setFont(font);
            g.drawString(str, x, y);
            y+=2*CELL_SIZE;
            str = "行数: "+lines;
            g.drawString(str, x, y);
            if(gameOver){
                str = "(T_T)![s]再来!";
                y+=2*CELL_SIZE;
                g.drawString(str, x, y);
            }
            if(pause){
                str = "[c]继续!";
                y+=2*CELL_SIZE;
                g.drawString(str, x, y);
            }else{
                str = "[p]暂停!";
                y+=2*CELL_SIZE;
                g.drawString(str, x, y);
            }
        }
        private void paintNextOne(Graphics g) {
            if(nextOne==null)//如果没有4格方块就返回,不绘制
                return;
            for (Cell cell : nextOne.getCells()) {
                int row = cell.getRow()+1;
                int col = cell.getCol()+9;
                int x = col*CELL_SIZE;
                int y = row*CELL_SIZE;
                g.setColor(new Color(cell.getColor()));
                g.fillRect(x, y, CELL_SIZE, CELL_SIZE);
                g.setColor(new Color(BORDER_COLOR));
                g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
            }
            
        }
        private void paintTetromino(Graphics g) {
            if(tetromino==null)//如果没有4格方块就返回,不绘制
                return;
            for (Cell cell : tetromino.getCells()) {
                int row = cell.getRow();
                int col = cell.getCol();
                int x = col*CELL_SIZE;
                int y = row*CELL_SIZE;
                g.setColor(new Color(cell.getColor()));
                g.fillRect(x, y, CELL_SIZE, CELL_SIZE);
                g.setColor(new Color(BORDER_COLOR));
                g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
            }
            
        }
        private void paintWall(Graphics g) {
            for (int row = 0; row <ROWS; row++) {
                for (int col = 0; col < COLS; col++) {
                    Cell cell = wall[row][col];
                    int x = col*CELL_SIZE;
                    int y = row*CELL_SIZE;
                    if(cell == null){
                        //g.setColor(new Color(BORDER_COLOR));
                       // g.drawRect(x, y,
                         //   CELL_SIZE, CELL_SIZE);
                    }else{
                        g.setColor(new Color(cell.getColor()));
                        g.fillRect(x, y,
                                CELL_SIZE, CELL_SIZE);
                        g.setColor(new Color(BORDER_COLOR));
                        g.drawRect(col*CELL_SIZE, row*CELL_SIZE,
                            CELL_SIZE, CELL_SIZE);
                    }
                }        
            }    
        }
        private void paintBackground(Graphics g) {
            g.setColor(new Color(BG_COLOR));
            g.fillRect(0, 0, getWidth(), getHeight());    
        }
        private void paintTetrisBorder(Graphics g) {
            g.setColor(new Color(BORDER_COLOR));
            g.drawRect(0, 0, CELL_SIZE*COLS, CELL_SIZE*ROWS-1);
            g.drawRect(CELL_SIZE*COLS,0,
                CELL_SIZE*8-1, CELL_SIZE*ROWS-1);    
        }
    }
    ===============================================================
    package com.tarena.tetris;
    import java.util.Arrays;
    import java.util.Random;
    /*
     * 四格方块类,有7种子类:I T S Z J L O
     * */
    public abstract class Tetromino {
        public static final int I_COLOR =0xff6600;
        public static final int T_COLOR =0xffff00;
        public static final int S_COLOR =0x66ccff;
        public static final int Z_COLOR =0x00ff00;
        public static final int J_COLOR =0x0000ff;
        public static final int L_COLOR =0xcc00ff;
        public static final int O_COLOR =0xff0000;
        protected Cell[] cells = new Cell[4];
        /*四格方块的下落,是四个格子一起下落*/
        public void softDrop(){
            for(int i = 0;i<cells.length;i++){
                cells[i].drop();
            }
        }
        /*向左移动一步*/
        public void moveLeft(){
            for(int i = 0;i<cells.length;i++){
                Cell cell = cells[i];//引用赋值
                cell.left();
            }
        }
        public void moveRight(){
            //增强for循环,是传统数组迭代的“简化版本”,
            //也称为foreach循环(foreach迭代)(java 5以后)
            for(Cell cell:cells){//底层实现就是经典迭代
                cell.right();
            }
        }
        public Cell[] getCells() {
            return cells;
        }
        protected Offset[] states;//旋转的状态
        protected class Offset{
            int row0,col0;
            int row1,col1;
            int row2,col2;
            int row3,col3;
            public Offset(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;
            }
            
        }
        private int index = 10000-1;
        /*向右转*/
        public void rotateRight(){
            index++;
            Offset offset = states[index%states.length];
            Cell axis = cells[0];//找到轴(axis)的位置
            
            cells[0].setRow(offset.row0+axis.getRow());
            cells[0].setCol(offset.col0+axis.getCol());
            cells[1].setRow(offset.row1+axis.getRow());
            cells[1].setCol(offset.col1+axis.getCol());
            cells[2].setRow(offset.row2+axis.getRow());
            cells[2].setCol(offset.col2+axis.getCol());
            cells[3].setRow(offset.row3+axis.getRow());
            cells[3].setCol(offset.col3+axis.getCol());
        }
        public void rotateLeft(){
            index--;
            Offset offset = states[index%states.length];
            Cell axis = cells[0];//找到轴(axis)的位置
    
            cells[0].setRow(offset.row0+axis.getRow());
            cells[0].setCol(offset.col0+axis.getCol());
            cells[1].setRow(offset.row1+axis.getRow());
            cells[1].setCol(offset.col1+axis.getCol());
            cells[2].setRow(offset.row2+axis.getRow());
            cells[2].setCol(offset.col2+axis.getCol());
            cells[3].setRow(offset.row3+axis.getRow());
            cells[3].setCol(offset.col3+axis.getCol());
        }
        /*随机生成一个具体方法*/
        public static Tetromino randomTetromino() {
            Random random = new Random();
            int type = random.nextInt(7);//0~6
            switch(type){
            case 0:return new I();
            case 1:return new T();
            case 2:return new S();
            case 3:return new J();
            case 4:return new Z();
            case 5:return new L();
            case 6:return new O();
            
            }
            return null;
        }
        public String toString(){
            return Arrays.toString(cells);
        }
        public boolean contains(int row, int col) {
            for(int i =0;i<cells.length;i++){
                Cell cell = cells[i];
                if(cell.getRow()==row && cell.getCol()==col){
                    return true;
                }
            }
            return false;
        }
        
        
    }
    class I extends Tetromino{
        public I(){
        cells[0] = new Cell(0,4,I_COLOR);
        cells[1] = new Cell(0,3,I_COLOR);
        cells[2] = new Cell(0,5,I_COLOR);
        cells[3] = new Cell(0,6,I_COLOR);
        states = new Offset[]{
            new Offset(0,0,-1,0,1,0,2,0),
            new Offset(0,0,0,-1,0,1,0,2),
            };
        }
    }
    class T extends Tetromino{
        public T(){
            cells[0] = new Cell(0,4,T_COLOR);
            cells[1] = new Cell(0,3,T_COLOR);
            cells[2] = new Cell(0,5,T_COLOR);
            cells[3] = new Cell(1,4,T_COLOR);
            states = new Offset[]{
                    
                    new Offset(0,0,1,0,-1,0,0,1),
                    new Offset(0,0,0,-1,0,1,1,0),
                    new Offset(0,0,1,0,-1,0,0,-1),
                    new Offset(0,0,0,1,0,-1,-1,0),
                        };
                }
    }
    class S extends Tetromino{
        public S(){
            cells[0] = new Cell(0,4,S_COLOR);
            cells[1] = new Cell(0,5,S_COLOR);
            cells[2] = new Cell(1,3,S_COLOR);
            cells[3] = new Cell(1,4,S_COLOR);
            states = new Offset[]{
                    new Offset(0,0,-1,0,1,1,0,1),
                    new Offset(0,0,0,1,1,-1,1,0),
                        };
                }
    }
    class Z extends Tetromino{
        public Z(){
            cells[0] = new Cell(0,4,Z_COLOR);
            cells[1] = new Cell(0,3,Z_COLOR);
            cells[2] = new Cell(1,4,Z_COLOR);
            cells[3] = new Cell(1,5,Z_COLOR);
            states = new Offset[]{
                    new Offset(0,0,-1,1,0,1,1,0),
                    new Offset(0,0,-1,-1,-1,0,0,1),
                        };
                }
    }
    class J extends Tetromino{
        public J(){
            cells[0] = new Cell(0,4,J_COLOR);
            cells[1] = new Cell(0,3,J_COLOR);
            cells[2] = new Cell(0,5,J_COLOR);
            cells[3] = new Cell(1,5,J_COLOR);
            states = new Offset[]{
                    new Offset(0,0,-1,0,1,0,1,-1),
                    new Offset(0,0,0,1,0,-1,-1,-1),
                    new Offset(0,0,1,0,-1,0,-1,1),
                    new Offset(0,0,0,-1,0,1,1,1),
                        };
                }
    }
    class L extends Tetromino{
        public L(){
            cells[0] = new Cell(0,4,L_COLOR);
            cells[1] = new Cell(0,3,L_COLOR);
            cells[2] = new Cell(0,5,L_COLOR);
            cells[3] = new Cell(1,3,L_COLOR);
            states = new Offset[]{
                    new Offset(0,0,-1,0,1,0,-1,-1),
                    new Offset(0,0,0,1,0,-1,-1,1),
                    new Offset(0,0,1,0,-1,0,1,1),
                    new Offset(0,0,0,-1,0,1,1,-1),
                        };
                }
    }
    class O extends Tetromino{
        public O(){
            cells[0] = new Cell(0,4,O_COLOR);
            cells[1] = new Cell(0,5,O_COLOR);
            cells[2] = new Cell(1,4,O_COLOR);
            cells[3] = new Cell(1,5,O_COLOR);
            states = new Offset[]{
                    new Offset(0,0,0,1,1,0,1,1),
                    new Offset(0,0,0,1,1,0,1,1),
                    
                        };
                }
    }
    

  • 上一篇:可以两人一起玩的坦克大战

    下一篇:Servlet总结:系列笔记之九

相关资讯
2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56