// (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
* 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;
}
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; y