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 }