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 }