001         package com.croftsoft.apps.mars.model.seri;
002    
003         import java.awt.*;
004         import java.awt.geom.Ellipse2D;
005         import java.util.Random;
006    
007         import com.croftsoft.core.lang.NullArgumentException;
008         import com.croftsoft.core.math.geom.Circle;
009         import com.croftsoft.core.math.geom.PointXY;
010    
011         import com.croftsoft.apps.mars.model.Obstacle;
012         import com.croftsoft.apps.mars.model.World;
013    
014         /*********************************************************************
015         * An obstacle.
016         *
017         * @version
018         *   2003-05-11
019         * @since
020         *   2003-03-30
021         * @author
022         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
023         *********************************************************************/
024    
025         public final class  SeriObstacle
026           extends SeriModel
027           implements Obstacle
028         //////////////////////////////////////////////////////////////////////
029         //////////////////////////////////////////////////////////////////////
030         {
031    
032         private static final long  serialVersionUID = 0L;
033    
034         //
035    
036         private static final double  Z          = 0.2;
037    
038         private static final double  DRIFT_RATE = 1.0;
039    
040         private static final double  SPEED_MAX  = 1.0;
041    
042         //
043    
044         private final World      world;
045    
046         private final Circle     circle;
047    
048         private final Random     random;
049    
050         private final Rectangle  driftBounds;
051    
052         private final double     radiusMin;
053    
054         //
055    
056         private boolean  active;
057    
058         private boolean  updated;
059    
060         private double   velocityX;
061    
062         private double   velocityY;
063    
064         //////////////////////////////////////////////////////////////////////
065         // constructor methods
066         //////////////////////////////////////////////////////////////////////
067    
068         public  SeriObstacle (
069           World      world,
070           double     centerX,
071           double     centerY,
072           double     radius,
073           double     radiusMin,
074           Random     random,
075           Rectangle  driftBounds )
076         //////////////////////////////////////////////////////////////////////
077         {
078           NullArgumentException.check ( this.world = world );
079    
080           circle = new Circle ( centerX, centerY, radius );
081    
082           this.radiusMin = radiusMin;
083    
084           NullArgumentException.check ( this.random = random );
085    
086           NullArgumentException.check ( this.driftBounds = driftBounds );
087    
088           active = true;
089    
090           updated = true;
091         }
092    
093         //////////////////////////////////////////////////////////////////////
094         // interface Model methods
095         //////////////////////////////////////////////////////////////////////
096    
097         public boolean  isActive  ( ) { return active;  }
098    
099         public Shape    getShape  ( ) { return circle;  }
100    
101         public boolean  isUpdated ( ) { return updated; }
102    
103         public double   getZ      ( ) { return Z;       }
104    
105         public void  setCenter (
106           double  x,
107           double  y )
108         //////////////////////////////////////////////////////////////////////
109         {
110           circle.setCenter ( x, y );       
111         }
112    
113         public void  prepare ( )
114         //////////////////////////////////////////////////////////////////////
115         {
116           updated = false;
117         }
118    
119         public void  update ( double  timeDelta )
120         //////////////////////////////////////////////////////////////////////
121         {
122           if ( !active )
123           {
124             return;
125           }
126    
127           velocityX
128             += DRIFT_RATE * timeDelta * ( 2.0 * random.nextDouble ( ) - 1.0 );
129    
130           velocityY
131             += DRIFT_RATE * timeDelta * ( 2.0 * random.nextDouble ( ) - 1.0 );
132    
133           if ( velocityX > SPEED_MAX )
134           {
135             velocityX = SPEED_MAX;
136           }
137           else if ( velocityX < -SPEED_MAX )
138           {
139             velocityX = -SPEED_MAX;
140           }
141    
142           if ( velocityY > SPEED_MAX )
143           {
144             velocityY = SPEED_MAX;
145           }
146           else if ( velocityY < -SPEED_MAX )
147           {
148             velocityY = -SPEED_MAX;
149           }
150    
151           PointXY  center = circle.getCenter ( );
152    
153           double  oldCenterX = center.getX ( );
154    
155           double  oldCenterY = center.getY ( );
156    
157           double  destinationX = oldCenterX + velocityX * timeDelta;
158    
159           double  destinationY = oldCenterY + velocityY * timeDelta;
160    
161           double  radius = circle.getRadius ( );
162    
163           double  minX = driftBounds.getX      ( ) + radius;
164    
165           double  minY = driftBounds.getY      ( ) + radius;
166    
167           double  maxX = driftBounds.getWidth  ( ) - radius;
168    
169           double  maxY = driftBounds.getHeight ( ) - radius;
170    
171           if ( destinationX < minX )
172           {
173             destinationX = minX;
174    
175             velocityX = -velocityX;
176           }
177           else if ( destinationX > maxX )
178           {
179             destinationX = maxX;
180    
181             velocityX = -velocityX;
182           }
183    
184           if ( destinationY < minY )
185           {
186             destinationY = minY;
187    
188             velocityY = -velocityY;
189           }
190           else if ( destinationY > maxY )
191           {
192             destinationY = maxY;
193    
194             velocityY = -velocityY;
195           }
196    
197           if ( ( destinationX != oldCenterX )
198             || ( destinationY != oldCenterY ) )
199           {
200             circle.setCenter ( destinationX, destinationY );
201    
202             if ( world.isBlocked ( this ) )
203             {
204               circle.setCenter ( oldCenterX, oldCenterY );
205             }       
206             else
207             {
208               updated = true;
209             }         
210           }
211         }
212    
213         //////////////////////////////////////////////////////////////////////
214         // interface Damageable method
215         //////////////////////////////////////////////////////////////////////
216    
217         public void  addDamage ( double  damage )
218         //////////////////////////////////////////////////////////////////////
219         {
220           if ( !active
221             || ( damage == 0.0 ) )
222           {
223             return;
224           }
225    
226           updated = true;
227    
228           double  radius = circle.getRadius ( ) - damage;
229    
230           if ( radius < radiusMin )
231           {
232             active = false;
233           }
234           else
235           {
236             circle.setRadius ( radius );
237           }
238         }
239    
240         //////////////////////////////////////////////////////////////////////
241         // interface Obstacle methods
242         //////////////////////////////////////////////////////////////////////
243    
244         public void  setActive ( boolean  active )
245         //////////////////////////////////////////////////////////////////////
246         {
247           this.active = active;
248         }
249    
250         public void  setRadius ( double  radius )
251         //////////////////////////////////////////////////////////////////////
252         {
253           circle.setRadius ( radius );
254         }
255    
256         //////////////////////////////////////////////////////////////////////
257         //////////////////////////////////////////////////////////////////////
258         }