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 /** <p>
013 * A Flipper is a mutable object that represents a flipper in the game
014 * A flipper
015 * </p>
016 * @specfield homeState : boolean //says whether the Flipper is down or up
017 * @specfield currentAngle : Angle //the current angle of the Flipper
018 */
019
020 public abstract class Flipper extends GameObject {
021 /*
022 * Abstraction Function
023 * AF(r) = a Flipper, f, such that
024 * f.homeState = r.homeState
025 * f.current = r.currentAngle
026 */
027
028 /*
029 * Representation Invariant
030 * homeState, Current != null
031 * the Flipper is within the bounds of its GameSpace, as specified by the Walls of
032 * the GameSpace
033 * current is between 0 and 90 degrees
034 */
035
036
037 //fields
038 private Boolean homeState; //true if Flipper is in home state, false if in away state
039 private Angle current; //current angle of Flipper
040
041 private Vect3 diff; //difference between tlf and center
042 final double RADS_PER_SECOND = 9.85;
043
044 //constructors
045
046 /**
047 * @effects constructs a new flipper
048 */
049 public Flipper(Vect3 tlf, Vect3 center, Vect3 ov, Angle oa, String name, GameSpace g) {
050 super(tlf, ov,oa,name,g);
051 this.shape = Shape.getFlipperShape();
052 this.current = Angle.ZERO;
053 this.homeState = true;
054 this.center = center;
055 diff = center.minus(tlf);
056 }
057
058 public Flipper(Map<String, String> props, GameSpace gs) {
059 super(props, gs);
060 this.shape = Shape.getFlipperShape();
061 this.current = Angle.ZERO;
062 this.homeState = true;
063 }
064
065 //methods
066 public abstract Vect3 getDiff(); //different for left and right flippers
067
068 @Override
069 protected Shape shape() {
070 return Shape.getFlipperShape();
071 }
072
073 /** default coref for flippers is 0.95. also, flippers require an orientation. **/
074 @Override
075 protected Map<String, String> defaults() {
076 Map<String, String> def = super.defaults();
077 def.remove("orientation");
078 def.put("coref", "0.95");
079 return def;
080 }
081
082
083 @Override
084 public Angle getOrientAngle() {
085 return orientAngle.plus(current);
086 }
087
088 /**
089 * @effects changes homeState to the opposite boolean value
090 */
091 @Override
092 public void actionPerformed(ActionEvent e) {
093 homeState = !homeState;
094 }
095
096 /**
097 * @effects if flipper is in home state, but its angle is not 0 degrees, decrease
098 * the angle by the radians/frame. if flipper is not in home state, but its angle
099 * is not 90 degrees, increase the angle by the radians/frame.
100 */
101 public void stepFrame() {
102 double radsPerFrame = RADS_PER_SECOND / g.getSettings().getFPS();
103 Angle angleToMove = new Angle(radsPerFrame);
104 if (homeState && !current.equals(Angle.ZERO)) {
105 //since Angles are never negative, this effectively tests overshooting 0
106 if (current.minus(angleToMove).compareTo(Angle.DEG_90) > 0) {
107 current = Angle.ZERO;
108 } else {
109 current = current.minus(angleToMove);
110 }
111 }
112 else if (!homeState && current.compareTo(Angle.DEG_90) < 0) {
113 if (current.plus(angleToMove).compareTo(Angle.DEG_90) > 0) {
114 current = Angle.DEG_90;
115 } else {
116 current = current.plus(angleToMove);
117 }
118 }
119 }
120
121 /**
122 * @return the GameObjectClassification of this object
123 */
124 public GameObjectClassification getGOClassification() {
125 return GameObjectClassification.FLIPPER;
126 }
127
128
129 /**
130 * @return the top left front corners of the grid locations occupied by the flipper,
131 * where the x grid positions go from 0-20, y from 0-20, and z from 0-10
132 */
133 public Set<Vect3> getOccupiedPositions() {
134 Set<Vect3> ops = new HashSet<Vect3>();
135 Vect3 tlf = getTLF();
136 ops.add(tlf);
137 ops.add(tlf.plus(new Vect3(1, 0, 0)));
138 ops.add(tlf.plus(new Vect3(0, 1, 0)));
139 ops.add(tlf.plus(new Vect3(1, 1, 0)));
140 return ops;
141 }
142
143 /** @return the direction of the vector represents the axis about which it rotates,
144 * the magnitude of the vector is how fast, in rad/sec
145 *
146 */
147 public Vect3 getAngularVelocity() {
148 if (homeState && current.compareTo(Angle.ZERO) > 0 ||
149 !homeState && current.compareTo(Angle.DEG_90) < 0) { //isMoving
150 return orientVect.unitSize().times(RADS_PER_SECOND);
151 } else {
152 return Vect3.ZERO;
153 }
154 }
155 }