前言
《JAVA打砖块》游戏是自制的游戏。玩家操作一根萤幕上水平的“棒子”,让一颗不断弹来弹去的“球”在撞击作为过关目标消去的“砖块”的途中不会落到萤幕底下。
主要设计
- 设计游戏界面,用swing实现
- 设计砖块,砖块类,
- 设计小球,满屏乱跑的小球类,负责打碎砖块
- 设计棒子,左右移动的木头板类
- 球碰到砖块、棒子与底下以外的三边会反弹,落到底下会失去一颗球,把砖块全部消去就可以破关。
- 小球碰到砖块的回调算法设计
- 小球碰到棒子的回调算法设计
- 设计碰撞特效,一个负责显示爆炸效果的类
- 设计音效类,碰撞时发出音效。
功能截图
游戏开始:
碰撞效果:
代码实现
游戏核心类
public class BricksGame extends BaseGame { private ArrayListlist = 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最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。
以上就是Java实现经典游戏打砖块游戏的示例代码的详细内容,更多关于Java打砖块游戏的资料请关注脚本之家其它相关文章!