001 package components; 002 003 import java.awt.event.ActionEvent; 004 import java.util.HashSet; 005 import java.util.Map; 006 import java.util.Set; 007 008 import physics3d.Angle; 009 import physics3d.Shape; 010 import physics3d.Vect3; 011 012 /** 013 * Absorber is a mutable object that can take in a ball and shoot it out. 014 * 015 *@specfield height : int 016 *@specfield width : int 017 *@specfield depth : int 018 */ 019 020 /* 021 * Abstraction Function 022 * AF(r) = an Absorber, a, such that 023 */ 024 025 /* 026 * Rep Invaariant 027 * height, width, depth >= 1 028 * height, width <=20 029 * depth <= 10 030 * center of the absorber is such that the absorber fits in the bounds of the GameSpace 031 * as specified by the Walls of the GameSpace 032 */ 033 034 public class Absorber extends GameObject { 035 036 //fields 037 /** the thing that this absorber is holding **/ 038 private GameObject holding; 039 040 //constants 041 /** this is apparently enough to have the ball lightly hit the ceiling on defaults **/ 042 private static Vect3 INIT_VEL = Vect3.Y_HAT.times(-50); 043 044 045 //constructors 046 /** Construct an absorber in GameSpace g with the given properties 047 * @requires p of the form { "property" => "setting", ... } **/ 048 public Absorber(Map<String, String> p, GameSpace g) { 049 super(p, g); 050 } 051 052 053 //depth 054 @Override 055 /** 056 * @effects if the Absorber is not currently holding anything, takes in the projectile. 057 * If the absorber is holding something, the projectile bounces off the Absorber. 058 */ 059 public void onCollision(GameObject projectile) { 060 //absorbers, unlike most gizmos, DO care about the projectile 061 if (holding == null) { 062 hold(projectile); 063 } 064 super.onCollision(projectile); 065 } 066 067 /** the bottom-right-back corner of this absorber **/ 068 public Vect3 getBRB() { 069 return new Vect3(center.x() + width/2.0 - 0.25, 070 center.y() + height/2.0 -0.25, 071 center.z() + depth/2.0 - 0.25); 072 } 073 074 /** hold on to the given projectile 075 * @requires projectile is a ball 076 * @throws IllegalArgumentException if projectile is null or projectil is not a ball **/ 077 public void hold(GameObject projectile) { 078 if (projectile == null || !(projectile instanceof Ball)) 079 throw new IllegalArgumentException("to hold: "+projectile); 080 081 holding = projectile; 082 projectile.setVisible(false); 083 projectile.setCenter(getBRB()); 084 projectile.setVelocity(Vect3.ZERO); 085 projectile.setFrozen(true); //FREEZE! 086 } 087 088 /** 089 * @effects the Absorber shoots out the ball if there is one inside 090 */ 091 @Override 092 public void actionPerformed(ActionEvent e) { 093 if (holding != null) { 094 holding.setFrozen(false); //UNFREEZE! 095 holding.setVelocity(INIT_VEL); 096 Vect3 top_right_back = new Vect3(center.x() + width/2.0 - .25, 097 center.y() - height/2.0 -.25, 098 center.z() + depth/2.0 - .25); 099 holding.setCenter(top_right_back); 100 holding.setVisible(true); 101 holding = null; 102 } 103 } 104 105 /** 106 * @return the GameObjectClassification of this object 107 */ 108 public GameObjectClassification getGOClassification() { 109 return GameObjectClassification.ABSORBER; 110 } 111 112 113 //See parent class 114 public void getBasicPropertyMap(Map<String,String> m) { 115 m.put("height", Integer.toString(height)); 116 m.put("width", Integer.toString(width)); 117 m.put("depth", Integer.toString(depth)); 118 super.getBasicPropertyMap(m); 119 } 120 121 @Override 122 protected Shape shape() { 123 return Shape.getAbsorberShape(height, width, depth); 124 } 125 126 /** 127 * @return the set of top left front points of grid positions occupied by this 128 * where the x grid positions go from 0-20, y from 0-20, and z from 0-10 129 */ 130 public Set<Vect3> getOccupiedPositions() { 131 Set<Vect3> ops = new HashSet<Vect3>(); 132 Vect3 tlf = getTLF(); 133 ops.add(tlf); 134 for (int i = 1; i < width; i++) { 135 ops.add(tlf.plus(new Vect3(i, 0, 0))); 136 } 137 for (int i = 1; i < height; i++) { 138 ops.add(tlf.plus(new Vect3(0, i, 0))); 139 } 140 for (int i = 1; i < depth; i++) { 141 ops.add(tlf.plus(new Vect3(0, i, 0))); 142 } 143 return ops; 144 } 145 146 /** the object held by the absorber 147 * @return the object inside the absorber. null if nothing there. **/ 148 public GameObject getObject() { 149 return holding; 150 } 151 /** remove the object from the absorber **/ 152 public void clearObject() { 153 if (holding != null) { 154 g.removeObject(holding); //remove it from gamespace 155 holding = null; 156 } 157 } 158 /** true if the absorber is already holding something 159 * @return true if something is inside the absorber **/ 160 public boolean isFull() { 161 return (holding != null); 162 } 163 164 }