1 package se
.umu
.cs
.dit06ajnajs
.level
;
3 import java
.awt
.Dimension
;
4 import java
.awt
.Graphics
;
7 import java
.awt
.image
.BufferedImage
;
8 import java
.util
.ArrayList
;
10 import java
.util
.logging
.Logger
;
12 import se
.umu
.cs
.dit06ajnajs
.AntiTD
;
13 import se
.umu
.cs
.dit06ajnajs
.agent
.Direction
;
14 import java
.util
.Collection
;
15 import se
.umu
.cs
.dit06ajnajs
.agent
.Tower
;
18 * Level is used to contain and manage all information about a level beeing
21 * @author Anton Johansson (dit06ajn@cs.umu.se)
22 * @author Andreas Jacobsson (dit06ajs@cs.umu.se)
26 private static Logger logger
= Logger
.getLogger("AntiTD");
29 private int unitsToWin
;
30 private int clearedUnits
;
31 private int squareSize
;
36 private MapSquare
[][] squareMatrix
;
37 private GoalSquare
[] goalSquares
;
38 private StartSquare
[] startSquares
;
39 private Collection
<Tower
> towers
;
42 * Sets parameters and adds Towers to random locations.
44 * @param name The name of this Level.
45 * @param squareMatrix A matrix containing MapSquares.
46 * @param towers Towers to add to this Level.
47 * @param unitsToWin The amount of Units needed in GoalSquares to win this
50 public Level(String name
, MapSquare
[][] squareMatrix
,
51 Collection
<Tower
> towers
, int unitsToWin
) {
52 this(name
, squareMatrix
);
54 // Add towers to TowerSquares
56 this.unitsToWin
= unitsToWin
;
57 for (Tower tower
: towers
) {
63 * Calculates and sets variables such as width and height based on the
64 * supplied matrix containing MapSquares. Makes every StartSquare observe
65 * alle the other. Initializes all TurnSquare to set all valid Direction.
67 * @param name The name of this Level.
68 * @param squareMatrix A matrix containing MapSquares.
70 public Level(String name
, MapSquare
[][] squareMatrix
) {
72 this.squareSize
= AntiTD
.SQUARE_SIZE
;
73 this.squareMatrix
= squareMatrix
;
74 this.clearedUnits
= 0;
76 this.numCol
= squareMatrix
.length
;
77 this.numRow
= squareMatrix
[0].length
;
78 } catch(NullPointerException e
) {
83 // Set width and height for map
84 this.width
= squareSize
* numCol
;
85 this.height
= squareSize
* numRow
;
87 this.goalSquares
= extractGoalSquares();
88 this.startSquares
= extractStartSquares();
89 // Make all startSquares observe each other
90 for (StartSquare s1
: startSquares
) {
91 for (StartSquare s2
: startSquares
) {
93 logger
.info("StartSquare observable: " + s1
94 + ", is observed by " + s2
);
103 * Reset the Level information, clears all Units, activates on StartSquare,
106 public void resetLevel() {
107 this.clearedUnits
= 0;
108 // Set one StartSquare as active
109 startSquares
[0].click();
111 this.resetStartSquares();
115 * Cleares queued units from start squares
118 private void resetStartSquares() {
119 for (StartSquare square
: this.startSquares
) {
125 * Returns the MapSquare at given x- y-coordinate.
127 * @param x The x-value to check.
128 * @param y The y-value to check.
129 * @return The MapSquare at given x- y-coordinate or null if none exist.
131 public MapSquare
getMapSquareAtPoint(int x
, int y
) {
132 return getMapSquareAtPoint(new Point(x
, y
));
136 * Returns the MapSquare at given x- y-coordinate.
138 * @param point The point to check.
139 * @return The MapSquare at given x- y-coordinate or null if none exist.
141 public MapSquare
getMapSquareAtPoint(Point point
) {
142 //TODO testa algoritmen
146 if (x
> width
|| y
> height
152 int col
= x
/ AntiTD
.SQUARE_SIZE
;
153 int row
= y
/ AntiTD
.SQUARE_SIZE
;
155 return squareMatrix
[col
][row
];
159 * Sets a new MapSquare at given x- y-coordinate.
161 * @param x The x-coordinate.
162 * @param y The y-coordinate.
163 * @param mapSquare The MapSquare to set at given x- y-coordinates .
165 public void setMapSquareAtPoint(int x
, int y
, MapSquare mapSquare
) {
166 setMapSquareAtPoint(new Point(x
, y
), mapSquare
);
170 * Sets a new MapSquare at given x- y-coordinate.
172 * @param point The point to set a new MapSquare.
173 * @param mapSquare The MapSquare to set at given point.
175 public void setMapSquareAtPoint(Point point
, MapSquare mapSquare
) {
179 if (x
> width
|| y
> height
) {
180 throw new IllegalArgumentException("Position is " +
181 "outside of map bounds.");
184 int col
= x
/ AntiTD
.SQUARE_SIZE
;
185 int row
= y
/ AntiTD
.SQUARE_SIZE
;
187 squareMatrix
[col
][row
] = mapSquare
;
191 * Creates a new Image representing this Level and returns it.
193 * @return A new Image representing this Level and returns it.
195 public Image
getMapImage() {
196 logger
.fine("------> getMapImage() -> " + Thread
.currentThread().toString());
197 Image backgroundImage
= new BufferedImage(width
, height
,
198 BufferedImage
.TYPE_INT_RGB
);
199 Graphics g
= backgroundImage
.getGraphics();
201 for (MapSquare
[] row
: squareMatrix
) {
202 for (MapSquare square
: row
) {
206 return backgroundImage
;
210 * Returns the Dimension of this Level.
212 * @return The Dimension of this Level.
214 public Dimension
getDimension() {
215 return new Dimension(width
, height
);
219 * Extract and return all GoalSquares in this Level.
221 * @return All GoalSquares in this Level.
223 private GoalSquare
[] extractGoalSquares() {
224 List
<GoalSquare
> squares
= new ArrayList
<GoalSquare
>();
225 for (MapSquare
[] row
: squareMatrix
) {
226 for (MapSquare square
: row
) {
227 if (square
instanceof GoalSquare
) {
228 squares
.add((GoalSquare
) square
);
232 GoalSquare
[] goalSquares
233 = squares
.toArray(new GoalSquare
[squares
.size()]);
238 * Extract all StartSquares from this Level.
240 * @return All StartSquares in this Level.
242 private StartSquare
[] extractStartSquares() {
243 List
<StartSquare
> squares
= new ArrayList
<StartSquare
>();
244 for (MapSquare
[] row
: squareMatrix
) {
245 for (MapSquare square
: row
) {
246 if (square
instanceof StartSquare
) {
247 squares
.add((StartSquare
) square
);
251 StartSquare
[] startSquares
252 = squares
.toArray(new StartSquare
[squares
.size()]);
257 * Returns a random free TowerSquare.
259 * @return A random free TowerSquare.
261 private TowerSquare
getRandomFreeTowerSquare() {
262 List
<TowerSquare
> squares
= extractTowerSquares();
263 List
<TowerSquare
> freeSquares
= new ArrayList
<TowerSquare
>();
265 for (TowerSquare square
: squares
) {
266 if (square
.isAvailable()) {
267 freeSquares
.add(square
);
270 if (freeSquares
.isEmpty()) {
271 // TODO What should happen if there are no free towersquares?
274 int index
= (int) (freeSquares
.size()*Math
.random());
275 return freeSquares
.get(index
);
278 public List
<TowerSquare
> extractTowerSquares() {
279 // TODO What should happen if there are no towersquares?
280 List
<TowerSquare
> squares
= new ArrayList
<TowerSquare
>();
281 for (MapSquare
[] row
: squareMatrix
) {
282 for (MapSquare square
: row
) {
283 if (square
instanceof TowerSquare
) {
284 squares
.add((TowerSquare
) square
);
292 * Extract all MapSquare of type TurnSquare from this Level.
294 * @return All TurnSquares in this Level.
296 public List
<TurnSquare
> extractTurnSquares() {
297 // TODO What should happen if there are no TurnSquares?
298 List
<TurnSquare
> squares
= new ArrayList
<TurnSquare
>();
299 for (MapSquare
[] row
: squareMatrix
) {
300 for (MapSquare square
: row
) {
301 if (square
instanceof TurnSquare
) {
302 squares
.add((TurnSquare
) square
);
310 * Returns every neighbouring MapSquare of the supplied MapSquare within
313 * @param square The square to get neighbours from.
314 * @param range Should be an int describing how many MapSquares away from
315 * specified MapSquares to return.
316 * @return A list of neighbouring MapSquares.
318 public List
<MapSquare
> getNeighbours(MapSquare square
, int range
) {
319 List
<MapSquare
> neighbours
= new ArrayList
<MapSquare
>();
321 // Calculate row and col
322 int col
= square
.getX() / AntiTD
.SQUARE_SIZE
;
323 int row
= square
.getY() / AntiTD
.SQUARE_SIZE
;
325 // Get width to scan for neighbours
326 int scanWidth
= range
* 2 + 1;
328 // Get top left position to start scanning of neighbours
329 int colLeft
= col
- range
;
330 int rowTop
= row
- range
;
332 logger
.info("Range: " + range
+ ", colLeft: " + colLeft
333 + ", rowTop: " + rowTop
+ ", scanWidth: " + scanWidth
);
335 // Nestled loop from top-left position
336 for (int tmpRow
= rowTop
;
337 tmpRow
< scanWidth
+ rowTop
;
339 for (int tmpCol
= colLeft
;
340 tmpCol
< scanWidth
+ colLeft
;
342 if (tmpCol
>= 0 && tmpCol
< numCol
// Col is inside bounds
343 // Row is inside bounds
344 && tmpRow
>= 0 && tmpRow
< numRow
345 // Col Row should not point to square to find neighbours
347 && (tmpRow
!= row
|| tmpCol
!= col
)) {
349 logger
.info("Adding neigbour for: " + square
+ "\n"
350 + " At col: " + tmpCol
+ ", row: " + tmpRow
);
351 neighbours
.add(squareMatrix
[tmpCol
][tmpRow
]);
355 logger
.info(neighbours
.size() + " neighbours found.");
360 * Calculate and set every possible direction the TurnSquares in this Level
361 * can have. Adds a Direction to every neighbouring MapSquare that is a
364 private void initTurnSquares() {
365 for (TurnSquare turnSquare
: extractTurnSquares()) {
366 int col
= turnSquare
.getX() / AntiTD
.SQUARE_SIZE
;
367 int row
= turnSquare
.getY() / AntiTD
.SQUARE_SIZE
;
370 && squareMatrix
[col
][row
- 1] instanceof PathSquare
) {
371 turnSquare
.addDirection(Direction
.UP
);
375 && squareMatrix
[col
+ 1][row
] instanceof PathSquare
) {
376 turnSquare
.addDirection(Direction
.RIGHT
);
380 && squareMatrix
[col
][row
+ 1] instanceof PathSquare
) {
381 turnSquare
.addDirection(Direction
.DOWN
);
385 && squareMatrix
[col
- 1][row
] instanceof PathSquare
) {
386 turnSquare
.addDirection(Direction
.LEFT
);
392 * Return every GoalSquare in this Level.
394 * @return every GoalSquare in this Level.
396 public GoalSquare
[] getGoalSquares() {
397 return this.goalSquares
;
401 * Return every StartSquare in this Level.
403 * @return every StartSquare in this Level.
405 public StartSquare
[] getStartSquares() {
406 return this.startSquares
;
410 * Gets the name of this Level.
412 * @return The name of this Level.
414 public String
getName() {
419 * Returns an Array representation of this map.
421 * @return An Array representation of this map.
423 public MapSquare
[][] toArray() {
428 * Return the active StartSquare in this Level.
430 * @return The active StartSquare in this Level.
432 public StartSquare
getActiveStartSquare() {
433 for (StartSquare square
: startSquares
) {
434 if (square
.isActive()) {
438 throw new NoActiveStartSquareException();
442 * Add a Tower to this Level. Will place the Tower at a random
443 * TowerSquare. Every neighbouring PathSquare is set to observe the Tower.
445 * @param t The Tower to add.
447 public void addTower(Tower t
) {
448 TowerSquare square
= getRandomFreeTowerSquare();
449 if (square
!= null) {
450 Point tPos
= new Point(square
.getCenterX() - (t
.getWidth()/2)
451 , square
.getCenterY() - (t
.getHeight()/2));
452 t
.setPostition(tPos
);
455 logger
.info("Tower placed @ (" + tPos
.x
+ ", " + tPos
.y
+ ")");
457 //Register as observer for the neighbours in range
458 int shootRange
= t
.getRange();
460 (int) Math
.ceil((shootRange
- AntiTD
.SQUARE_SIZE
*0.5)
461 / (AntiTD
.SQUARE_SIZE
));
463 List
<MapSquare
> neighbours
464 = getNeighbours(square
, squareRange
);
465 logger
.info("There are >" + neighbours
.size()
466 + "< neighbours in range >" + t
.getRange() + "< pixels");
468 for (MapSquare neighbour
: neighbours
) {
469 if (neighbour
instanceof PathSquare
) {
470 logger
.info("Adding tower-observer: " + t
471 + " to: " + neighbour
);
472 neighbour
.addObserver(t
);
476 throw new IllegalArgumentException("No available towersquares");
481 * Returns all Towers in this Level.
483 * @return All Towers in this Level.
485 public Collection
<Tower
> getTowers() {
492 public void resetTowers() {
493 for (Tower tower
: this.towers
) {
499 * Returns the number of Units needed in goal to win this Level.
501 * @return The number of Units needed in goal to win this Level.
503 public int getUnitsToWin() {
504 return this.unitsToWin
;
508 * Returns the number of units that have reached a goalsquare.
509 * @return The number of units that have reached a goalsquare.
511 public int getNumOfClearedUnits() {
512 return this.clearedUnits
;
516 * Adds to the number of units that have reached a goalsquare.
517 * @param num Number of new units that have reached a goalsquare.
519 public void addClearedUnits(int num
) {
520 this.clearedUnits
+= num
;