Java編程打磚塊游戲
初始需要定義的一些常量,和使用的庫(kù)。
- 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;
***步:創(chuàng)建游戲需要的磚塊,磚塊的行數(shù)和每行的數(shù)量都是確定的(NBRICK_ROWS,NBRICKS_PER_ROW),最上一排磚塊距窗口頂部距離 (BRICK_Y_OFFSET)。然后是顏色的填充,利用行數(shù)判斷所需的顏色。
- 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);
- }
- }
第二步:創(chuàng)建游戲所需的擋板
擋板的大小位置都是確定的;
- 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);
- }
比較有挑戓性的部分是能夠讓擋板隨著鼠標(biāo)移勱。擋板只需要在x軸方向上移動(dòng)。
加入鼠標(biāo)偵聽事件:addMouseListeners9();
和鼠標(biāo)拖拽事件的代碼:
- /* 單擊鼠標(biāo)事件 */
- public void mousePressed(MouseEvent e){
- last = new GPoint(e.getPoint());
- gobj = getElementAt(last);
- }
- /* 鼠標(biāo)拖動(dòng)事件 */
- public void mouseDragged(MouseEvent e){
- if(gobj != null){
- gobj.move(e.getX() - last.getX(), 0);
- last = new GPoint(e.getPoint());
- }
- }
這樣就可以使用鼠標(biāo)拖動(dòng)擋板了。但是還需要求擋板能移動(dòng)出游戲的邊界,所以加入判斷條件
- (gobj.getX() > 0 || e.getX() - last.getX() > 0) && (gobj.getX() + gobj.getWidth() < getWidth() || e.getX() - last.getX() < 0)
當(dāng)擋板移動(dòng)到左邊界時(shí),鼠標(biāo)需要向右移動(dòng)才有效,當(dāng)擋板移動(dòng)到右邊界時(shí),鼠標(biāo)需要向左移動(dòng)才有效。
- /* 鼠標(biāo)拖動(dòng)事件 */
- 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());
- }
- }
第三步:創(chuàng)建一個(gè)小球,使其在墻內(nèi)反彈;
程序需要記錄小球的速度。它由兩個(gè)獨(dú)立分量組成,你們可以按照下面的例子聲明實(shí)例變量:private double vx, vy;速度分量表示在每個(gè)時(shí)間區(qū)間位置的變化量。一開始,小球向下運(yùn)勱,初始速度vy可以設(shè)為+3.0(在Java 中,y 值向屏幕往下增加)。如果每個(gè)回合小球的路線都相同,游戲會(huì)很無(wú)聊,因此,vx 分量的值應(yīng)該隨機(jī)選取。
1. 聲明一個(gè)實(shí)例變量rgen, 隨機(jī)數(shù)生成器: private RandomGenerator rgen = RandomGenerator.getInstance();
2. 初始化vx 變量: vx = rgen.nextDouble(1.0, 3.0);if (rgen.nextBoolean(0.5)) vx=-vx; 返段代碼生成一個(gè)1.0到3.0間的雙浮點(diǎn)型隨機(jī)數(shù)賦給 vx,并按0.5 的概率將速度取反。這種算法比調(diào)用 nextDouble(-3.0, +3.0) 好很多,后者可能會(huì)出現(xiàn)小球幾乎垂直下落的情況,返對(duì)玩家來(lái)說太過于簡(jiǎn)單。
然后是讓小球在墻壁之間來(lái)回彈跳,先忽略擋板和磚塊的影響。
- /* 創(chuàng)建一個(gè)反彈的小球 */
- 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;
- }
- }
第四步:碰撞檢測(cè)
現(xiàn)在到了有趣的部分。為了使突破游戲更真實(shí),需要判斷小球是否和屏幕中其它物體產(chǎn)生了碰撞。
這里我為了讓其他方法能獲取ball和paddle的數(shù)據(jù)定義兩個(gè)實(shí)例變量:
private GOval BALL;
private GRect PADDLE;
然后分別在createBall和createPaddle中加入 BALL = ball 和 PADDLE = paddle;
創(chuàng)建碰撞檢測(cè)的方法
- private GObject getCollidingObject(){
- /* 小球的正切正方形的四個(gè)頂點(diǎn) */
- 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;
- }
- }
是用小球的正切正方形的四個(gè)點(diǎn)進(jìn)行判斷十分碰到擋板或磚塊;碰到擋板垂直反彈,碰到磚塊,消除方塊并反彈。
- if(collider == PADDLE){
- vy = -vy;
- } else if (collider != null){
- vy = -vy;
- remove(collider);
- n++;
- }
第五步:尾聲
1.加入游戲獲勝和失敗的判斷條件;
2.加入獲勝和失敗的反饋;
3.加入回合數(shù);
完整代碼:
- /*
- * 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));
- }
- }
- /*
- * 根據(jù)提供的數(shù)據(jù)創(chuàng)建游戲需要的磚塊;
- */
- 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);
- }
- }
- }
- /*
- * 創(chuàng)建一個(gè)可以用鼠標(biāo)拖動(dòng)的擋板;
- * 擋板不能被拖出屏幕邊界;
- */
- 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();
- }
- /* 單擊鼠標(biāo)事件 */
- public void mousePressed(MouseEvent e){
- last = new GPoint(e.getPoint());
- gobj = getElementAt(last);
- }
- /* 鼠標(biāo)拖動(dòng)事件 */
- 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());
- }
- }
- /* 創(chuàng)建一個(gè)反彈的小球 */
- 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; //記錄消除的磚塊數(shù)目;
- 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(){
- /* 小球的正切正方形的四個(gè)頂點(diǎn) */
- 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;
- }
- }
- /* 創(chuàng)建一個(gè)隨機(jī)數(shù)生成器 */
- private RandomGenerator rgen = RandomGenerator.getInstance();
- /* 小球移動(dòng)的實(shí)例變量 */
- private double vx, vy;
- /* 小球移動(dòng)的暫停時(shí)間 */
- 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 */
- }
剛開始學(xué),還有很多地方實(shí)現(xiàn)的不完善;
原文鏈接:http://www.cnblogs.com/mybluecode/archive/2012/12/17/2821370.html