1 package se
.umu
.cs
.dit06ajnajs
;
3 import java
.awt
.Graphics
;
4 import java
.awt
.event
.MouseAdapter
;
5 import java
.awt
.event
.MouseEvent
;
7 import java
.util
.ArrayList
;
9 import java
.util
.logging
.Logger
;
11 import java
.awt
.event
.ActionEvent
;
12 import java
.awt
.event
.ActionListener
;
13 import java
.awt
.event
.WindowAdapter
;
14 import java
.awt
.event
.WindowEvent
;
16 import se
.umu
.cs
.dit06ajnajs
.agent
.AgentPrototypeFactory
;
17 import se
.umu
.cs
.dit06ajnajs
.agent
.Tower
;
18 import se
.umu
.cs
.dit06ajnajs
.agent
.Unit
;
19 import se
.umu
.cs
.dit06ajnajs
.level
.GoalSquare
;
20 import se
.umu
.cs
.dit06ajnajs
.level
.Level
;
21 import se
.umu
.cs
.dit06ajnajs
.level
.StartSquare
;
23 import se
.umu
.cs
.edu
.jap
.highscoreservice
.HighScoreServiceClient
;
24 import se
.umu
.cs
.edu
.jap
.highscoreservice
.Entry
;
26 import se
.umu
.cs
.edu
.jap
.highscoreservice
.stubs
.FailureFaultException
;
27 import java
.net
.MalformedURLException
;
28 import java
.util
.Date
;
29 import java
.awt
.Point
;
31 public class ATDController
{
32 private static Logger logger
= Logger
.getLogger("AntiTD");
34 private final int FRAMES_PER_SECOND
= 20;
35 private static boolean mute
;
37 private ATDModel model
;
40 private boolean running
;
41 private boolean clocking
;
42 private boolean changeLevel
;
43 private boolean paused
;
44 private Thread animationThread
;
45 private Thread creditThread
;
47 public ATDController(List
<Level
> levels
) {
48 // Create model and view
49 this.model
= new ATDModel(levels
);
50 this.view
= new ATDView(model
);
53 // TODO: game related init
56 // Sound is on by default
60 this.changeLevel
= false;
61 this.animationThread
= new Thread(new AnimationThread());
62 this.creditThread
= new Thread(new CreditThread());
63 animationThread
.start();
67 public void advanceLevel() {
68 ATDSoundPlayer
.killMusic();
69 if (model
.advanceLevel()) {
70 view
.updateScoreboard();
71 view
.updateBackgroundImage();
72 ATDSoundPlayer
.playMusic(model
.getNextTrack());
79 public void newGame() {
80 ATDSoundPlayer
.killMusic();
82 view
.updateScoreboard();
83 view
.updateBackgroundImage();
85 ATDSoundPlayer
.playMusic(model
.getNextTrack());
88 public void restartLevel() {
89 ATDSoundPlayer
.killMusic();
91 view
.updateScoreboard();
92 view
.updateBackgroundImage();
93 ATDSoundPlayer
.playMusic(model
.getNextTrack());
96 public void winGame() {
97 ATDSoundPlayer
.killMusic();
99 String urlString
= "http://salt.cs.umu.se:37080/axis2/services/HighScoreService";
100 URL url
= new URL(urlString
);
101 HighScoreServiceClient client
= new HighScoreServiceClient(url
);
103 String name
= view
.promtForHighScoreEntry();
104 String date
= new Date().toString();
105 String score
= model
.getScore() + "";
107 client
.store(new Entry(name
, date
, score
));
108 view
.printMessage("Score stored.");
110 } catch (FailureFaultException e
) {
111 // e.printStackTrace();
112 view
.printMessage("Couldn't store score");
113 } catch (MalformedURLException e
) {
114 // TODO - fix error message
119 public void loseGame() {
120 ATDSoundPlayer
.killMusic();
121 if (view
.showLevelLostDialog() == 0) {
129 * Wrapper method, calls clickPoint(int x, int y).
131 * @param point The point to click.
133 public void clickPoint(Point point
) {
134 clickPoint(point
.x
, point
.y
);
139 * Clicks all Clickables at the specified x, y point.
141 * @param x The x-location to click.
142 * @param y The y-location to click.
144 public void clickPoint(int x
, int y
) {
145 List
<Unit
> units
= model
.getUnits();
146 for (Unit unit
: units
) {
147 if (unit
.contains(x
, y
)) {
151 model
.getCurrentLevel().getMapSquareAtPoint(x
, y
).click();
155 * Toggles sound on/off.
157 private void toggleMute() {
158 if (ATDSoundPlayer
.isMute()) {
159 ATDSoundPlayer
.setMute(false);
160 view
.updateMuteMenu("Mute");
161 view
.printMessage("Sound is on");
163 ATDSoundPlayer
.setMute(true);
164 view
.updateMuteMenu("unMute");
165 view
.printMessage("Sound is muted");
170 * Toggles pause, which freezes game.
172 private void togglePause() {
174 ATDController
.this.paused
= false;
175 view
.updatePauseMenu("Pause");
176 view
.printMessage("");
178 ATDController
.this.paused
= true;
179 view
.updatePauseMenu("Resume");
180 view
.printMessage("Game is paused");
185 * Quits this application.
187 private void quitApplication() {
188 this.running
= false;
189 this.clocking
= false;
190 logger
.info("Closing program");
195 private class AnimationThread
implements Runnable
{
196 private long usedTime
;
197 public AnimationThread() {
204 * While running, the thread loops through all actions the game can
205 * generate as many times per second determined by the final class
206 * variable FRAMES_PER_SECOND
209 // TODO Will running ever be false?
211 // Check if game is paused
215 } catch (InterruptedException e
) {
216 // TODO Auto-generated catch block
220 long startTime
= System
.currentTimeMillis();
223 List
<Unit
> units
= model
.getUnits();
224 List
<Unit
> deadUnits
= new ArrayList
<Unit
>();
225 for (Unit unit
: units
) {
226 if (unit
.isAlive()) {
228 for (Unit otherUnit
: units
) {
229 if (unit
!= otherUnit
) {
230 if (unit
.intersectsNextMove(otherUnit
)) {
232 unit
.collision(otherUnit
);
240 logger
.info("Dead unit is collected to list deadUnits");
242 /*the towers should be rewarded for dead units
243 Remember that cleared units are also "dead"
244 but should not be counted
249 // Collect dead units
250 if (!deadUnits
.isEmpty()) {
251 model
.removeUnits(deadUnits
);
252 logger
.info("Dead agents cleared");
256 List
<Tower
> towers
= model
.getTowers();
257 for (Tower tower
: towers
) {
261 // Remove units from goalsquares and count points
262 GoalSquare
[] goalSquares
= model
.getGoalSquares();
265 for (GoalSquare square
: goalSquares
) {
266 numOfUnits
= square
.getNumUnits();
267 credit
+= square
.getCredit();
269 // Only update model if changes has been made and level is not
271 if ((credit
> 0 || numOfUnits
> 0)
272 && !model
.isLevelComplete()) {
273 model
.addCredit(credit
);
274 model
.addGoalUnit(numOfUnits
);
275 view
.updateScoreboard();
276 ATDSoundPlayer
.play(model
.getSound("goal"));
279 // Release Unit from StartSquares
280 StartSquare
[] startSquares
= model
.getStartSquares();
281 for (StartSquare startSquare
: startSquares
) {
282 Unit unitToStart
= startSquare
.getUnitToStart();
283 boolean unitToStartCollided
= false;
284 if (unitToStart
!= null) {
285 for (Unit unit
: units
) {
286 unitToStartCollided
= unitToStart
.intersects(unit
);
287 if (unitToStartCollided
) {
292 if (!unitToStartCollided
) {
293 // No collision found
294 startSquare
.removeUnit(unitToStart
);
296 model
.releaseUnit(unitToStart
);
301 // Repaint all agents
302 //TODO kan det finnas en agent som inte är paintable?
303 Graphics g
= view
.getGameGraphics();
304 for (Unit unit
: units
) {
307 for (Tower tower
: towers
) {
311 // Refresh the game view
314 this.usedTime
= System
.currentTimeMillis() - startTime
;
315 // Try to keep a given number of frames per second.
317 // TODO think, fps???
318 Thread
.sleep((1000 - usedTime
) / FRAMES_PER_SECOND
);
319 } catch (InterruptedException e
) {
320 System
.err
.println("Error in thread, exiting.");
327 private class CreditThread
implements Runnable
{
328 public CreditThread() {
333 * While running, the thread sleeps for an interval and then calculates
334 * the earned credits from units on the map. The credits are then added
339 // Check if game is paused
343 } catch (InterruptedException e
) {
344 // TODO Auto-generated catch block
348 // Calculate earned credits
349 int credit
= calculateCredit();
351 model
.addCredit(credit
);
352 view
.updateScoreboard();
355 if (model
.isLevelComplete()) {
356 System
.out
.println("Victory!");
357 ATDSoundPlayer
.killMusic();
358 ATDSoundPlayer
.play(model
.getSound("victory"));
359 // Check if user wants to restart level or go to next
360 if(view
.showLevelCompleteDialog() == 0) {
367 if (model
.isLevelLost()) {
369 System
.out
.println("You lose!");
375 } catch (InterruptedException e
) {
382 private int calculateCredit() {
383 List
<Unit
> units
= model
.getUnits();
384 int credit
= units
.size() * 10;
390 public void saveToHighScoreService() {
391 // Save highscore to Highscoreservice
393 /* Connect listeners to View *************************************/
395 private void connectListeners() {
396 this.view
.addMapListener(new MapListener());
397 this.view
.addClosingListener(new ClosingListener());
398 this.view
.addReleaseUnitListener(new ReleaseUnitListener());
399 this.view
.addPauseMenuItemListener(new PausResumeListener());
400 this.view
.addMuteMenuItemListener(new MuteListener());
401 this.view
.addNewGameMenuItemListener(new NewGameListener());
402 this.view
.addAboutMenuItemListener(new AboutListener());
403 this.view
.addHelpMenuItemListener(new HelpListener());
404 this.view
.addRestartLevelMenuItemListener(new RestartLevelListener());
407 /* Inner Listener classes ****************************************/
409 private class MapListener
extends MouseAdapter
{
411 public void mouseClicked(MouseEvent me
) {
412 clickPoint(me
.getX(), me
.getY());
413 // TODO, only update what is needed.
414 view
.updateBackgroundImage();
418 private class ClosingListener
extends WindowAdapter
419 implements ActionListener
{
420 public void actionPerformed(ActionEvent ae
) {
425 public void windowClosing(WindowEvent we
) {
430 private class PausResumeListener
implements ActionListener
{
431 public void actionPerformed(ActionEvent ae
) {
432 ATDController
.this.togglePause();
436 private class MuteListener
implements ActionListener
{
437 public void actionPerformed(ActionEvent ae
) {
438 ATDController
.this.toggleMute();
442 private class NewGameListener
implements ActionListener
{
443 public void actionPerformed(ActionEvent ae
) {
444 ATDController
.this.newGame();
448 private class RestartLevelListener
implements ActionListener
{
449 public void actionPerformed(ActionEvent ae
) {
450 ATDController
.this.restartLevel();
454 private class AboutListener
implements ActionListener
{
455 public void actionPerformed(ActionEvent ae
) {
457 ATDController
.this.togglePause();
459 view
.showAboutDialog();
460 ATDController
.this.togglePause();
464 private class HelpListener
implements ActionListener
{
465 public void actionPerformed(ActionEvent ae
) {
467 ATDController
.this.togglePause();
469 view
.showHelpDialog();
470 ATDController
.this.togglePause();
475 * Creates a new unit and adds it to the game model.
477 private class ReleaseUnitListener
implements ActionListener
{
478 public void actionPerformed(ActionEvent ae
) {
479 AgentPrototypeFactory factory
= AgentPrototypeFactory
.getInstance();
480 if (!model
.addUnit(factory
.createUnit(view
.getSelectedUnitType()))) {
481 view
.printMessage("Insufficient funds!");
483 view
.printMessage("");