// (c) 1998 Ekkehard Kraemer (ekraemer@pluto.camelot.de) import java.awt.*; import java.util.*; import java.net.*; /** * The main game engine - controls everything. *

* Source * * @see BojngInterface * @see Stats * @see Timer * @see Update * @see Ball * @see Paddle * @see Field */ class Bojng extends Canvas implements Runnable,BojngInterface { /** Sets up everything, starts main game thread. * * @param urlBase the document base of the game * @param stats statistics display on the top of the screen * @param msgs message display at the bottom */ Bojng(URL urlBase,Stats stats,Label msgs) { super(); this.stats=stats; this.msgs=msgs; msgs.setText(defaultMessage); field=new Field(this,urlBase,this); setBackground(Color.black); blockwidth=Images.block[0].getWidth(null)+10; blockheight=Images.block[0].getHeight(null)+8; imgwidth=field.width*blockwidth; imgheight=field.height*blockheight; paddle=new Paddle(this); resize(imgwidth,imgheight); thread=new Thread(this); thread.start(); } /** Stops all threads and enters the S_STOPNOW state. */ void kill() { state=S_STOPNOW; timer.stopNow=true; stats.stopNow=true; try { Thread.sleep(500); } catch (Exception e) {} } /** Main loop - handles everything, controled by state. */ public void run() { try { while (!initOffGr()) { Thread.sleep(500); } state=S_NEWLEVEL; while (state!=S_STOPNOW) { synchronized(msgs) { if (msgShowCntr>0) { msgShowCntr--; if (msgShowCntr==0) msgs.setText(defaultMessage); } } synchronized(this) { switch (state) { case S_NEWLEVEL: { removeBullets(); synchronized(bombTargets) { bombTargets.removeAllElements(); } drawBackground(0,0,imgwidth,imgheight); defaultMessage=field.loadLevel((Math.abs((new Random()).nextInt())%80)+1); paddle.reset(); paddle.draw(true); stats.setBalls(3); state=S_BALLINVALID; break; } case S_BALLINVALID: { removeBullets(); if (stats.noBallLeft()) state=S_GAMEOVER; else { balls.removeAllElements(); balls.addElement(new Ball(this,-1000,-1000)); paddle.initBall(); state=S_WAITFORCLICK; stateCntr=clickWaitTime/timer.ms; } break; } case S_WAITFORCLICK: { removeBullets(); update(); Ball ball=(Ball)(balls.firstElement()); double a=paddle.getBallAngle(); ball.remove(); ball.moveTo(paddle.x+paddle.ballStartX, paddle.y-ball.sprad,a); ball.draw(); update(); if (stateCntr>0) { stateCntr--; int s=stateCntr/timer.ms; if (s>0 && s<=3) msg("..."+s+"..."); if (stateCntr<1) state=S_PLAYING; // let the ball off } break; } case S_PLAYING: { synchronized(bombTargets) { if (bombTargets.size()>0) { Point p=(Point)(bombTargets.firstElement()); Item i=field.getItem(p.x,p.y); if (i!=null) { hit(i,null); removeItem(p.x,p.y); clearBlock(p.x,p.y); } bombTargets.removeElement(p); } } for (Enumeration e=bullets.elements(); e.hasMoreElements();) { Point p=(Point)(e.nextElement()); if (!moveBullet(p)) bullets.removeElement(p); } update(); for (Enumeration e=balls.elements(); e.hasMoreElements();) { Ball ball=(Ball)e.nextElement(); boolean out=ball.tick(); if (out) killBall(ball); update(); } if (nextRandomCntr==0) { nextRandomCntr=(nextRandomBase+ posRand(nextRandomVar))/timer.ms; } else { nextRandomCntr--; if (nextRandomCntr<1) field.placeRandom(timer.ms); } field.tick(); if (balls.size()<1) state=S_BALLINVALID; break; } case S_ALLITEMSREMOVED: case S_GAMEOVER: { removeBullets(); state=S_NEWLEVEL; break; } } } synchronized(timer) { timer.wait(); } } } catch (Exception e) { e.printStackTrace(System.err); } System.err.println("Bojng thread stopped"); } /** Repaints the window using the off-screen image. * * @param g the Graphics context */ public void paint(Graphics g) { if (state==S_INIT) { super.paint(g); return; } synchronized(offImg) { g.drawImage(offImg,0,0,null); } } /** Repaints the window using the off-screen image. * * @param g the Graphics context */ public void update(Graphics g) { if (state==S_INIT) { super.update(g); return; } synchronized(offImg) { g.drawImage(offImg,0,0,null); } } /** Handles mouse movement events to place the paddle. * * @param evt the mouse event, unused * @param x the x coordinate, unused * @param y the y coordinate * @return true, if handled */ public boolean mouseMove(Event evt,int x,int y) { try { if (state!=S_PLAYING && state!=S_WAITFORCLICK) return false; int nx=x-paddle.width/2; if (nx<0) nx=0; if (nx>=imgwidth-paddle.width) nx=imgwidth-paddle.width; if (nx!=paddle.x) synchronized(this) { update(); paddle.moveTo(nx); if (state==S_WAITFORCLICK) { Ball ball=(Ball)(balls.firstElement()); ball.remove(); ball.moveTo(paddle.x+paddle.ballStartX, paddle.y-ball.sprad); ball.draw(); } update(); } return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** Handles mouse clicks events to start the game or shoot bullets. * * @param evt the mouse event, unused * @param x the x coordinate, unused * @param y the y coordinate, unused * @return true, if handled */ public boolean mouseDown(Event evt,int x,int y) { switch (state) { case S_WAITFORCLICK: synchronized(this) { state=S_PLAYING; } break; case S_PLAYING: shoot(); break; } return true; } /** Initializes the off-screen and background images. */ synchronized boolean initOffGr() { canvgr=getGraphics(); if (canvgr==null) return false; offImg=createImage(imgwidth,imgheight); if (offImg==null) return false; offGr=offImg.getGraphics(); if (offGr==null) return false; update=new Update(this,offImg,imgwidth,imgheight); Image backCell=Images.back; Images.back=createImage(imgwidth,imgheight); Graphics gr=Images.back.getGraphics(); int w=backCell.getWidth(null); int h=backCell.getHeight(null); for (int y=0; yfalse, if the bullet should be removed */ boolean moveBullet(Point p) { update(); drawBackground(p.x,p.y-bulheight,bulwidth,bulheight+2); update(); p.y-=bulspeed; if (p.y>0) { Graphics g=getGraphics(); g.setColor(bulcol); g.drawLine(p.x,p.y-bulheight,p.x,p.y); g.dispose(); Item i=field.getItem(p.x/blockwidth,p.y/blockheight); if (i!=null && i.contains(p)) { hit(i,null); return false; } for (Enumeration e=balls.elements(); e.hasMoreElements();) { Ball ball=(Ball)e.nextElement(); if (ball.contains(p)) killBall(ball); } return true; } else return false; } /** Removes all bullets, for example if a game is ended. */ void removeBullets() { for (Enumeration e=bullets.elements(); e.hasMoreElements();) { Point p=(Point)(e.nextElement()); update(); drawBackground(p.x,p.y-bulheight,bulwidth,bulheight+2); update(); } bullets.removeAllElements(); } /** Kills a ball, removes it from the ball vector, updates statistics * and displays a message about it. * * @param ball the ball to be removed */ void killBall(Ball ball) { msg("Another one bites the dust..."); ball.remove(); balls.removeElement(ball); stats.decBalls(); } /** Calculates a random positive integer. * * @param max the maximum value * @return -1<;rc<max */ public int posRand(int max) { int r=rand.nextInt(); if (r<0) r=-r; return r%max; } /** Starts a new BombThread to explode a bomb. The coordinates are int * block space. * * @param x the x coordinate * @param y the y coordinate */ public void bomb(int x,int y) { (new Thread(new BombThread(this,x,y))).start(); } /** Adds a location to the bomb target vector. * * @param p the point to be added, in block space */ void addBombTarget(Point p) { synchronized(bombTargets) { bombTargets.addElement(p); } } /** Draws an image on the off-screen buffer and adds it to the * update region. * * @param i the image to be drawn * @param x the x coordinate * @param y the y coordinate */ public void drawImage(Image i,int x,int y) { synchronized (offImg) { offGr.drawImage(i,x,y,null); } update.add(x,y,i.getWidth(null),i.getHeight(null)); } /** Calls update.update * * @see Update#update() */ public void update() { update.update(); } /** Teleports a ball to a random location and displays a message about * this. * * @param ball the ball to be teleported */ void teleport(Ball ball) { Point p=field.getFreeBlock(); if (p==null) return; msg("It's just a jump to the left..."); ball.moveTo(p.x*blockwidth, p.y*blockheight, rand.nextDouble()*PI.zwei); } /** Returns the number of ms waited between two ticks. * * @returns timer.ms */ public int ms() { return timer.ms; } public Rectangle getItem(int x,int y) { return field.getItem(x,y); } public Update _update() { return update; } public Rectangle _paddle() { return paddle; } public int _fieldWidth() { return field.width; } public int _fieldHeight() { return field.height; } public int _blockwidth() { return blockwidth; } public int _blockheight() { return blockheight; } public int _imgwidth() { return imgwidth; } public int _imgheight() { return imgheight; } Timer timer=new Timer(25); // Delay in ms Update update; Thread thread; Vector balls=new Vector(); // Image[] imgs; Paddle paddle; //URL urlBase; Stats stats; Vector bullets=new Vector(); Field field; Vector bombTargets=new Vector(); // final int IBALL=0,IPADDLE=1,IBACK=2,IBLOCK=3,IBULLET=4; // Zustand final int S_INIT=0, // initialize S_NEWLEVEL=1, // start new level S_BALLINVALID=2, // no ball in game S_WAITFORCLICK=3, // one ball attached to paddle S_PLAYING=4, // ball(s) flying... S_ALLITEMSREMOVED=6, // all blocks cleared S_GAMEOVER=7, // last ball died S_STOPNOW=8; // shutdown int state=S_INIT; int stateCntr=0; int nextRandomCntr=0; final int clickWaitTime=6000; final int nextRandomBase=5000,nextRandomVar=5000; Random rand=new Random(); // Punkte final int P_BASE=50, P_TRIPLE=100, P_BULLETS=50, P_GROW=75, P_NEWBALL=150, P_BOMB=200; // Feld/Graphik int blockwidth,blockheight; // Size of block (Pixels) int imgwidth,imgheight; // Pixel size of image/canvas Graphics offGr,canvgr; Image offImg; final int bulwidth=1,bulheight=4; // Bullets final int bulspeed=10; // Pixel/tick final Color bulcol=Color.white; Point standardPos; // Msg Label msgs; int msgShowCntr=0; final int msgShowTime=2500; String defaultMessage="---------"; } /** * Sorry, not documented yet. *

* Source */ class BombThread implements Runnable { BombThread(Bojng bojng,int x,int y) { this.bojng=bojng; this.x=x; this.y=y; } public void run() { for (int dy=-1; dy<2; dy++) for (int dx=-1; dx<2; dx++) { Rectangle i=bojng.getItem(x+dx,y+dy); if (i!=null) bojng.addBombTarget(new Point(x+dx,y+dy)); // bojng.move(bojng.standardPos.x+bojng.posRand(20)-10, // bojng.standardPos.y+bojng.posRand(20)-10); try { Thread.sleep(100); } catch (Exception e) {} } // bojng.move(bojng.standardPos.x,bojng.standardPos.y); } Bojng bojng; int x,y; }