2 * FrenzyController.java
5 * $Id: FrenzyController.java,v 1.5 2008/05/17 03:29:37 rmh3093 Exp rmh3093 $
8 * $Log: FrenzyController.java,v $
9 * Revision 1.5 2008/05/17 03:29:37 rmh3093
10 * add semi-random movement pattern
12 * Revision 1.4 2008/05/16 23:04:18 rmh3093
13 * implement scrolling pane for last consumed object
15 * Revision 1.3 2008/05/16 22:06:44 rmh3093
16 * meets final submission goals
18 * Revision 1.2 2008/04/30 04:10:52 rmh3093
19 * break out random number generator, first attempt at moving enemies
21 * Revision 1.1 2008/04/26 15:45:41 rmh3093
27 Copyright (c) 2008, Ryan M. Hope
30 Redistribution and use in source and binary forms, with or without modification,
31 are permitted provided that the following conditions are met:
33 * Redistributions of source code must retain the above copyright notice,
34 this list of conditions and the following disclaimer.
35 * Redistributions in binary form must reproduce the above copyright notice,
36 this list of conditions and the following disclaimer in the documentation
37 and/or other materials provided with the distribution.
38 * Neither the name of the project nor the names of its contributors may be
39 used to endorse or promote products derived from this software without
40 specific prior written permission.
42 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
43 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
44 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
45 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
46 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
49 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
51 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 import java
.awt
.event
.*;
55 import java
.util
.TreeSet
;
58 * Controls the Frenzy view and updates the model
62 public class FrenzyController
{
64 // Random number generator
65 private BetterRandom betterRandom
;
67 private FrenzyModel f_model
;
68 private FrenzyView f_view
;
71 * Create a new Frenzy Controller
73 * @param f_model the Frenzy game f_model
74 * @param f_view the Frenzy game f_view
76 FrenzyController(FrenzyModel f_model
, FrenzyView f_view
,
77 BetterRandom betterRandom
) {
78 this.f_model
= f_model
;
80 this.betterRandom
= betterRandom
;
82 // Add player to board in random position
83 f_model
.player
= new FrenzyPlayer();
86 // Add listeners to f_view
87 f_view
.addQuitListener(new QuitListener());
88 f_view
.addResetListener(new ResetListener());
89 f_view
.addSpawnListener(new SpawnListener());
90 f_view
.addPauseListener(new PauseListener());
91 f_view
.addPlayerControlsListener(new PlayerControlsListener());
92 f_view
.addEnemySpawnListener(new SpawnListener());
93 f_view
.addFasterEnemyListener(new FasterEnemyListener());
94 f_view
.addSlowerEnemyListener(new SlowerEnemyListener());
97 private void resumeGame() {
98 TreeSet
<String
> keys
=
99 new TreeSet
<String
>(f_model
.enemies
.keySet());
100 for (String key
: keys
) {
101 FrenzyEnemy enemy
= f_model
.enemies
.get(key
);
103 synchronized (enemy
.moverThread
) {
104 enemy
.moverThread
.notifyAll();
106 // Sleep for a random amount of time so that when enemies wake up
107 // from sleeping they dont look like they are moving in sync
109 Thread
.sleep(betterRandom
.rand
.nextInt(50));
110 } catch (InterruptedException e
) {
114 synchronized (f_view
.enemySpawnerThread
) {
115 f_view
.enemySpawnerThread
.notifyAll();
119 protected synchronized void spawnEnemy() {
120 if (f_model
.gamestate
) {
121 // Can't spawn new enemies if there are no unique ASCII characters
122 if (f_model
.enemyCount
< FrenzyModel
.MAX_ENIMES
) {
126 int num
= betterRandom
.rand
.nextInt(255);
128 // These characters don't print
129 if (num
< 33 || ((num
> 126) && (num
< 161)) || num
== 173)
132 // Can't use players symbol
133 if (String
.valueOf((char)num
) == FrenzyPlayer
.symbol
)
136 // The symbol for the new enemy
137 String symbol
= String
.valueOf((char)num
);
139 // Check to make sure the symbol is already in use
140 if (f_model
.enemies
.containsKey(symbol
)) continue;
142 // Find a random unoccupied location for the enemy to spawn
146 x
= betterRandom
.rand
.nextInt(f_model
.getBoardSize());
147 y
= betterRandom
.rand
.nextInt(f_model
.getBoardSize());
148 if (f_view
.boardSquares
[y
][x
].isOccupied() ==
149 FrenzyModel
.OCCUPANT
.NONE
) {
154 int move_x
= betterRandom
.rand
.nextInt(2);
155 int move_y
= betterRandom
.rand
.nextInt(2);
156 FrenzyEnemy
.MOVEMENT_PATTERN mp
= null;
157 // Spawn the new enemy
158 if ((move_x
== 1) && (move_y
== 1)) {
159 mp
= FrenzyEnemy
.MOVEMENT_PATTERN
.NE
;
160 } else if ((move_x
== 1) && (move_y
== 0)) {
161 mp
= FrenzyEnemy
.MOVEMENT_PATTERN
.SE
;
162 } else if ((move_x
== 0) && (move_y
== 1)) {
163 mp
= FrenzyEnemy
.MOVEMENT_PATTERN
.NW
;
164 } else if ((move_x
== 0) && (move_y
== 0)) {
165 mp
= FrenzyEnemy
.MOVEMENT_PATTERN
.SW
;
168 new FrenzyEnemy(f_model
, x
, y
, symbol
, mp
,
169 betterRandom
.rand
.nextInt(3),
170 new EnemyMover(), betterRandom
);
171 f_model
.enemies
.put(symbol
, enemy
);
172 f_view
.addOccupant(enemy
, f_view
.boardSquares
[y
][x
]);
173 f_model
.increaseEnemyCount();
174 enemy
.moverThread
.start();
180 synchronized (f_view
.enemySpawnerThread
) {
182 f_view
.enemySpawnerThread
.wait();
183 } catch (InterruptedException e
) {
190 * Handles moving the Frenzy player around the game board
194 class PlayerControlsListener
implements KeyListener
{
196 public void keyPressed(KeyEvent e
) {
199 public void keyTyped(KeyEvent e
) {
202 // Only perform an action on the release of the key
203 public void keyReleased(KeyEvent e
) {
205 if (f_model
.gamestate
) {
207 int keycode
= e
.getKeyCode();
210 int x_old
= f_model
.player
.getXposition();
211 int y_old
= f_model
.player
.getYposition();
212 if ((keycode
> 36 && keycode
< 41) && f_model
.gamestate
) {
214 // Remove player from current location
215 f_view
.removeOccupant(f_view
.boardSquares
[y_old
][x_old
]);
222 x_new
= f_model
.boardsize
-1;
227 f_model
.player
.setXposition(x_new
);
233 y_new
= f_model
.boardsize
-1;
238 f_model
.player
.setYposition(y_new
);
243 if (x_old
== f_model
.boardsize
-1) {
249 f_model
.player
.setXposition(x_new
);
254 if (y_old
== f_model
.boardsize
-1) {
260 f_model
.player
.setYposition(y_new
);
264 // If new location is occupied by an enemy, eat it
265 if (f_view
.boardSquares
[y_new
][x_new
].isOccupied() ==
266 FrenzyModel
.OCCUPANT
.ENEMY
) {
270 f_view
.boardSquares
[y_new
][x_new
].getText();
271 f_model
.player
.eatEnemy();
272 f_model
.decreaseEnemyCount();
273 if (f_model
.player
.getConsumedCount() > 0 &&
274 f_model
.enemyCount
==0) {
275 f_model
.gamestate
= false;
276 f_view
.statusLabel
.setText("Game over.");
279 // Remove key from list so that the symbol can be reused
280 f_model
.enemies
.remove(key
);
282 // ====================================================
283 // These should be handled by events
285 // Update the last action display
286 f_view
.lastActionArea
.setText(
287 f_model
.player
.getSymbol() + " ate " + key
+
288 "\n" + f_view
.lastActionArea
.getText());
290 // Update the consumed enemy count display
291 int count
= f_model
.player
.getConsumedCount();
292 f_view
.consumedLabel
.setText(String
.valueOf(count
));
294 // ====================================================
297 // Add player to new square
298 f_view
.addOccupant(f_model
.player
,
299 f_view
.boardSquares
[y_new
][x_new
]);
306 * Handles quitting Frenzy
310 class QuitListener
implements ActionListener
{
311 public void actionPerformed(ActionEvent e
) {
318 * Handles resetting Frenzy
322 class ResetListener
implements ActionListener
{
323 public void actionPerformed(ActionEvent e
) {
324 f_model
.gamestate
= true;
325 f_view
.statusLabel
.setText("Game Running!");
326 f_view
.pauseControl
.setSelected(false);
327 f_model
.player
.setConsumedCount(0);
328 f_view
.consumedLabel
.setText("0");
329 if (f_model
.player
.dead
) {
331 f_model
.player
.dead
= false;
338 * Handles resetting Frenzy
342 class PauseListener
implements ActionListener
{
343 public void actionPerformed(ActionEvent e
) {
344 if (f_view
.pauseControl
.isSelected()) {
345 f_model
.gamestate
= false;
346 f_view
.statusLabel
.setText("Game Paused!");
348 f_model
.gamestate
= true;
349 if (!f_model
.player
.dead
) resumeGame();
350 f_view
.statusLabel
.setText("Game Running!");
356 * Handles spawning of new enemies
360 class SpawnListener
implements ActionListener
{
362 public void actionPerformed(ActionEvent e
) {
363 if (f_model
.gamestate
) spawnEnemy();
369 * Handles increasing enemy speed
373 class FasterEnemyListener
implements ActionListener
{
375 public void actionPerformed(ActionEvent e
) {
376 f_model
.enemyMoveInterval
= f_model
.enemyMoveInterval
- 10;
382 * Handles decreasing enemy speed
386 class SlowerEnemyListener
implements ActionListener
{
388 public void actionPerformed(ActionEvent e
) {
389 f_model
.enemyMoveInterval
= f_model
.enemyMoveInterval
+ 10;
395 * Handles moving enemies
401 public synchronized void move(String symbol
) {
402 FrenzyEnemy enemy
= f_model
.enemies
.get(symbol
);
403 FrenzyEnemy eaten
= null;
405 int x
= enemy
.getXposition();
406 int y
= enemy
.getYposition();
407 FrenzyModel
.OCCUPANT occupant_t
=
408 f_view
.boardSquares
[y
][x
].isOccupied();
409 if (occupant_t
!= FrenzyModel
.OCCUPANT
.NONE
) {
410 String occupant
= f_view
.boardSquares
[y
][x
].getText();
411 if (occupant_t
== FrenzyModel
.OCCUPANT
.PLAYER
) {
412 f_model
.gamestate
= false;
413 f_model
.player
.dead
= true;
414 f_view
.statusLabel
.setText("Game over.");
416 eaten
= f_model
.enemies
.get(occupant
);
419 System
.out
.println("Oh no!");
423 f_model
.enemies
.remove(occupant
);
425 f_view
.lastActionArea
.setText(
426 symbol
+ " ate " + occupant
+
427 "\n" + f_view
.lastActionArea
.getText());
429 f_view
.removeOccupant(
430 f_view
.boardSquares
[enemy
.Yposition_old
][enemy
.Xposition_old
]);
431 f_view
.addOccupant(enemy
, f_view
.boardSquares
[y
][x
]);
437 private void spawnPlayer() {
439 int x
= betterRandom
.rand
.nextInt(f_model
.boardsize
);
440 int y
= betterRandom
.rand
.nextInt(f_model
.boardsize
);
441 if (f_view
.boardSquares
[y
][x
].isOccupied() ==
442 FrenzyModel
.OCCUPANT
.NONE
) {
443 f_model
.player
.setXposition(x
);
444 f_model
.player
.setYposition(y
);
448 f_view
.spawnPlayer();