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 }