Fixed bug in collecting credits and changed behaviour of playing music
[AntiTD.git] / src / se / umu / cs / dit06ajnajs / ATDController.java
blob8ec2be98dde89062b05e9a758cb4885189994034
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;
8 import java.util.List;
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;
25 import java.net.URL;
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;
38 private ATDView view;
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);
51 connectListeners();
53 // TODO: game related init
54 newGame();
56 // Sound is on by default
57 mute = false;
58 this.running = true;
59 this.clocking = true;
60 this.changeLevel = false;
61 this.animationThread = new Thread(new AnimationThread());
62 this.creditThread = new Thread(new CreditThread());
63 animationThread.start();
64 creditThread.start();
67 public void advanceLevel() {
68 ATDSoundPlayer.killMusic();
69 if (model.advanceLevel()) {
70 view.updateScoreboard();
71 view.updateBackgroundImage();
72 ATDSoundPlayer.playMusic(model.getNextTrack());
73 } else {
74 // Game won
75 winGame();
79 public void newGame() {
80 ATDSoundPlayer.killMusic();
81 model.newGame();
82 view.updateScoreboard();
83 view.updateBackgroundImage();
84 view.repaintGame();
85 ATDSoundPlayer.playMusic(model.getNextTrack());
88 public void restartLevel() {
89 ATDSoundPlayer.killMusic();
90 model.restartLevel();
91 view.updateScoreboard();
92 view.updateBackgroundImage();
93 ATDSoundPlayer.playMusic(model.getNextTrack());
96 public void winGame() {
97 ATDSoundPlayer.killMusic();
98 try {
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.");
109 newGame();
110 } catch (FailureFaultException e) {
111 // e.printStackTrace();
112 view.printMessage("Couldn't store score");
113 } catch (MalformedURLException e) {
114 // TODO - fix error message
115 e.printStackTrace();
119 public void loseGame() {
120 ATDSoundPlayer.killMusic();
121 if (view.showLevelLostDialog() == 0) {
122 newGame();
123 } else {
124 quitApplication();
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)) {
148 unit.click();
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");
162 } else {
163 ATDSoundPlayer.setMute(true);
164 view.updateMuteMenu("unMute");
165 view.printMessage("Sound is muted");
170 * Toggles pause, which freezes game.
172 private void togglePause() {
173 if (paused) {
174 ATDController.this.paused = false;
175 view.updatePauseMenu("Pause");
176 view.printMessage("");
177 } else {
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");
191 System.exit(0);
195 private class AnimationThread implements Runnable {
196 private long usedTime;
197 public AnimationThread() {
198 // Paint background
200 view.repaintGame();
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
208 public void run() {
209 // TODO Will running ever be false?
210 while (running) {
211 // Check if game is paused
212 while (paused) {
213 try {
214 Thread.sleep(100);
215 } catch (InterruptedException e) {
216 // TODO Auto-generated catch block
217 e.printStackTrace();
220 long startTime = System.currentTimeMillis();
222 // Update all units
223 List<Unit> units = model.getUnits();
224 List<Unit> deadUnits = new ArrayList<Unit>();
225 for (Unit unit : units) {
226 if (unit.isAlive()) {
227 // Collisioncheck
228 for (Unit otherUnit : units) {
229 if (unit != otherUnit) {
230 if (unit.intersectsNextMove(otherUnit)) {
231 // Collision!
232 unit.collision(otherUnit);
236 unit.act();
237 } else {
238 // Add dead unit
239 deadUnits.add(unit);
240 logger.info("Dead unit is collected to list deadUnits");
241 //TODO
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");
255 // Update all towers
256 List<Tower> towers = model.getTowers();
257 for (Tower tower : towers) {
258 tower.act();
261 // Remove units from goalsquares and count points
262 GoalSquare[] goalSquares = model.getGoalSquares();
263 int credit = 0;
264 int numOfUnits = 0;
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
270 // completed
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) {
288 // Collision
289 break;
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) {
305 unit.paint(g);
307 for (Tower tower : towers) {
308 tower.paint(g);
311 // Refresh the game view
312 view.repaintGame();
314 this.usedTime = System.currentTimeMillis() - startTime;
315 // Try to keep a given number of frames per second.
316 try {
317 // TODO think, fps???
318 Thread.sleep((1000 - usedTime) / FRAMES_PER_SECOND);
319 } catch (InterruptedException e) {
320 System.err.println("Error in thread, exiting.");
321 return;
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
335 * to the player
337 public void run() {
338 while(clocking) {
339 // Check if game is paused
340 while(paused) {
341 try {
342 Thread.sleep(100);
343 } catch (InterruptedException e) {
344 // TODO Auto-generated catch block
345 e.printStackTrace();
348 // Calculate earned credits
349 int credit = calculateCredit();
350 if (credit > 0) {
351 model.addCredit(credit);
352 view.updateScoreboard();
354 // Goal check
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) {
361 advanceLevel();
362 } else {
363 restartLevel();
366 // Lose check
367 if (model.isLevelLost()) {
369 System.out.println("You lose!");
370 loseGame();
372 try {
373 // Sleep an interval
374 Thread.sleep(1000);
375 } catch (InterruptedException e) {
376 e.printStackTrace();
382 private int calculateCredit() {
383 List<Unit> units = model.getUnits();
384 int credit = units.size() * 10;
385 return credit;
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 {
410 @Override
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) {
421 quitApplication();
424 @Override
425 public void windowClosing(WindowEvent we) {
426 quitApplication();
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) {
456 if (!paused) {
457 ATDController.this.togglePause();
459 view.showAboutDialog();
460 ATDController.this.togglePause();
464 private class HelpListener implements ActionListener {
465 public void actionPerformed(ActionEvent ae) {
466 if (!paused) {
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!");
482 } else {
483 view.printMessage("");