CS106A Assignment3: Breakout——浅谈自上而下的设计体验

来源:互联网 发布:suse linux rpm 安装 编辑:程序博客网 时间:2024/05/19 02:31

斯坦福大学CS106A编程方法学的第三次作业,Breakout,我自己写好了代码,并且能够完整运行。从编写这个程序的过程中学习到了很多的东西,比如各种GObject的创建、使用、常用方法等等。但是我觉得收获最大的还是一种编程设计思想:自上而下的设计。


我一开始写程序的时候写着写着就乱了,不知道下一步应该做什么。CS106A的作业要求上面已经做了很多的分解工作,但是每一步的具体方法对我来说依然是一个很大的挑战。后来,开始把注意力放在了如何设计程序上,而不是如何写出最终的代码。我认为,自上而下的设计就是把很复杂的问题高度抽象化,把一个庞大的问题简单直观的分解成几个较为简单明了的问题,然后不断的进行分解,直到最终的问题可以用简洁的代码表达出来。我最终的程序中,run()方法里只有两行:setup()用于初始化游戏,play()用于进行游戏。这样的分解,也为之后思考的问题提供了不少的便利。

在实际写代码的过程中,即使把程序设计好了,还是很容易迷失方向,在游戏中尤其体现在时间的先后关系上。后来,我开始在程序中添加大量的注释,这样才解决了容易迷失方向这个问题。在实际编写代码的时候,在每一个方法前用注释标明这个方法具体要做的几件事情,然后一件件的写出代码。这个过程实际上也是一种对问题的自上而下的分解,不仅可以让自己知道应该写出那些内容,也加深了对于所要解决的问题的思考。

下面就把我的代码贴出来,肯定有写的不到位的地方,也希望大家能够指出来,大家共同进步。

import acm.graphics.*;import acm.program.*;import acm.util.*;import java.applet.*;import java.awt.*;import java.awt.event.*;public class Breakout extends GraphicsProgram {/** Width and height of application window in pixels */public static final int APPLICATION_WIDTH = 400;public static final int APPLICATION_HEIGHT = 600;/** Dimensions of game board (usually the same) */private static final int WIDTH = APPLICATION_WIDTH;private static final int HEIGHT = APPLICATION_HEIGHT;/** Dimensions of the paddle */private static final int PADDLE_WIDTH = 60;private static final int PADDLE_HEIGHT = 10;/** Offset of the paddle up from the bottom */private static final int PADDLE_Y_OFFSET = 30;/** Number of bricks per row */private static final int NBRICKS_PER_ROW = 10;/** Number of rows of bricks */private static final int NBRICK_ROWS = 10;/**Number of bricks */private static  int brickNum = NBRICKS_PER_ROW * NBRICK_ROWS;/** Separation between bricks */private static final int BRICK_SEP = 4;/** Width of a brick */private static final int BRICK_WIDTH =  (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;/** Height of a brick */private static final int BRICK_HEIGHT = 8;/** Radius of the ball in pixels */private static final int BALL_RADIUS = 10;/** Offset of the top brick row from the top */private static final int BRICK_Y_OFFSET = 70;/** Number of turns */private static final int NTURNS = 3;/**Delay time for the animation */private static final int DELAY = 15;/* Method: run() *//** Runs the Breakout program. */public void run() {setup(); //画出砖块,球板,提示标签play();//开始玩游戏}private void setup() {/**=============================== * 画出砖块 * =============================== * 1、用两个for loop画出所有的砖块 * 2、把砖块添加到合适的位置 * 3、将砖块设置为合适的颜色  * ===============================  *///用两个for loop画出所有的砖块for (int i=0;i<NBRICK_ROWS;i++){for (int j=0;j<NBRICKS_PER_ROW;j++){rect = new GRect(BRICK_WIDTH,BRICK_HEIGHT);//给砖块上色,Switch方法着色rect.setFilled(true);int trace = i / 2;switch (trace){case 0: color = Color.RED; break;case 1: color = Color.ORANGE; break;case 2: color = Color.YELLOW; break;case 3: color = Color.GREEN; break;case 4: color = Color.CYAN; break;}rect.setColor(color);//计算砖块的坐标int x = (BRICK_WIDTH + BRICK_SEP) * j ;int y = BRICK_Y_OFFSET + (BRICK_HEIGHT + BRICK_SEP)* i;add(rect,x,y);}}/**========================================= * 画出球板以及游戏开始的提示标签 * ========================================= * 1、添加球板 * 2、添加提示标签 * ========================================= *///添加球板paddle = new GRect(PADDLE_WIDTH,PADDLE_HEIGHT);paddle.setFilled(true);add(paddle, (getWidth()-PADDLE_WIDTH)/2, getHeight()-PADDLE_HEIGHT-PADDLE_Y_OFFSET);//添加提示标签label = new GLabel("CLICK TO SERVE!");label.setFont("Times New Roman-36");add(label,(getWidth()-label.getWidth())/2,(getHeight()-label.getAscent())/2);}private void play(){/**============================================ * 开始玩游戏 * ============================================ * Version 0.4 * 1、等待单击鼠标,游戏开始 * 2、关联球板跟随鼠标移动 * 3、创建一个比赛用球,放置在屏幕中央 * 4、移动球,碰到三面墙壁立刻反弹 * 5、碰到底边游戏结束 * 6、碰到球板反弹,板砖反弹,并清除板砖 * ============================================ *///等待单击鼠标,游戏开始addMouseListeners();waitForClick();remove(label);ball = new GOval(BALL_RADIUS,BALL_RADIUS);ball.setFilled(true);add(ball, getWidth()/2 - BALL_RADIUS, getHeight()/2 - BALL_RADIUS);//设置速度参数vx = rgen.nextDouble(1.0,5.0);if (rgen.nextBoolean(0.5)) vx = -vx;vy = 4.0;/**=============================================== * 利用while loop进行游戏 * =============================================== * 1、移动球,y方向速度固定,x方向初始速度随机 * 2、碰到底部一次游戏结束 * 3、碰到三面墙壁改变一个方向上速度的符号 * 4、碰到球板y方向速度符号改变,随机选择x方向的速度 * 5、清理所有砖块,赢得比赛 * =============================================== */while (true){ball.move(vx,vy);int i = 0;  //用于追踪游戏次数if (ball.getY()+2*BALL_RADIUS > paddle.getY()){  //低于球板上沿就结束比赛,否则会有诡异的效果i++;if (i>2){youLose();waitForClick();break;} else {remove(ball);pause(1000);ball = new GOval(BALL_RADIUS,BALL_RADIUS);ball.setFilled(true);add(ball, getWidth()/2 - BALL_RADIUS, getHeight()/2 - BALL_RADIUS);}}//碰到三面墙壁球的运动规则if (ball.getX()<0 || ball.getX()+2*BALL_RADIUS>getWidth()) vx= -vx;if (ball.getY()<0 ) vy= -vy;//===================================================================pause(DELAY);collider = getColliderObject();  //球与球板以及砖块碰撞的规则if (collider == paddle){vy = -vy;vx = rgen.nextDouble(1.0, 5.0);if (rgen.nextBoolean(0.5)) vx=-vx;} else if (collider != null) {vy = -vy;remove(collider);brickNum--;//如果砖块数量为0,玩家赢得游戏,跳出while loopif (brickNum == 0) {youWin();waitForClick();break;}}}removeAll();}private void youWin() {/**======================== * youWin()方法 * ======================== * 1、清理屏幕 * 2、弹出赢得游戏提示 * 3、弹出退出游戏的提示 * ======================== */removeAll();GLabel win = new GLabel("Congratulations! You win!");win.setFont("Times New Roman-36");add(win,(getWidth()-win.getWidth())/2,(getHeight()-win.getAscent())/2);pause(1000);remove(win);GLabel end = new GLabel("Click to end");end.setFont("Times New Roman-36");add(end,(getWidth()-end.getWidth())/2,(getHeight()-end.getAscent())/2);}private void youLose() {/**======================== * youLose()方法 * ======================== * 1、清理屏幕 * 2、弹出输掉游戏提示 * 3、弹出退出游戏的提示 * ======================== */removeAll();GLabel lose = new GLabel("What a pity! You lose!");lose.setFont("Times New Roman-36");add(lose,(getWidth()-lose.getWidth())/2,(getHeight()-lose.getAscent())/2);pause(1000);remove(lose);GLabel end = new GLabel("Click to end");end.setFont("Times New Roman-36");add(end,(getWidth()-end.getWidth())/2,(getHeight()-end.getAscent())/2);}private GObject getColliderObject() {/**getColliderObject()方法 * ======================================= * 用于追踪球与其它图像对象的碰撞 * 检查球的四个角点是否包含其他图像对象 * ======================================= */GObject check = getElementAt(ball.getX(),ball.getY());  //检查左上角if (check == null)check = getElementAt(ball.getX()+2*BALL_RADIUS,ball.getY());  //检查右上角if (check == null)check = getElementAt(ball.getX(),ball.getY()+2*BALL_RADIUS);  //检查左下角if (check == null)check = getElementAt(ball.getX()+2*BALL_RADIUS,ball.getY()+2*BALL_RADIUS);   //检查右下角if (check == null)check = getElementAt(ball.getX()+2*BALL_RADIUS,ball.getY()+2*BALL_RADIUS);   //检查右下角if (check == null)check = getElementAt(ball.getX()+2*BALL_RADIUS,ball.getY()+2*BALL_RADIUS);   //检查右下角return check;}/**=====================================================================================*/public void mouseClicked(MouseEvent e){  //单击鼠标时,将球板的中间位置与鼠标的位置对齐last = new GPoint(e.getPoint());paddle.move(e.getX()-paddle.getX()-PADDLE_WIDTH/2, 0);}public void mouseMoved(MouseEvent e){    //移动鼠标时,球板跟随鼠标一起移动if (last != null){paddle.move(e.getX()-last.getX(),0);last = new GPoint(e.getPoint());}}/**=====================================================================================*//**==================================== * 定义实例变量 * ==================================== * */private double vx,vy; //球的速度参数private GOval ball;private GRect rect;private Color color;private GRect paddle;  //球板private GLabel label;  //开始游戏提示标签private GPoint last;   //用于记录鼠标的位置private RandomGenerator rgen = new RandomGenerator();  //随机设定x轴方向的速度private GObject collider; //检查球与其他对象的碰撞}

原创粉丝点击