001 package components;
002
003 import java.awt.event.KeyEvent;
004 import java.awt.event.KeyListener;
005 import java.io.File;
006 import java.io.IOException;
007 import java.util.Collections;
008 import java.util.HashMap;
009 import java.util.HashSet;
010 import java.util.Map;
011 import java.util.Set;
012
013 import javax.xml.parsers.ParserConfigurationException;
014
015 import org.xml.sax.SAXException;
016
017 import physics3d.Angle;
018 import physics3d.Vect3;
019 import rendering.Textures;
020 import staffui.MagicKeyListener;
021
022 /**
023 * GameSpace is the game board where a game of Gizmoball take place
024 *
025 * @specfield gameObjects : set //the GameObjects in the GameSpace
026 * @specfield walls : set // the set of Walls for the GameSpace
027 * @specfield settings : GameSettings //the class maintains game settings
028 */
029
030
031 /*
032 * Abstraction Function
033 * AF(r) = a GameSpace, g, such that
034 * g.fixedObjects = r.fObjects
035 * g.mobileObjects = r.mObjects
036 * g.walls = r.walls
037 * g.settings = r.settings
038 */
039
040 /*
041 * Rep Invariant
042 * all fields are not null
043 * the fixedObjects and mobileObjects and wall all have gs as their GameSpace.
044 * the fixedObjects and mobileObjects are within the walls of the GameSpace
045 */
046
047
048 public class GameSpace implements KeyListener {
049
050
051
052 //setupy things
053 private static final boolean debug = false;
054 private GameSettings settings;
055 private Set<GameObject> gObjects;
056 private final Set<Wall> walls;
057
058 //texture
059 private Map<GameObjectClassification, String> texLocations;
060
061 //listeny things
062 protected MagicKeyListener mkl;
063 private KeyRegistry registry; //keeps track of which keys->gameobjects
064
065 //constructors
066 public GameSpace(GameSettings settings) {
067 this.settings = settings;
068 gObjects = Collections.synchronizedSet(new HashSet<GameObject>());
069
070 //add walls...this sizes are specified
071 int xsize = 20;
072 int ysize = 20;
073 int zsize = 10;
074 Set<Wall> set = new HashSet<Wall>();
075 set.add(new Wall(new Vect3(0, 0, 0), ysize, xsize,
076 Vect3.Z_HAT, Angle.ZERO, false, "front wall", this));
077 set.add(new Wall(new Vect3(0, 0, zsize), ysize, xsize,
078 Vect3.Z_HAT, Angle.DEG_180, false, "back wall", this));
079 set.add(new Wall(new Vect3(-xsize/4, 0, zsize/2), ysize, zsize,
080 Vect3.Y_HAT, Angle.DEG_90, false, "left wall", this));
081 set.add(new Wall(new Vect3(3*xsize/4, 0, zsize/2), ysize, zsize,
082 Vect3.Y_HAT, Angle.DEG_90, false, "right wall", this));
083 set.add(new Wall(new Vect3(0, 3*ysize/4, zsize/2), zsize, xsize,
084 Vect3.X_HAT.neg(), Angle.DEG_90, false, "bottom wall", this));
085 set.add(new Wall(new Vect3(0, -ysize/4, zsize/2), zsize, xsize,
086 Vect3.X_HAT, Angle.DEG_90, false, "top wall", this));
087 walls = Collections.unmodifiableSet(set);
088
089 //default texture locations
090 texLocations = Textures.getDefaultTex();
091
092 if (debug) checkRep();
093
094 //listen!
095 this.mkl = new MagicKeyListener(this, true);
096 this.registry = new KeyRegistry();
097 }
098
099
100 //Proves the repInvariant
101 private void checkRep() {
102
103 for (GameObject elt : this.getObjects()) {
104 if (elt == null) {
105 throw new RuntimeException("Error, object is null!");
106 }
107 if (elt.getGameSpace() != this) {
108 throw new RuntimeException("Error, object does not reference me as gamespace");
109 }
110 // //These values will change, when they're not longer hard coded
111 // if (elt.getTLF().x() > 20 || elt.getTLF().y() > 20 || elt.getTLF().z() > 10) {
112 // throw new RuntimeException("Error, gameobject has left the gamespace!");
113 // }
114
115 }
116 }
117
118
119
120 //methods
121
122 /**
123 * Given a file name, will load that files gb xml data in this
124 * @throws IOException
125 * @throws SAXException
126 * @throws ParserConfigurationException
127 * @requires string is a valid xml file location name
128 */
129 public void writeXML(File name) throws ParserConfigurationException, SAXException, IOException {
130 XMLWriter xmlw = new XMLWriter();
131 xmlw.writeXML(this, name);
132 }
133
134 /**
135 * @requires name is a the name of an object in this
136 * @return the gameobject whose name is the arugment "name"
137 */
138 public GameObject getByName(String name) {
139 synchronized (gObjects) {
140 if (debug) checkRep();
141 for(GameObject m : gObjects) {
142 if (m.getName().equalsIgnoreCase(name))
143 return m;
144 }
145 throw new RuntimeException("Name " + name + " not found in gamespace");
146 }
147 }
148
149
150 /**
151 * @requires cname is the String name of a recognized class
152 * @returns gObjects, without Walls or cnames
153 */
154 public Set<GameObject> getObjectsBut(GameObjectClassification c) {
155
156 synchronized (gObjects) {
157 Set<GameObject> toReturn = new HashSet<GameObject>();
158 for (GameObject go : gObjects) {
159 if ( go.getGOClassification() != c && go.getGOClassification() != GameObjectClassification.WALL) {
160 toReturn.add(go);
161 }
162 }
163 return Collections.unmodifiableSet(toReturn);
164 }
165 }
166
167 /**
168 * @return gObjects U walls
169 */
170 public Set<GameObject> getObjects() {
171 Set<GameObject> objs = gObjects;
172 objs.addAll(walls);
173 return Collections.unmodifiableSet(objs);
174 }
175
176 /**
177 * @return gObjects
178 */
179 public Set<GameObject> getObjectsNoWalls() {
180 return Collections.unmodifiableSet(gObjects);
181 }
182
183 /**
184 * Returns just the balls
185 * @returns only the ball objects
186 */
187 public Set<GameObject> getBalls() {
188 synchronized (gObjects) {
189 Set<GameObject> toReturn = Collections.synchronizedSet(new HashSet<GameObject>());
190
191 for (GameObject go: gObjects) {
192 if (go.getGOClassification() == GameObjectClassification.BALL) {
193 toReturn.add(go);
194 }
195 }
196 return Collections.unmodifiableSet(toReturn);
197 }
198 }
199 // /**
200 // * @requires loc != null, and loc is within the bounds of the game space.
201 // * @return the fixed object at loc (it could return the mobile object at loc too, but that won't happen)
202 // */
203 // public GameObject getObjectAt(Vect3 loc) {
204 // throw new RuntimeException("not implemented");
205 // }
206 //
207 //
208 // /**
209 // * @requires loc != null, and loc is within the bounds of the game space.
210 // * @return the fixed objects within size grid spaces of loc
211 // */
212 // public List<GameObject> getObjectAround(Vect3 loc, int size) {
213 // throw new RuntimeException("not implemented");
214 // }
215
216
217 /**
218 * @requires o != null, o within bounds of the GameSpace, o.g equals this
219 * @effects adds fo into the GameSpace
220 */
221 public void add(GameObject o) {
222 if (debug) checkRep();
223 if (!o.getGameSpace().equals(this)) {
224 throw new IllegalArgumentException("GameObject must referece this GameSpace");
225 }
226 gObjects.add(o);
227 if (debug) checkRep();
228 }
229
230
231
232
233
234
235 public void stepFrame() {
236 // t.start();
237 synchronized (gObjects) {
238 if (debug) checkRep();
239 for (GameObject go : gObjects) {
240 go.stepFrame();
241 }
242 }
243 // t.stop();
244
245 if (debug) checkRep();
246 }
247
248
249 /**
250 * @return this.settings
251 */
252 public GameSettings getSettings() {
253 if (debug) checkRep();
254 return settings;
255 }
256
257 /**
258 * @requires settings != null
259 * @effects This loads settings into this, and replace this.settings
260 */
261 public void loadSettings(GameSettings settings) {
262 if (debug) checkRep();
263 this.settings = settings;
264 }
265
266 /**
267 * @requires objecttype, properties != null, properties contains all the properties
268 * that objecttype requires
269 * @effects creates a new GameObject according to properties and adds it into the GameSpace
270 */
271 public void loadObject(GameObjectClassification objecttype, Map<String,String> properties) {
272 if (debug) checkRep();
273 GameObject newObject = objecttype.newInstance(properties, this);
274 add(newObject);
275 if (debug) checkRep();
276 }
277
278 /**
279 * @return a Map of texture locations used by this GameObject keyed by GameObjectClassifications
280 */
281 public Map<GameObjectClassification, String> getTexLocations() {
282 return texLocations;
283 }
284
285 /**
286 * @requires p != null, p is a top left front corner grid position
287 * @return the GameObject whose top left front corner is p or null if no such GameObject
288 * is in the GameSpace
289 */
290 public GameObject getObjectByGrid(Vect3 p) {
291 for (GameObject go : gObjects) {
292 if (go.getTLF().equals(p)) {
293 return go;
294 }
295 }
296 return null;
297 }
298
299 /**
300 * @requires go != null
301 * @modifies gObjects
302 * @effects removes go from gObjects if it is in gObjects
303 */
304 public void removeObject(GameObject go) {
305 gObjects.remove(go);
306 }
307
308 /**
309 * @requires newTL != null
310 * @modifies texLocations
311 * @effects changes the set of textures used by this GameSpace to those specified by newTL
312 */
313 public void setTexLocations(Map<GameObjectClassification, String> newTL) {
314 texLocations = newTL;
315 }
316
317
318 ////////////////////////////////
319 //
320 // KEY LISTENER STUFF:
321 // uses registry to select which object
322 // then fires that object's action() method
323 //
324 ////////////////////////////////
325 public KeyListener getListener() {
326 return mkl;
327 }
328 public void addUpKey(int key, GameObject tgt) {
329 registry.registerUp(key, tgt);
330 }
331 public void addDownKey(int key, GameObject tgt) {
332 registry.registerDown(key, tgt);
333 System.err.println("registry now contains "+ registry.getDown(key)+ " for "+ key);
334 }
335
336 public void keyPressed(KeyEvent arg0) {
337 if (debug) checkRep();
338 System.err.println("entered gamespace keyPressed");
339 Set<GameObject> tgts = registry.getDown(arg0.getKeyCode());
340 if (tgts != null)
341 for(GameObject g : tgts)
342 g.action();
343 if (debug) checkRep();
344 }
345
346 public void keyReleased(KeyEvent arg0) {
347 if (debug) checkRep();
348 Set<GameObject> tgts = registry.getUp(arg0.getKeyCode());
349 if (tgts != null)
350 for(GameObject g : tgts)
351 g.action();
352 if (debug) checkRep();
353 }
354
355 public void keyTyped(KeyEvent arg0) {
356 /* we do nothing on keytyped events
357 if (debug) checkRep();
358 for (GameObject g : this.getObjects())
359 g.getKeyListener().keyTyped(arg0);
360 if (debug) checkRep();
361 */
362 }
363
364 /** return the key registry **/
365 public KeyRegistry getRegistry() {
366 return registry;
367 }
368 }