1 package nl.tudelft.jpacman;
2
3 import nl.tudelft.jpacman.board.BoardFactory;
4 import nl.tudelft.jpacman.board.Direction;
5 import nl.tudelft.jpacman.game.Game;
6 import nl.tudelft.jpacman.game.GameFactory;
7 import nl.tudelft.jpacman.level.*;
8 import nl.tudelft.jpacman.npc.ghost.GhostFactory;
9 import nl.tudelft.jpacman.points.PointCalculator;
10 import nl.tudelft.jpacman.points.PointCalculatorLoader;
11 import nl.tudelft.jpacman.sprite.PacManSprites;
12 import nl.tudelft.jpacman.ui.Action;
13 import nl.tudelft.jpacman.ui.PacManUI;
14 import nl.tudelft.jpacman.ui.PacManUiBuilder;
15
16 import java.awt.event.KeyEvent;
17 import java.io.IOException;
18 import java.util.List;
19
20 /**
21 * Creates and launches the JPacMan UI.
22 *
23 * @author Jeroen Roosen
24 */
25 @SuppressWarnings("PMD.TooManyMethods")
26 public class Launcher {
27
28 private static final PacManSprites SPRITE_STORE = new PacManSprites();
29
30 public static final String DEFAULT_MAP = "/board.txt";
31 private String levelMap = DEFAULT_MAP;
32
33 private PacManUI pacManUI;
34 private Game game;
35
36 /**
37 * @return The game object this launcher will start when {@link #launch()}
38 * is called.
39 */
40 public Game getGame() {
41 return game;
42 }
43
44 /**
45 * The map file used to populate the level.
46 *
47 * @return The name of the map file.
48 */
49 protected String getLevelMap() {
50 return levelMap;
51 }
52
53 /**
54 * Set the name of the file containing this level's map.
55 *
56 * @param fileName
57 * Map to be used.
58 * @return Level corresponding to the given map.
59 */
60 public Launcher withMapFile(String fileName) {
61 levelMap = fileName;
62 return this;
63 }
64
65 /**
66 * Creates a new game using the level from {@link #makeLevel()}.
67 *
68 * @return a new Game.
69 */
70 public Game makeGame() {
71 GameFactory gf = getGameFactory();
72 Level level = makeLevel();
73 game = gf.createSinglePlayerGame(level, loadPointCalculator());
74 return game;
75 }
76
77 private PointCalculator loadPointCalculator() {
78 return new PointCalculatorLoader().load();
79 }
80
81 /**
82 * Creates a new level. By default this method will use the map parser to
83 * parse the default board stored in the <code>board.txt</code> resource.
84 *
85 * @return A new level.
86 */
87 public Level makeLevel() {
88 try {
89 return getMapParser().parseMap(getLevelMap());
90 } catch (IOException e) {
91 throw new PacmanConfigurationException(
92 "Unable to create level, name = " + getLevelMap(), e);
93 }
94 }
95
96 /**
97 * @return A new map parser object using the factories from
98 * {@link #getLevelFactory()} and {@link #getBoardFactory()}.
99 */
100 protected MapParser getMapParser() {
101 return new MapParser(getLevelFactory(), getBoardFactory());
102 }
103
104 /**
105 * @return A new board factory using the sprite store from
106 * {@link #getSpriteStore()}.
107 */
108 protected BoardFactory getBoardFactory() {
109 return new BoardFactory(getSpriteStore());
110 }
111
112 /**
113 * @return The default {@link PacManSprites}.
114 */
115 protected PacManSprites getSpriteStore() {
116 return SPRITE_STORE;
117 }
118
119 /**
120 * @return A new factory using the sprites from {@link #getSpriteStore()}
121 * and the ghosts from {@link #getGhostFactory()}.
122 */
123 protected LevelFactory getLevelFactory() {
124 return new LevelFactory(getSpriteStore(), getGhostFactory(), loadPointCalculator());
125 }
126
127 /**
128 * @return A new factory using the sprites from {@link #getSpriteStore()}.
129 */
130 protected GhostFactory getGhostFactory() {
131 return new GhostFactory(getSpriteStore());
132 }
133
134 /**
135 * @return A new factory using the players from {@link #getPlayerFactory()}.
136 */
137 protected GameFactory getGameFactory() {
138 return new GameFactory(getPlayerFactory());
139 }
140
141 /**
142 * @return A new factory using the sprites from {@link #getSpriteStore()}.
143 */
144 protected PlayerFactory getPlayerFactory() {
145 return new PlayerFactory(getSpriteStore());
146 }
147
148 /**
149 * Adds key events UP, DOWN, LEFT and RIGHT to a game.
150 *
151 * @param builder
152 * The {@link PacManUiBuilder} that will provide the UI.
153 */
154 protected void addSinglePlayerKeys(final PacManUiBuilder builder) {
155 builder.addKey(KeyEvent.VK_UP, moveTowardsDirection(Direction.NORTH))
156 .addKey(KeyEvent.VK_DOWN, moveTowardsDirection(Direction.SOUTH))
157 .addKey(KeyEvent.VK_LEFT, moveTowardsDirection(Direction.WEST))
158 .addKey(KeyEvent.VK_RIGHT, moveTowardsDirection(Direction.EAST));
159 }
160
161 private Action moveTowardsDirection(Direction direction) {
162 return () -> {
163 assert game != null;
164 getGame().move(getSinglePlayer(getGame()), direction);
165 };
166 }
167
168 private Player getSinglePlayer(final Game game) {
169 List<Player> players = game.getPlayers();
170 if (players.isEmpty()) {
171 throw new IllegalArgumentException("Game has 0 players.");
172 }
173 return players.get(0);
174 }
175
176 /**
177 * Creates and starts a JPac-Man game.
178 */
179 public void launch() {
180 makeGame();
181 PacManUiBuilder builder = new PacManUiBuilder().withDefaultButtons();
182 addSinglePlayerKeys(builder);
183 pacManUI = builder.build(getGame());
184 pacManUI.start();
185 }
186
187 /**
188 * Disposes of the UI. For more information see
189 * {@link javax.swing.JFrame#dispose()}.
190 *
191 * Precondition: The game was launched first.
192 */
193 public void dispose() {
194 assert pacManUI != null;
195 pacManUI.dispose();
196 }
197
198 /**
199 * Main execution method for the Launcher.
200 *
201 * @param args
202 * The command line arguments - which are ignored.
203 */
204 public static void main(String[] args) {
205 new Launcher().launch();
206 }
207 }