初始需要定义的一些常量,和使用的库。
- 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;
- /** 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;
***步:创建游戏需要的砖块,砖块的行数和每行的数量都是确定的(NBRICK_ROWS,NBRICKS_PER_ROW),最上一排砖块距窗口顶部距离 (BRICK_Y_OFFSET)。然后是颜色的填充,利用行数判断所需的颜色。
- for(int i = 0; i < NBRICK_ROWS; i++){
- for(int j = 0; j < NBRICKS_PER_ROW; j++){
- GRect brick = new GRect(0 + j * (BRICK_WIDTH + BRICK_SEP), BRICK_Y_OFFSET + i * (BRICK_HEIGHT + BRICK_SEP), BRICK_WIDTH, BRICK_HEIGHT);
- brick.setFilled(true);
- if(i < 2){
- brick.setColor(Color.RED);
- } else if(i < 4){
- brick.setColor(Color.ORANGE);
- } else if(i < 6){
- brick.setColor(Color.YELLOW);
- } else if(i < 8){
- brick.setColor(Color.GREEN);
- } else {
- brick.setColor(Color.CYAN);
- }
- add(brick);
- }
- }
第二步:创建游戏所需的挡板
挡板的大小位置都是确定的;
- private void createPaddle(){
- /* HEIGHT 定义的是窗口高度所以要使用getHeight();*/
- GRect paddle = new GRect((WIDTH - PADDLE_WIDTH) / 2, getHeight() - PADDLE_HEIGHT - PADDLE_Y_OFFSET, PADDLE_WIDTH, PADDLE_HEIGHT);
- paddle.setFilled(true);
- paddle.setColor(Color.BLACK);
- add(paddle);
- }
比较有挑戓性的部分是能够让挡板随着鼠标移劢。挡板只需要在x轴方向上移动。
加入鼠标侦听事件:addMouseListeners9();
和鼠标拖拽事件的代码:
- /* 单击鼠标事件 */
- public void mousePressed(MouseEvent e){
- last = new GPoint(e.getPoint());
- gobj = getElementAt(last);
- }
- /* 鼠标拖动事件 */
- public void mouseDragged(MouseEvent e){
- if(gobj != null){
- gobj.move(e.getX() - last.getX(), 0);
- last = new GPoint(e.getPoint());
- }
- }
这样就可以使用鼠标拖动挡板了。但是还需要求挡板能移动出游戏的边界,所以加入判断条件
- (gobj.getX() > 0 || e.getX() - last.getX() > 0) && (gobj.getX() + gobj.getWidth() < getWidth() || e.getX() - last.getX() < 0)
当挡板移动到左边界时,鼠标需要向右移动才有效,当挡板移动到右边界时,鼠标需要向左移动才有效。
- /* 鼠标拖动事件 */
- public void mouseDragged(MouseEvent e){
- if(gobj != null && (gobj.getX() > 0 || e.getX() - last.getX() > 0) && (gobj.getX() + gobj.getWidth() < getWidth() || e.getX() - last.getX() < 0)){
- gobj.move(e.getX() - last.getX(), 0);
- last = new GPoint(e.getPoint());
- }
- }
第三步:创建一个小球,使其在墙内反弹;
程序需要记录小球的速度。它由两个独立分量组成,你们可以按照下面的例子声明实例变量:private double vx, vy;速度分量表示在每个时间区间位置的变化量。一开始,小球向下运劢,初始速度vy可以设为+3.0(在Java 中,y 值向屏幕往下增加)。如果每个回合小球的路线都相同,游戏会很无聊,因此,vx 分量的值应该随机选取。
1. 声明一个实例变量rgen, 随机数生成器: private RandomGenerator rgen = RandomGenerator.getInstance();
2. 初始化vx 变量: vx = rgen.nextDouble(1.0, 3.0);if (rgen.nextBoolean(0.5)) vx=-vx; 返段代码生成一个1.0到3.0间的双浮点型随机数赋给 vx,并按0.5 的概率将速度取反。这种算法比调用 nextDouble(-3.0, +3.0) 好很多,后者可能会出现小球几乎垂直下落的情况,返对玩家来说太过于简单。
然后是让小球在墙壁之间来回弹跳,先忽略挡板和砖块的影响。
- /* 创建一个反弹的小球 */
- private void createBall(){
- GOval ball = new GOval((getWidth() - 2 * BALL_RADIUS) / 2, (getHeight() - 2 * BALL_RADIUS) / 2, BALL_RADIUS, BALL_RADIUS);
- ball.setFilled(true);
- add(ball);
- vy = 3.0;
- vx = rgen.nextDouble(1.0, 3.0);
- if(rgen.nextBoolean(0.5)) vx = -vx;
- while(true){
- ball.move(vx,vy);
- pause(PAUSE_TIME);
- if(ball.getX() < 0 || ball.getX() + 2 * BALL_RADIUS > getWidth()) vx = -vx;
- if(ball.getY() < 0 || ball.getY() + 2 * BALL_RADIUS > getHeight()) vy = -vy;
- }
- }
第四步:碰撞检测
现在到了有趣的部分。为了使突破游戏更真实,需要判断小球是否和屏幕中其它物体产生了碰撞。
这里我为了让其他方法能获取ball和paddle的数据定义两个实例变量:
private GOval BALL;
private GRect PADDLE;
然后分别在createBall和createPaddle中加入 BALL = ball 和 PADDLE = paddle;
创建碰撞检测的方法
- private GObject getCollidingObject(){
- /* 小球的正切正方形的四个顶点 */
- double x1 = BALL.getX();
- double y1 = BALL.getY();
- double x2 = BALL.getX() + 2 * BALL_RADIUS;
- double y2 = BALL.getY();
- double x3 = BALL.getX() + 2 * BALL_RADIUS;
- double y3 = BALL.getY() + 2 * BALL_RADIUS;
- double x4 = BALL.getX();
- double y4 = BALL.getY() + 2 * BALL_RADIUS;
- if(getElementAt(x1,y1) != null){
- return getElementAt(x1,y1);
- } else if(getElementAt(x2,y2) != null){
- return getElementAt(x2,y2);
- } else if(getElementAt(x3,y3) != null){
- return getElementAt(x3,y3);
- } else if(getElementAt(x4,y4) != null){
- return getElementAt(x4,y4);
- } else{
- return null;
- }
- }
是用小球的正切正方形的四个点进行判断十分碰到挡板或砖块;碰到挡板垂直反弹,碰到砖块,消除方块并反弹。
- if(collider == PADDLE){
- vy = -vy;
- } else if (collider != null){
- vy = -vy;
- remove(collider);
- n++;
- }
第五步:尾声
1.加入游戏获胜和失败的判断条件;
2.加入获胜和失败的反馈;
3.加入回合数;
完整代码:
- /*
- * File: Breakout.java
- * -------------------
- * Name:
- * Section Leader:
- *
- * This file will eventually implement the game of Breakout.
- */
- 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;
- /** 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;
- /* Method: run() */
- /** Runs the Breakout program. */
- public void run() {
- createAllBrick(NBRICK_ROWS, NBRICKS_PER_ROW);
- createPaddle();
- int i = 0;
- while(i < NTURNS){
- createBall();
- i++;
- if (isWin == 1) break;
- }
- if(i == 3){
- add(new GLabel("YOU LOSE", getWidth() / 2, getHeight() / 2));
- }
- }
- /*
- * 根据提供的数据创建游戏需要的砖块;
- */
- private void createAllBrick(int row, int rank){
- for(int i = 0; i < row; i++){
- for(int j = 0; j < rank; j++){
- GRect brick = new GRect(0 + j * (BRICK_WIDTH + BRICK_SEP), BRICK_Y_OFFSET + i * (BRICK_HEIGHT + BRICK_SEP), BRICK_WIDTH, BRICK_HEIGHT);
- brick.setFilled(true);
- if(i < 2){
- brick.setColor(Color.RED);
- } else if(i < 4){
- brick.setColor(Color.ORANGE);
- } else if(i < 6){
- brick.setColor(Color.YELLOW);
- } else if(i < 8){
- brick.setColor(Color.GREEN);
- } else {
- brick.setColor(Color.CYAN);
- }
- add(brick);
- }
- }
- }
- /*
- * 创建一个可以用鼠标拖动的挡板;
- * 挡板不能被拖出屏幕边界;
- */
- private void createPaddle(){
- /* HEIGHT 定义的是窗口高度所以要使用getHeight();*/
- GRect paddle = new GRect((WIDTH - PADDLE_WIDTH) / 2, getHeight() - PADDLE_HEIGHT - PADDLE_Y_OFFSET, PADDLE_WIDTH, PADDLE_HEIGHT);
- PADDLE = paddle;
- paddle.setFilled(true);
- paddle.setColor(Color.BLACK);
- add(paddle);
- addMouseListeners();
- }
- /* 单击鼠标事件 */
- public void mousePressed(MouseEvent e){
- last = new GPoint(e.getPoint());
- gobj = getElementAt(last);
- }
- /* 鼠标拖动事件 */
- public void mouseDragged(MouseEvent e){
- if(gobj != null && (gobj.getX() > 0 || e.getX() - last.getX() > 0) && (gobj.getX() + gobj.getWidth() < getWidth() || e.getX() - last.getX() < 0)){
- gobj.move(e.getX() - last.getX(), 0);
- last = new GPoint(e.getPoint());
- }
- }
- /* 创建一个反弹的小球 */
- private void createBall(){
- GOval ball= new GOval((getWidth() - 2 * BALL_RADIUS) / 2, (getHeight() - 2 * BALL_RADIUS) / 2, BALL_RADIUS, BALL_RADIUS);
- ball.setFilled(true);
- BALL = ball;
- add(ball);
- int n = 0; //记录消除的砖块数目;
- vy = 3.0;
- vx = rgen.nextDouble(1.0, 3.0);
- if(rgen.nextBoolean(0.5)) vx = -vx;
- while(true){
- ball.move(vx,vy);
- GObject collider = getCollidingObject();
- pause(PAUSE_TIME);
- if(collider == PADDLE){
- vy = -vy;
- } else if (collider != null){
- vy = -vy;
- remove(collider);
- n++;
- if (n == 100){
- add(new GLabel("YOU WIN!", getWidth() /2, getHeight() / 2));//显示消息;
- remove(ball);
- isWin = 1;
- break;
- }
- }
- if(ball.getX() < 0 || ball.getX() + 2 * BALL_RADIUS > getWidth()) vx = -vx;
- if(ball.getY() < 0) vy = -vy;
- if(ball.getY() + 2 * BALL_RADIUS > getHeight()){
- remove(ball);
- break;
- }
- }
- }
- private GObject getCollidingObject(){
- /* 小球的正切正方形的四个顶点 */
- double x1 = BALL.getX();
- double y1 = BALL.getY();
- double x2 = BALL.getX() + 2 * BALL_RADIUS;
- double y2 = BALL.getY();
- double x3 = BALL.getX() + 2 * BALL_RADIUS;
- double y3 = BALL.getY() + 2 * BALL_RADIUS;
- double x4 = BALL.getX();
- double y4 = BALL.getY() + 2 * BALL_RADIUS;
- if(getElementAt(x1,y1) != null){
- return getElementAt(x1,y1);
- } else if(getElementAt(x2,y2) != null){
- return getElementAt(x2,y2);
- } else if(getElementAt(x3,y3) != null){
- return getElementAt(x3,y3);
- } else if(getElementAt(x4,y4) != null){
- return getElementAt(x4,y4);
- } else{
- return null;
- }
- }
- /* 创建一个随机数生成器 */
- private RandomGenerator rgen = RandomGenerator.getInstance();
- /* 小球移动的实例变量 */
- private double vx, vy;
- /* 小球移动的暂停时间 */
- private int PAUSE_TIME = 20;
- private GOval BALL;
- private GRect PADDLE;
- private int isWin = 0;/* 是否获胜 */
- private GObject gobj; /* The object being dragged */
- private GPoint last; /* The last mouse position */
- }
刚开始学,还有很多地方实现的不完善;
原文链接:http://www.cnblogs.com/mybluecode/archive/2012/12/17/2821370.html