《JAVA打砖块》游戏是自制的游戏。玩家操作一根萤幕上水平的“棒子”,让一颗不断弹来弹去的“球”在撞击作为过关目标消去的“砖块”的途中不会落到萤幕底下。。
游戏开始:
碰撞效果:
游戏核心类
public class BricksGame extends BaseGame {
private ArrayList<GameObject> list = new ArrayList<>();
private RenderTask render;
private Random random = new Random();
private boolean over;
private Image memImage;
private Graphics memG;// 双缓冲的画布
public BricksGame(int width, int height, String title) throws HeadlessException {
super(width, height, title);
super.setBgColor(new Color(0x23,0x30,0x41));
initGame(width, height);
}
private void initGame(int width, int height) {
setFps(60);
over=false;
// 获取窗口的内外大小
Container contentPane = this.getContentPane();
Dimension size = contentPane.getSize();
int contentWidth = size.width;
int contentHeight = size.height;
this.setContentWidth(contentWidth);
this.setContentHeight(contentHeight);
//System.out.println(contentPane instanceof JPanel);// true
//System.out.println(size.width);//582
//System.out.println(size.height);//403
// 窗口四个方向的边界值
Insets insets = getInsets();
//System.out.println(insets.top);
//System.out.println(insets.bottom);
//System.out.println(insets.left);
//System.out.println(insets.right);
Scene env = new Scene(width, height, new Margin(insets.left, insets.right, insets.top, insets.bottom));
ImageIcon woodIcon = new ImageIcon("image/wood.png");
int w = woodIcon.getIconWidth();
int h = woodIcon.getIconHeight();
Wood wood = new Wood(w, h, new Color(0x97, 0x5B, 0x12));
wood.setScene(env);
wood.setX(getWidth()/2 - w/2);
wood.setY(getHeight()-50);
wood.setImage(woodIcon.getImage());
list.add(wood);
Ball ball = new Ball(10, Color.WHITE);
ImageIcon iconBall = new ImageIcon("image/ball2.png");
ball.setImage(iconBall.getImage());
ball.setScene(env);
ball.setCoordinator(width / 2 - ball.getRadius(), wood.getY()-ball.getRadius()*2);
ball.setWoodBar(wood);
list.add(ball);
Color[] colors = new Color[]{
new Color(0xAA, 0xCF, 0x51),
new Color(0xFC, 0xA9, 0x4B),
new Color(0x73, 0xC7, 0xFF),
Color.PINK,
Color.GRAY
};
//ImageIcon brickIcon = new ImageIcon("image/brick_1.png");
int brW = 60;
int brH = 30;
int start = 25;
int brickX = start;
int brickY = 100;
int brickAreaWidth = getWidth() - start *2;
int count = brickAreaWidth / brW - 1;
int remainWidth = brickAreaWidth - count * brW;
int intervalHort = brW + 3;
start = brickX = (getWidth() - intervalHort * (count)) / 2;
int intervalVert = brH + 3;
HitBrick hitBrick = new HitBrick();
for (int j = 0; j < 3; j++) {// brick line
for(int i = 0; i< count; i++){// brick columns
Brick brick = new Brick();
brick.setColor(colors[i % colors.length]);
//brick.setImage(brickIcon.getImage());
brick.setWidth(brW);
brick.setHeight(brH);
brick.setX(brickX);
brick.setY(brickY);
brick.setBall(ball);
brick.setHitListener(hitBrick);
brickX += intervalHort;
list.add(brick);
}
brickX = start;
brickY += intervalVert;
}
// 双缓冲,在内存里面创建一个和窗口JFrame一样大小的Image
memImage = createImage(getWidth(), getHeight());
memG = memImage.getGraphics();
GameOver gameOver = new GameOver(memG);
ball.setGameOverListener(gameOver);
// 键盘事件的监听
Input input = new Input();
input.init();
addKeyListener(input);
// 重新渲染画面任务
render = new RenderTask(this);
render.start();
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
//super.mousePressed(e);
System.out.println(String.format("x:%d, y:%d", e.getX(), e.getY()));
//x:218,y:305,w:164,h:45
if ((e.getX() >= 218 && e.getX() <=(218+164))
&& (e.getY() >= 305 && e.getY() <= (305+45))
){
render.setExitd(true);
render = null;
memImage = null;
memG = null;
removeKeyListener(input);
removeMouseListener(this);
list.clear();
initGame(width, height);
}
}
});
}
@Override
public void paint(Graphics g) {
clear(memG);// 将画布清空为背景色
for (int i = 0; i < list.size(); i++) {
list.get(i).onTick();
list.get(i).draw(memG);
}
if (list.size() == 2){// 只剩下小球和挡板,则通关成功!
Wood wood = (Wood) list.get(0);
wood.setX(getWidth()/2 - wood.getWidth()/2);
wood.setY(getHeight()-50);
Ball ball = (Ball) list.get(1);
ball.setCoordinator(getWidth() / 2 - ball.getRadius(), /*bottom*/wood.getY()-ball.getRadius()*2);
ball.setMoving(false);
String gameOver = "恭喜通关!";
memG.setFont(new Font("Serif", Font.BOLD, 35));
int stringWidth = memG.getFontMetrics().stringWidth(gameOver);
memG.setColor(Color.RED);
memG.drawString(gameOver, getWidth()/2 - stringWidth/2, getHeight()/2);
stopRenderTask();
}
if (over) {
String gameOver = "Game Over";
memG.setFont(new Font("Serif", Font.BOLD, 35));
int stringWidth = memG.getFontMetrics().stringWidth(gameOver);
memG.setColor(Color.WHITE);
memG.drawString(gameOver, getWidth()/2 - stringWidth/2, getHeight()/2);
String playAgain = "重新开始";
stringWidth = memG.getFontMetrics().stringWidth(playAgain);
int increase = 16;
int fontSize = memG.getFont().getSize();
int rectH = (int) (fontSize * 1.3);
int rx=getWidth()/2 - stringWidth/2 - increase /2;
int ry=getHeight() - fontSize * 4-(rectH-fontSize)/2;
int rw = stringWidth + increase;
int rh = rectH;
//System.out.println(String.format("x:%d,y:%d,w:%d,h:%d", rx, ry, rw, rh));
memG.drawRect(rx, ry, rw, rh);
memG.setColor(new Color(33, 165, 230));
memG.drawString(playAgain, getWidth()/2 - stringWidth/2, getHeight() - fontSize * 3 - 5);
}
// 将内存Image的内容复制到窗口上
g.drawImage(memImage, 0, 0, null);
// 耗性能的轮询判断,一个对象是否要消失
for (int i = 2; i < list.size(); i++) {// 0,1位置是挡板和小球,不能消失
GameObject gameObject = list.get(i);
if (gameObject.isGone()) {
list.remove(i);
--i;
}
}
}
private void stopRenderTask() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
render.setExitd(true);
}
}).start();
}
public void exit(){
//System.exit(1);
}
public void clear(Graphics g){
if (g!=null) {
g.setColor(getBgColor());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
// 小球碰到砖块的回调
class HitBrick implements Brick.HitListener{
private ExecutorService executorService = Executors.newFixedThreadPool(3);
private File file = new File("audio/brick2.wav");
private AudioClip audio;
public HitBrick() {
try {
audio = Applet.newAudioClip(file.toURI().toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Override
public void hit(Brick brick) {
executorService.execute(new PlayHitAudioTask(audio));
ExplodeObject eo = new ExplodeObject();
eo.x = brick.x;
eo.y = brick.y;
eo.width = brick.width;
eo.height = brick.height;
eo.color = brick.color;
list.add(eo);
}
}
// 游戏结束内容的绘制
class GameOver implements Ball.GameOverListener{
private Graphics memG;
public GameOver(Graphics g) {
this.memG = g;
}
@Override
public void over() {
over = true;
}
}
}
小球类
public class Ball extends RectGameObject{
private int radius;
private int speed = 4;// 小球移动速度
private boolean moving;// 是否在移动
private boolean gameOver;// 是否over
private boolean postv;// 初始水平方向的移动左右方向
private int horiMove;// 水平移动距离(正负号代表移动方向)
private int vertMove;// 垂直移动距离(正负号代表移动方向)
private Wood woodBar;//木头板
private Image image;
private Point center = new Point();
private GameOverListener l;
public Ball(int radius, Color color){
this.radius = radius;
this.color = color;
}
@Override
public void draw(Graphics g) {
g.setColor(color);
//g.drawImage(image, x, y, null);
g.fillOval(x, y, radius * 2, radius * 2);
}
@Override
public void onTick() {
if (!moving){
if(Input.getKeyDown(KeyEvent.VK_UP)){
postv = (Math.random() * 10) <= 4 ? true : false;
moving = true;
gameOver = false;
horiMove = postv ? speed : -speed;
vertMove = -speed;
} /*else if(Input.getKeyDown(KeyEvent.VK_LEFT)){
Wood wb = woodBar;
if (!wb.isReachEdge()) {
transferBy(-wb.getSpeed(), 0);
}
} else if(Input.getKeyDown(KeyEvent.VK_RIGHT)){
Wood wb = woodBar;
if (!wb.isReachEdge()) {
transferBy(wb.getSpeed(), 0);
}
}*/
}
if (moving){
// arrive at left and right edge
Scene scene = getScene();
Margin margin = scene.in;
if (x <= margin.left || x >= scene.width - margin.right - radius * 2){
horiMove = -horiMove;
}
// arrive at top edge
if (y <= margin.top && vertMove < 0){
vertMove = -vertMove;
}
// 小球落在了挡板上
if(getCenter().x >= woodBar.getX()
&& getCenter().x <= woodBar.getX() + woodBar.getWidth()
&& Math.abs(getCenter().y - woodBar.y) <= radius
&& vertMove > 0
){
vertMove = -vertMove;
}
// arrive at bottom edge
// 小球落在了窗口的底部,停住小球 GAME OVER
if (y >= scene.height - margin.bottom - radius * 2){
moving = false;
gameOver = true;
if (l != null)
l.over();
return;
}
this.transferBy(horiMove, vertMove);
}
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
public Wood getWoodBar() {
return woodBar;
}
public void setWoodBar(Wood woodBar) {
this.woodBar = woodBar;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public boolean isMoving() {
return moving;
}
public void setMoving(boolean moving) {
this.moving = moving;
}
public int getHoriMove() {
return horiMove;
}
public void setHoriMove(int horiMove) {
this.horiMove = horiMove;
}
public int getVertMove() {
return vertMove;
}
public void setVertMove(int vertMove) {
this.vertMove = vertMove;
}
@Override
public int getWidth() {
return 2 * radius;
}
@Override
public int getHeight() {
return getWidth();
}
public Point getCenter(){
center.x = x + radius;
center.y = y + radius;
return center;
}
public boolean isGameOver() {
return gameOver;
}
public void setGameOver(boolean gameOver) {
this.gameOver = gameOver;
}
public GameOverListener getGameOverListener() {
return l;
}
public void setGameOverListener(GameOverListener l) {
this.l = l;
}
public interface GameOverListener{
void over();
}
}
砖块类
package game;
import java.awt.*;
public class Brick extends RectGameObject {
private Ball ball;
private Point leftTop = new Point();
private Point leftBottom = new Point();
private Point rightTop = new Point();
private Point rightBottom = new Point();
public Brick(){}
@Override
public void draw(Graphics g) {
g.setColor(getColor());
g.fillRect(x, y, getWidth(), getHeight());
}
@Override
public void onTick() {
if (ball.isMoving()) {
//start 碰撞检测/
boolean is = isSameQuadrant(ball.getCenter(), getLeftTop(), getRightBottom());
if (is) {
int r = ball.getRadius();
Point lt = getLeftTop();
Point lb = getLeftBottom();
Point rt = getRightTop();
Point rb = getRightBottom();
Point c = ball.getCenter();
int dx1 = Math.abs(c.x - lt.x), dy1 = Math.abs(c.y - lt.y);
int dx2 = Math.abs(c.x - lb.x), dy2 = Math.abs(c.y - lb.y);
int dx3 = Math.abs(c.x - rt.x), dy3 = Math.abs(c.y - rt.y);
int dx4 = Math.abs(c.x - rb.x), dy4 = Math.abs(c.y - rb.y);
if(((dx1*dx1) + (dy1*dy1) <= r*r)
||((dx2*dx2) + (dy2*dy2) <= r*r)
||((dx3*dx3) + (dy3*dy3) <= r*r)
||((dx4*dx4) + (dy4*dy4) <= r*r)){
System.out.println("发生了碰撞");
if (hitListener != null) {
hitListener.hit(this);
}
setGone(true);
}
} else {
Point c = ball.getCenter();
int squareW = ball.getRadius() * 2;
int squareH = squareW;
int brcx = x + getWidth() / 2;
int brcy = y + getHeight() / 2;
if((Math.abs(c.x - brcx) <= (squareW + getWidth())*0.5)
&&(Math.abs(c.y - brcy) <= (squareH + getHeight())*0.5)
){
System.out.println("......发生碰撞");
if (hitListener != null) {
hitListener.hit(this);
}
setGone(true);
/* 击中砖块,改变小球的方向 */
// 判断小球首先撞击的是砖块的左右还是上下侧,非常重要,否则出现不合理的移动方向。
double horizontal = (squareW + getWidth())*0.5 - Math.abs(c.x - brcx);
double vertical = (squareH + getHeight())*0.5 - Math.abs(c.y - brcy);
if (horizontal < vertical)
ball.setHoriMove(-ball.getHoriMove());
else
ball.setVertMove(-ball.getVertMove());
}
}
//end碰撞检测//
}
}
public Ball getBall() {
return ball;
}
public void setBall(Ball ball) {
this.ball = ball;
}
public Point getLeftTop(){
leftTop.x = x;
leftTop.y = y;
return leftTop;
}
public Point getRightTop(){
rightTop.x = x+getWidth();
rightTop.y = y;
return rightTop;
}
public Point getLeftBottom(){
leftBottom.x = x;
leftBottom.y = y + getHeight();
return leftBottom;
}
public Point getRightBottom(){
rightBottom.x = x + getWidth();
rightBottom.y = y + getHeight();
return rightBottom;
}
private HitListener hitListener;
public void setHitListener(HitListener hitListener){
this.hitListener = hitListener;
}
public interface HitListener {
void hit(Brick brick);
}
}
通过此次的《JAVA打砖块》实现,让我对JAVA的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。
java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。
点赞,关注博主后,私聊博主免费获取
需要技术指导,写项目程序,等更多服务请联系博主
今天是持续写作的第 21 / 100 天。
可以关注我,点赞我、评论我、收藏我啦。