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    }