package org.crazyit.ball; import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
import java.io.IOException; /**
* 小球对象
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class Ball extends BallComponent {
// 定义球的竖向速度
private int speedY = 10;
// 定义弹球的横向速度
private int speedX = 8;
// 定义是否在运动
private boolean started = false;
// 定义是否结束运动
private boolean stop = false; /**
* m 有参数构造器
*
* @param panelWidth
* int 画板宽度
* @param panelHeight
* int 画板高度
* @param offset
* int 位移
* @param path
* String 图片路径
*/
public Ball(int panelWidth, int panelHeight, int offset, String path)
throws IOException {
// 调用父构造器
super(panelWidth, panelHeight, path);
// 设置y坐标
this.setY(panelHeight - super.getImage().getHeight(null) - offset);
} /**
* 设置横向速度
*
* @param speed
* int 速度
* @return void
*/
public void setSpeedX(int speed) {
this.speedX = speed;
} /**
* 设置竖向速度
*
* @param speed
* int 速度
* @return void
*/
public void setSpeedY(int speed) {
this.speedY = speed;
} /**
* 设置是否在运动
*
* @param b
* boolean
* @return void
*/
public void setStarted(boolean b) {
this.started = b;
} /**
* 设置是否结束运动
*
* @param b
* boolean
* @return void
*/
public void setStop(boolean b) {
this.stop = b;
} /**
* 返回横向速度
*
* @return int 速度
*/
public int getSpeedX() {
return this.speedX;
} /**
* 返回竖向速度
*
* @return int 速度
*/
public int getSpeedY() {
return this.speedY;
} /**
* 是否在运动
*
* @return boolean 是否在运动
*/
public boolean isStarted() {
return this.started;
} /**
* 是否已经结束运动
*
* @return boolean 是否已经结束运动
*/
public boolean isStop() {
return this.stop;
} }
Ball
package org.crazyit.ball; import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
import java.io.IOException; /**
* 桌面弹球游戏相关组件的父类
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class BallComponent {
// 设置x坐标
private int x = -1;
// 设置y坐标
private int y = -1;
// 设置图片
private Image image = null;
// 设置图片速度
private int speed = 5; /**
* 构造器
*
* @param path
* String 图片路径
*/
public BallComponent(String path) throws IOException {
super();
this.image = ImageIO.read(new File(path));
} /**
* 构造器
*
* @param panelWidth
* int 画板宽度
* @param panelHeight
* int 画板高度
* @param path
* String 图片路径
*/
public BallComponent(int panelWidth, int panelHeight, String path)
throws IOException {
super();
// 读取图片
this.image = ImageIO.read(new File(path));
// 设置x坐标
this.x = (int) ((panelWidth - image.getWidth(null)) / 2);
} /**
* 构造器
*
* @param x
* int 图像的x坐标
* @param y
* int 图像的y坐标
* @param path
* String 图片路径
*/
public BallComponent(String path, int x, int y) throws IOException {
super();
// 读取图片
this.image = ImageIO.read(new File(path));
this.x = x;
this.y = y;
} /**
* 获取x坐标
*
* @return int x坐标
*/
public int getX() {
return this.x;
} /**
* 获取y坐标
*
* @return int y坐标
*/
public int getY() {
return this.y;
} /**
* 获取图片速度
*
* @return int 图片速度
*/
public int getSpeed() {
return this.speed;
} /**
* 设置x坐标
*
* @param x
* int x坐标
* @return void
*/
public void setX(int x) {
this.x = x;
} /**
* 设置y坐标
*
* @param y
* int y坐标
* @return void
*/
public void setY(int y) {
this.y = y;
} /**
* 返回图片
*
* @return Image 图片
*/
public Image getImage() {
return this.image;
}
}
BallComponent
package org.crazyit.ball; import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.IOException; /**
* 游戏界面
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class BallFrame extends JFrame {
// 定义JPanel的宽度
private final int BALLPANEL_WIDTH = 307;
// 定义JPanel的高度
private final int BALLPANEL_HEIGHT = 400;
// 定义画板
private BallPanel ballPanel = null;
// 定义档板
// private Image stick = null;
// 设置档板x坐标
private int stickX = -1;
// 创建一个BallService实例
private BallService service = null;
// 定义一个timer
Timer timer = null; /**
* 默认构造器
*/
public BallFrame() throws IOException {
super();
// 初始化
initialize();
} /**
* 初始化界面
*
* @return void
*/
public void initialize() throws IOException {
// 设置窗口的标题
this.setTitle("弹球");
// 设置为不可改变大小
this.setResizable(false);
// 设置背景为黑色
this.setBackground(Color.BLACK);
// 获取画板
ballPanel = getBallPanel();
// 创建BallService实例
service = new BallService(this, BALLPANEL_WIDTH, BALLPANEL_HEIGHT); // 定义每0.1秒执行一次监听器
ActionListener task = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 开始改变位置
service.run();
// 刷新画板
ballPanel.repaint();
}
};
// 如果timer不为空
if (timer != null) {
// 重新开始timer
timer.restart();
} else {
// 新建一个timer
timer = new Timer(100, task);
// 开始timer
timer.start();
} this.add(ballPanel);
// 增加事件监听器
KeyListener[] klarr = this.getKeyListeners();
if (klarr.length == 0) {
// 定义键盘监听适配器
KeyListener keyAdapter = new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
// 改变档板的坐标
service.setStickPos(ke);
}
};
this.addKeyListener(keyAdapter);
}
} /**
* 获取画板
*
* @return BallPanel 返回BallPanle
*/
public BallPanel getBallPanel() { if (ballPanel == null) {
// 新建一个画板
ballPanel = new BallPanel();
// 设置画板的大小
ballPanel.setPreferredSize(new Dimension(BALLPANEL_WIDTH,
BALLPANEL_HEIGHT));
}
return ballPanel;
} // 定义一个JPanel内部类来完成画图功能
public class BallPanel extends JPanel {
/**
* 重写void paint( Graphics g )方法
*
* @param g
* Graphics
* @return void
*/
public void paint(Graphics g) {
// 画图
service.draw(g);
}
} }
BallFrame
package org.crazyit.ball; import java.io.IOException; import javax.swing.JFrame; /**
* 游戏入口类
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class BallGame {
/**
* 开始游戏
*
* @return void
*/
public static void main(String[] args) throws IOException {
BallFrame ballFrame = new BallFrame();
ballFrame.pack();
ballFrame.setVisible(true);
ballFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
BallGame
package org.crazyit.ball; import java.awt.event.KeyEvent;
import java.awt.Image;
import java.awt.Graphics;
import java.io.IOException; /**
* 处理游戏逻辑的对象
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class BallService {
// 定义一个Stick(档板)
private Stick stick = null;
// 定义一个弹球
private Ball ball = null;
// 定义一个游戏结束图片
private BallComponent gameOver = null;
// 定义一个赢了游戏的图片
private BallComponent won = null;
// 定义一个砖块图片数组
private Brick[][] bricks = null;
private int width;
private int height;
BallFrame ballFrame = null; /**
* 私有空构造器
*/
private BallService() {
super();
} /**
*
* @param frame
* JFrame JFrame实例
* @param width
* int 宽
* @param height
* int 高
* @return BallService
*/
public BallService(BallFrame frame, int width, int height)
throws IOException {
// 初始化变量
this.width = width;
this.height = height;
this.ballFrame = frame;
// 创建一个Stick(档板)实例
stick = new Stick(width, height, "img/stick.jpg");
// 创建一个弹球的实例
ball = new Ball(width, height, stick.getImage().getHeight(null),
"img/ball.gif");
// 游戏结束图片
gameOver = new BallComponent("img/over.gif");
// 赢图片
won = new BallComponent("img/win.gif");
// 砖块图片数组
bricks = createBrickArr("img/brick.gif", 11, 6);
} /**
* run
*
* @return void
*/
public void run() {
// 弹球坐标改变
setBallPos();
// 道具坐标改改变
setMagicPos();
} /**
* 设置档板图片的位置
*
* @param ke
* KeyEvent 键盘事件
* @return void
*/
public void setStickPos(KeyEvent ke) {
// 把弹球的运动状态设为true
ball.setStarted(true);
// 如果是左方向键
if (ke.getKeyCode() == KeyEvent.VK_LEFT) {
if (stick.getX() - stick.SPEED > 0) {
// x坐标向左移动
stick.setX(stick.getX() - stick.SPEED);
}
}
// 如果是右方向键
if (ke.getKeyCode() == KeyEvent.VK_RIGHT) {
if (stick.getX() + stick.SPEED < width - stick.getPreWidth()) {
// x坐标向右移动
stick.setX(stick.getX() + stick.SPEED);
// ballFrame.getBallGame().reStart( ballFrame );
}
}
// 如果是F2键
if (ke.getKeyCode() == KeyEvent.VK_F2) {
// 初始化ballFrame
try {
ballFrame.initialize();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
} /**
* 设置小球图片的位置
*
* @return void
*/
public void setBallPos() {
// 正数的数度
int absSpeedX = Math.abs(ball.getSpeedX());
int absSpeedY = Math.abs(ball.getSpeedY());
// 如果游戏已经开始而且没有结束
if (ball.isStarted()) {
// 如果小球碰到左边界
if (ball.getX() - absSpeedX < 0) {
// 重新设置x坐标
ball.setX(ball.getImage().getWidth(null));
// 把x方向的速度设为反方向
ball.setSpeedX(-ball.getSpeedX());
}
// 如果小球碰到右边界
if (ball.getX() + absSpeedX > width
- ball.getImage().getWidth(null)) {
// 重新设置x坐标
ball.setX(width - ball.getImage().getWidth(null) * 2);
// 把x方向的速度设为反方向
ball.setSpeedX(-ball.getSpeedX());
}
// 如果小球碰到上边界
if (ball.getY() - absSpeedY < 0) {
// 重新设置y坐标
ball.setY(ball.getImage().getWidth(null));
// 把y方向的速度设为反方向
ball.setSpeedY(-ball.getSpeedY());
}
// 如果小球碰到下边界
if (ball.getY() + absSpeedY > height
- stick.getImage().getHeight(null)) {
// 如果小球与档板有碰撞
if (isHitStick(ball)) {
// 重新设置y坐标
ball.setY(height - ball.getImage().getHeight(null) * 2);
// 把y方向的速度设为反方向
ball.setSpeedY(-ball.getSpeedY());
}
}
// 与砖块碰撞后的运动
for (int i = bricks.length - 1; i > -1; i--) {
for (int j = bricks[i].length - 1; j > -1; j--) {
// 如果小球与砖块有碰撞
if (isHitBrick(bricks[i][j])) {
if (ball.getSpeedY() > 0) {
ball.setSpeedY(-ball.getSpeedY());
}
}
}
}
// 结束游戏
if (ball.getY() > height) {
ball.setStop(true);
} // 设置x坐标
ball.setX(ball.getX() - (int) (Math.random() * 2)
- ball.getSpeedX());
// 设置y坐标
ball.setY(ball.getY() - (int) (Math.random() * 2)
- ball.getSpeedY());
}
} /**
* 小球与砖块是否有碰撞
*
* @return boolean
*/
public boolean isHitBrick(Brick brick) {
if (brick.isDisable()) {
return false;
}
// ball的圆心x坐标
double ballX = ball.getX() + ball.getImage().getWidth(null) / 2;
// ball的圆心y坐标
double ballY = ball.getY() + ball.getImage().getHeight(null) / 2;
// brick的中心x坐标
double brickX = brick.getX() + brick.getImage().getWidth(null) / 2;
// brick的中心y坐标
double brickY = brick.getY() + brick.getImage().getHeight(null) / 2;
// 两个坐标点的距离
double distance = Math.sqrt(Math.pow(ballX - brickX, 2)
+ Math.pow(ballY - brickY, 2));
// 如果两个图形重叠,返回true;
if (distance < (ball.getImage().getWidth(null) + brick.getImage()
.getWidth(null)) / 2) {
// 使brick无效
brick.setDisable(true);
return true; }
return false;
} /**
* BallComponent是否与档板有碰撞
*
* @param image
* BallComponent 图像
* @return boolean
*/
public boolean isHitStick(BallComponent bc) {
// 获取图片对象
Image tempImage = bc.getImage();
// 如果与档板有碰撞
if (bc.getX() + tempImage.getWidth(null) > stick.getX()
&& bc.getX() < stick.getX() + stick.getPreWidth()
&& bc.getY() + tempImage.getHeight(null) > stick.getY()) {
return true;
}
return false;
} /**
* 设置道具的位置
*
* @return void
*/
public void setMagicPos() {
for (int i = 0; i < bricks.length; i++) {
for (int j = 0; j < bricks[i].length; j++) {
// 获取magic
Magic magic = bricks[i][j].getMagic();
if (magic != null) {
// 如果这个brick的状态是无效的
if (bricks[i][j].isDisable() && magic.getY() < height) {
// 设置magic的y坐标向下增加
magic.setY(magic.getY() + magic.getSpeed());
// 设置档板的宽度
setStickWidth(magic); }
}
}
}
} /**
* 设置档板的长度
*
* @param magic
* Magic 道具
* @return void
*/
public void setStickWidth(Magic magic) {
if (isHitStick(magic)) {
// 道具的作用
magic.magicDo(stick);
}
} /**
* 判断是否赢了
*
* @return boolean
*/
public boolean isWon() {
// 如果消了全部砖块,则为赢
for (int i = 0; i < bricks.length; i++) {
for (int j = 0; j < bricks[i].length; j++) {
if (!bricks[i][j].isDisable()) {
return false;
}
}
}
return true;
} /**
* 创建一个类型为Brick的数组
*
* @param path
* String 图像路径
* @param xSize
* int
* @param ySize
* int
* @return Brick[][]
*/
public Brick[][] createBrickArr(String path, int xSize, int ySize)
throws IOException {
// 创建一个Brick[][]
Brick[][] bricks = new Brick[xSize][ySize];
int x = 0;
int y = 0;
int random = 0;
int imageSize = 28;
boolean isDisable = false;
// 迭代初始化数组
for (int i = 0; i < xSize; i++) {
for (int j = 0; j < ySize; j++) {
// 创建一个新的砖块
random = (int) (Math.random() * 3);
x = i * imageSize;
y = j * imageSize;
// 一定机率没有砖块
isDisable = Math.random() > 0.8 ? true : false;
if (isDisable) {
random = 0;
}
Brick brick = new Brick(path, random, x, y);
brick.setDisable(isDisable);
// 设置x坐标
brick.setX(x);
// 设置y坐标
brick.setY(y);
bricks[i][j] = brick;
}
}
return bricks;
} /**
* 画图
*
* @param g
* Graphics 用来画图的对象
* @return void
*/
public void draw(Graphics g) {
// 如果赢了
if (isWon()) {
// 绘制赢的图片
g.drawImage(won.getImage(), won.getX(), won.getY(), width,
height - 10, null);
} else if (ball.isStop()) {
// 绘制游戏结束图像
g.drawImage(gameOver.getImage(), gameOver.getX(), gameOver.getY(),
width, height - 10, null);
} else {
// 清除原来的图像
g.clearRect(0, 0, width, height);
// 绘制档板图像
g.drawImage(stick.getImage(), stick.getX(), stick.getY(), stick
.getPreWidth(), stick.getImage().getHeight(null), null);
// 绘制弹球图像
g.drawImage(ball.getImage(), ball.getX(), ball.getY(), null);
// 迭代绘制砖块图像
for (int i = 0; i < bricks.length; i++) {
for (int j = 0; j < bricks[i].length; j++) {
BallComponent magic = bricks[i][j].getMagic();
// 如果这个砖块图像对像是有效的
if (!bricks[i][j].isDisable()) {
// 里面的数字1为砖块图像间的间隙
g.drawImage(bricks[i][j].getImage(), bricks[i][j]
.getX(), bricks[i][j].getY(), bricks[i][j]
.getImage().getWidth(null) - 1, bricks[i][j]
.getImage().getHeight(null) - 1, null);
} else if (magic != null && magic.getY() < height) {
g.drawImage(magic.getImage(), magic.getX(), magic
.getY(), null);
}
}
}
}
}
}
BallService
package org.crazyit.ball; import java.awt.Image;
import java.io.IOException; /**
* 砖块类
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class Brick extends BallComponent { // 定义道具
private Magic magic = null;
// 定义一个boolean变量设置本类是否有效
private boolean disable = false;
public static final int MAGIC_LONG_TYPE = 1;
public static final int MAGIC_SHORT_TYPE = 2; /**
* 构造器
*
* @return void
*/
public Brick(String path, int type, int x, int y) throws IOException {
super(path);
if (type == Brick.MAGIC_LONG_TYPE) {
this.magic = new LongMagic("img/long.gif", x, y);
} else if (type == Brick.MAGIC_SHORT_TYPE) {
this.magic = new ShortMagic("img/short.gif", x, y);
}
if (this.magic != null) {
this.magic.setX(x);
this.magic.setY(y);
}
} /**
* 设置本类有没有效
*
* @param disable
* boolean
* @return void
*/
public void setDisable(boolean disable) {
this.disable = disable;
} /**
* 查看本类有没有效
*
* @return boolean 是否有效
*/
public boolean isDisable() {
return this.disable;
} /**
* 获取道具
*
* @return String magic
*/
public Magic getMagic() {
return this.magic;
} /**
* 设置道具
*
* @return String magic
*/
public void setMagic(Magic magic) {
this.magic = magic;
}
}
Brick
package org.crazyit.ball; import java.io.IOException; /**
* 道具对象
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public abstract class Magic extends BallComponent {
/**
* 提供给子类调用的构造器
*
* @param path
* String 文件路径
* @param x
* int x坐标
* @param y
* int y坐标
*/
public Magic(String path, int x, int y) throws IOException {
super(path, x, y);
} /**
* 道具的功能
*
* @param stitck
* Stick
* @return void
*/
public abstract void magicDo(Stick stick);
}
Magic
package org.crazyit.ball; import java.io.IOException; /**
* 使挡板变长的道具
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class LongMagic extends Magic {
/**
* 构造器
*
* @param path
* String 文件路径
* @param x
* int x坐标
* @param y
* int y坐标
*/
public LongMagic(String path, int x, int y) throws IOException {
super(path, x, y);
} /**
* 道具的功能 : 档板变长
*
* @param stitck
* Stick
* @return void
*/
public void magicDo(Stick stick) {
double imageWidth = stick.getImage().getWidth(null);
// 如果档板没有变长过
if (stick.getPreWidth() <= imageWidth) {
// 将档板的长度改为双倍
stick.setPreWidth((int) (stick.getPreWidth() * 2));
}
}
}
LongMagic
package org.crazyit.ball; import java.io.IOException; /**
* 使挡板变短的道具
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class ShortMagic extends Magic {
/**
* 构造器
*
* @param path
* String 文件路径
* @param x
* int x坐标
* @param y
* int y坐标
*/
public ShortMagic(String path, int x, int y) throws IOException {
super(path, x, y);
} /**
* 道具的功能 : 档板变短
*
* @param stitck
* Stick
* @return void
*/
public void magicDo(Stick stick) {
double imageWidth = stick.getImage().getWidth(null);
// 如果档板没有变短过
if (stick.getPreWidth() >= imageWidth) {
// 将档板的宽度改为一半
stick.setPreWidth((int) (stick.getPreWidth() * 0.5));
}
}
}
ShortMagic
package org.crazyit.ball; import java.io.IOException; /**
* 挡板类
*
* @author yangenxiong yangenxiong2009@gmail.com
* @author Kelvin Mak kelvin.mak125@gmail.com
* @version 1.0
* <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
* <br>Copyright (C), 2009-2010, yangenxiong
* <br>This program is protected by copyright laws.
*/
public class Stick extends BallComponent {
// 定义档板移动的速度
public static final int SPEED = 20;
// 定义档板初始的长度
private int preWidth = 0; /**
* 有参数构造器
*
* @param panelWidth
* int 画板宽度
* @param panelHeight
* int 画板高度
* @param path
* String 图片路径
*/
public Stick(int panelWidth, int panelHeight, String path)
throws IOException {
// 调用父构造器
super(panelWidth, panelHeight, path);
// 设置y坐标
this.setY(panelHeight - super.getImage().getHeight(null));
// 设置原本的长度
this.preWidth = super.getImage().getWidth(null);
} /**
* 获取初始长度
*
* @return int 初始长度
*/
public int getPreWidth() {
return this.preWidth;
} /**
* 设置初始长度
*
* @return void
*/
public void setPreWidth(int preWidth) {
this.preWidth = preWidth;
} }
Stick