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    }