001 import java.awt.*;
002 import java.awt.event.*;
003 import java.awt.geom.*;
004 import java.util.*;
005 import javax.swing.*;
006 import javax.swing.BorderFactory;
007 import javax.swing.border.Border;
008 import javax.swing.border.TitledBorder;
009 import javax.swing.border.EtchedBorder;
010
011 /**
012 * This class works as a game engine which loops to do updates.
013 *
014 */
015 class GameEngine extends JPanel implements Runnable {
016
017 // Field variables
018 public static final int NUM_BLOCKS = 32; // 4 X 8
019 public static final int BLOCK_SPACE = 5;
020 public static final int WIDTH = (Block.WIDTH+BLOCK_SPACE)*8+BLOCK_SPACE;
021 public static final int HEIGHT = 364;
022 public static final int THRESHOLD = BouncerFrame.HEIGHT - 2*Ball.RADIUS;
023 public static final int BALL_START_XPOS = 20;
024 public static final int BALL_START_YPOS = 280;
025 public static final int BAR_START_XPOS = 0;
026 public static final int BAR_START_YPOS = 300;
027 public static final int LEVEL1_INTERVAL = 100; // speed of level 1
028 public static final int LEVEL2_INTERVAL = 90; // speed of level 2
029 public static final int LEVEL3_INTERVAL = 80; // speed of level 3
030 public static final int LEVEL4_INTERVAL = 70; // speed of level 4
031 public static final int LEVEL5_INTERVAL = 60; // speed of level 5
032
033 public static boolean isHitBottom = false; // indicates if the ball hits the bottom
034 // set as global for simplicity
035 public static boolean isCheat = false; // tooggle cheat mode
036 // set as global for simplicity
037 int blocksDestroyed = 0;
038 boolean gameStarted = false;
039 boolean stopRequested = false;
040 boolean suspendRequested = false;
041 Ball ball;
042 Block[] blockArray;
043 Bar bar;
044 int currentInterval;
045 int score;
046
047 private SuspendRequestor suspender = new SuspendRequestor();
048
049 public GameEngine() {
050
051 currentInterval = LEVEL1_INTERVAL;
052 score = 0;
053 setSize(WIDTH, HEIGHT);
054 setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
055 blockArray = new Block[GameEngine.NUM_BLOCKS];
056 int x = 10 , y = 10;
057 for(int i=0; i<4; i++) {
058
059 for(int j=0; j<8 ; j++) {
060 blockArray[i*8 + j] = new Block(x, y, Color.YELLOW);
061 x = x + Block.WIDTH + BLOCK_SPACE;
062 }
063
064 x = 10; // reset the x position
065 y = y + Block.HEIGHT + 5;
066 }
067 bar = new Bar(BAR_START_XPOS, BAR_START_YPOS, Color.BLACK);
068 // position the ball above the center of the bar
069 ball = new Ball(bar.getXPos()+Bar.WIDTH/2-ball.RADIUS, bar.getYPos()-2*Ball.RADIUS, Color.RED, 10, 10);
070
071 repaint();
072
073 requestFocus();
074 addKeyListener(new KeyHandler());
075
076 } // end of GameEngine(RecordPanel)
077
078 public void startGame() {
079
080 if(!gameStarted) {
081 gameStarted = true;
082 stopRequested = false;
083 suspendRequested = false;
084 ball.setXPos(bar.getXPos()+Bar.WIDTH/2);
085 ball.setYPos(bar.getYPos()-Ball.RADIUS);
086
087 //*******Add something here to make the game start*****
088
089 //*****************************************************
090 }
091
092 } // end of startGame()
093
094 public void suspendResumeGame() {
095
096 suspendRequested = !suspendRequested;
097
098 if(gameStarted) {
099 //********Handle the request according to the state of the game*******
100 //**********Only need to write codes inside this if-block*************
101 }
102
103 } // end of suspendResumeGame()
104
105 public void requestSuspend() {
106
107 //*********Write your code here*************
108
109 } // end of requestSuspend()
110
111 public synchronized void requestResume() {
112
113 //*********Write your code here*************
114
115 } // end of requestResume()
116
117 public void stopGame() {
118
119 stopRequested = true;
120 gameStarted = false;
121
122 } // end of stopGame()
123
124
125 public void paintComponent(Graphics g) {
126
127 super.paintComponent(g);
128 Graphics2D g2 = (Graphics2D)g;
129
130 // draw the ball
131 ball.draw(g2);
132
133 // draw the blocks
134 for(int i=0; i<blockArray.length; i++) {
135 if(!blockArray[i].isDestroyed()){
136 blockArray[i].draw(g2);
137 //System.out.println(i + "th block drawn");
138 }
139 }
140
141 // draw the bar
142 bar.draw(g2);
143
144 // debug message for showing the dimension of the game panel
145 //System.out.println(getWidth()+" X "+getHeight());
146
147 } // end of paintComponent(Graphics)
148
149
150 public void run() {
151
152 // loop thoughout the whole game, unless stop is requested
153 while(!stopRequested) {
154
155 //******Add something here to make the suspend/resume work*******
156
157 //***************************************************************
158
159 // check if the ball hits any block
160 int blockResult;
161 for(int i=0; i<blockArray.length; i++) {
162 if(!blockArray[i].isDestroyed()) {
163 blockResult = blockArray[i].isHit(ball);
164 if(blockResult == Block.TOP_OR_BOTTOM) {
165 blockArray[i].setDestroyed(true);
166 ball.setYVel(-ball.getYVel());
167 // increase score
168 score += currentInterval;
169 blocksDestroyed++;
170 }
171 else if(blockResult == Block.LEFT_OR_RIGHT) {
172 blockArray[i].setDestroyed(true);
173 ball.setXVel(-ball.getXVel());
174 // increase score
175 score += currentInterval;
176 blocksDestroyed++;
177 }
178 else { // do nothing
179 }
180 }
181 }
182
183 // check if all the blocks are destroyed
184 if(blocksDestroyed >= NUM_BLOCKS) {
185 // repaint all the things
186 repaint();
187 stopGame();
188 JOptionPane.showMessageDialog(this, "You've won!\nScore = "+score);
189 System.exit(0);
190 }
191
192 // check if the ball hits the bar
193 int barResult = bar.isHit(ball);
194 if(barResult==Bar.LEFT_SIDE || barResult==Bar.RIGHT_SIDE) {
195 // make it move faster horizontally
196 ball.setXVel(ball.getXVel()+2);
197 ball.setYVel(-ball.getYVel());
198 }
199 else if(barResult == Bar.MIDDLE) {
200 ball.setYVel(-ball.getYVel());
201 }
202 else {
203 // do nothing, since no hit
204 }
205
206 // check if the ball has hit the bottom
207 if(!isCheat && isHitBottom) {
208 stopGame();
209 JOptionPane.showMessageDialog(this, "Game Over!\nScore = "+score);
210 System.exit(0);
211 }
212
213
214 // move the ball
215 ball.move(getWidth(), getHeight());
216
217 // repaint all the things
218 repaint();
219
220 // sleep for delay
221 try {
222 Thread.sleep(currentInterval);
223 } catch(InterruptedException ie) {}
224 }
225
226 } // end of run()
227
228 // public boolean isFocusTraversable() <- Deprecated since JDK1.4
229 public boolean isFocusable() {
230
231 return true; // allow panel to get input focus
232
233 }
234
235 /**
236 * Inner class for handling the left and right button events
237 *
238 */
239 private class KeyHandler extends KeyAdapter {
240
241 public void keyPressed(KeyEvent event) {
242
243 int keyCode = event.getKeyCode();
244
245 if (keyCode == KeyEvent.VK_LEFT && !suspendRequested) {
246 //System.out.println("left pressed");
247 bar.move(getWidth(), getHeight(), Bar.LEFT);
248 if(!gameStarted)
249 ball.setXPos(bar.getXPos()+Bar.WIDTH/2-Ball.RADIUS);
250 }
251 else if (keyCode == KeyEvent.VK_RIGHT && !suspendRequested) {
252 //System.out.println("right pressed");
253 bar.move(getWidth(), getHeight(), Bar.RIGHT);
254 if(!gameStarted)
255 ball.setXPos(bar.getXPos()+Bar.WIDTH/2-Ball.RADIUS);
256 }
257 else if (keyCode == KeyEvent.VK_UP) {
258 //System.out.println("up pressed");
259 if(!gameStarted)
260 startGame();
261 }
262 else if (keyCode == KeyEvent.VK_C) {
263 isCheat = !isCheat;
264 if(isCheat) ball.setColor(Color.BLUE);
265 else ball.setColor(Color.RED);
266 }
267 else if (keyCode == KeyEvent.VK_P) {
268 suspendResumeGame();
269 }
270 else {
271 // do nothing
272 }
273
274 repaint();
275
276 } // end of keyPressed(KeyEvent)
277
278 } // end of KeyHandler inner class definition
279
280 } // end of GameEngine class definition
281
282 // The class for us to use its objects as locks
283 class SuspendRequestor
284 { public synchronized void set ( boolean b)
285 { suspendRequested = b;
286 notifyAll();}
287
288 public synchronized void waitForResume()
289 throws InterruptedException
290 { while ( suspendRequested) wait (); }
291
292 private boolean suspendRequested;
293 }
|