前言
《JAVA打砖块》游戏是自制的游戏。玩家操作一根萤幕上水平的[棒子],让一颗不断弹来弹去的[球]在撞击作为过关目标消去的[砖块]的途中不会落到萤幕底下。
主要设计
设计游戏界面,用swing实现 设计砖块,砖块类, 设计小球,满屏乱跑的小球类,负责打碎砖块 设计棒子,左右移动的木头板类 球碰到砖块、棒子与底下以外的三边会反弹,落到底下会失去一颗球,把砖块全部消去就可以破关。 小球碰到砖块的回调算法设计 小球碰到棒子的回调算法设计 设计碰撞特效,一个负责显示爆炸效果的类 设计音效类,碰撞时发出音效。
功能截图
游戏开始:
碰撞效果:
代码实现
游戏核心类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
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 ; } } } |
小球类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
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(); } } |
砖块类
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
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打砖块游戏的资料请关注其它相关文章!
原文链接:https://juejin.cn/post/7067900690618089503
查看更多关于Java实现经典游戏打砖块游戏的示例代码的详细内容...