Java實(shí)現(xiàn)經(jīng)典游戲打磚塊游戲的示例代碼
前言
《JAVA打磚塊》游戲是自制的游戲。玩家操作一根螢?zāi)簧纤降?ldquo;棒子”,讓一顆不斷彈來(lái)彈去的“球”在撞擊作為過(guò)關(guān)目標(biāo)消去的“磚塊”的途中不會(huì)落到螢?zāi)坏紫隆?/p>
主要設(shè)計(jì)
- 設(shè)計(jì)游戲界面,用swing實(shí)現(xiàn)
- 設(shè)計(jì)磚塊,磚塊類,
- 設(shè)計(jì)小球,滿屏亂跑的小球類,負(fù)責(zé)打碎磚塊
- 設(shè)計(jì)棒子,左右移動(dòng)的木頭板類
- 球碰到磚塊、棒子與底下以外的三邊會(huì)反彈,落到底下會(huì)失去一顆球,把磚塊全部消去就可以破關(guān)。
- 小球碰到磚塊的回調(diào)算法設(shè)計(jì)
- 小球碰到棒子的回調(diào)算法設(shè)計(jì)
- 設(shè)計(jì)碰撞特效,一個(gè)負(fù)責(zé)顯示爆炸效果的類
- 設(shè)計(jì)音效類,碰撞時(shí)發(fā)出音效。
功能截圖
游戲開(kāi)始:
碰撞效果:
代碼實(shí)現(xiàn)
游戲核心類
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;// 雙緩沖的畫(huà)布 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; // 獲取窗口的內(nèi)外大小 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 // 窗口四個(gè)方向的邊界值 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; } // 雙緩沖,在內(nèi)存里面創(chuàng)建一個(gè)和窗口JFrame一樣大小的Image memImage = createImage(getWidth(), getHeight()); memG = memImage.getGraphics(); GameOver gameOver = new GameOver(memG); ball.setGameOverListener(gameOver); // 鍵盤(pán)事件的監(jiān)聽(tīng) Input input = new Input(); input.init(); addKeyListener(input); // 重新渲染畫(huà)面任務(wù) 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);// 將畫(huà)布清空為背景色 for (int i = 0; i < list.size(); i++) { list.get(i).onTick(); list.get(i).draw(memG); } if (list.size() == 2){// 只剩下小球和擋板,則通關(guān)成功! 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 = "恭喜通關(guān)!"; 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 = "重新開(kāi)始"; 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); } // 將內(nèi)存Image的內(nèi)容復(fù)制到窗口上 g.drawImage(memImage, 0, 0, null); // 耗性能的輪詢判斷,一個(gè)對(duì)象是否要消失 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()); } } // 小球碰到磚塊的回調(diào) 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); } } // 游戲結(jié)束內(nèi)容的繪制 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;// 小球移動(dòng)速度 private boolean moving;// 是否在移動(dòng) private boolean gameOver;// 是否over private boolean postv;// 初始水平方向的移動(dòng)左右方向 private int horiMove;// 水平移動(dòng)距離(正負(fù)號(hào)代表移動(dòng)方向) private int vertMove;// 垂直移動(dòng)距離(正負(fù)號(hào)代表移動(dòng)方向) 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 碰撞檢測(cè)///////////////////////////////////////////// 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("發(fā)生了碰撞"); 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("......發(fā)生碰撞"); if (hitListener != null) { hitListener.hit(this); } setGone(true); /* 擊中磚塊,改變小球的方向 */ // 判斷小球首先撞擊的是磚塊的左右還是上下側(cè),非常重要,否則出現(xiàn)不合理的移動(dòng)方向。 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碰撞檢測(cè)////////////////////////////////////////////// } } 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); } }
總結(jié)
通過(guò)此次的《JAVA打磚塊》實(shí)現(xiàn),讓我對(duì)JAVA的相關(guān)知識(shí)有了進(jìn)一步的了解,對(duì)java這門(mén)語(yǔ)言也有了比以前更深刻的認(rèn)識(shí)。
java的一些基本語(yǔ)法,比如數(shù)據(jù)類型、運(yùn)算符、程序流程控制和數(shù)組等,理解更加透徹。java最核心的核心就是面向?qū)ο笏枷耄瑢?duì)于這一個(gè)概念,終于悟到了一些。
以上就是Java實(shí)現(xiàn)經(jīng)典游戲打磚塊游戲的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java打磚塊游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Springboot工具類FileCopyUtils使用教程
這篇文章主要介紹了Springboot內(nèi)置的工具類之FileCopyUtils的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-12-12mybatis/mybatis-plus模糊查詢語(yǔ)句特殊字符轉(zhuǎn)義攔截器的實(shí)現(xiàn)
在開(kāi)發(fā)中,我們通常會(huì)遇到這樣的情況。用戶在錄入信息是錄入了‘%’,而在查詢時(shí)無(wú)法精確匹配‘%’。究其原因,‘%’是MySQL的關(guān)鍵字,如果我們想要精確匹配‘%’,那么需要對(duì)其進(jìn)行轉(zhuǎn)義,本文就詳細(xì)的介紹一下2021-11-11Mybatis實(shí)現(xiàn)動(dòng)態(tài)增刪改查功能的示例代碼
這篇文章主要介紹了Mybatis實(shí)現(xiàn)動(dòng)態(tài)增刪改查功能的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04淺談Ribbon、Feign和OpenFeign的區(qū)別
這篇文章主要介紹了淺談Ribbon、Feign和OpenFeign的區(qū)別。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06SpringBoot實(shí)現(xiàn)發(fā)送郵件功能過(guò)程圖解
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)發(fā)送郵件功能過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03基于Java中進(jìn)制的轉(zhuǎn)換函數(shù)詳解
下面小編就為大家?guī)?lái)一篇基于Java中進(jìn)制的轉(zhuǎn)換函數(shù)詳解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07