001         package com.croftsoft.core.animation.updater;
002    
003         import java.awt.Rectangle;
004         import java.awt.Shape;
005         import javax.swing.JComponent;
006    
007         import com.croftsoft.core.animation.Clock;
008         import com.croftsoft.core.animation.ComponentUpdater;
009         import com.croftsoft.core.animation.Sprite;
010         import com.croftsoft.core.lang.NullArgumentException;
011         import com.croftsoft.core.math.MathConstants;
012    
013         /*********************************************************************
014         * Bounces a Sprite off the walls of a Rectangle.
015         *
016         * @version
017         *   2003-07-11
018         * @since
019         *   2002-02-15
020         * @author
021         *   <a href="https://www.croftsoft.com/">David Wallace Croft</a>
022         *********************************************************************/
023    
024         public final class  BounceUpdater
025           implements ComponentUpdater
026         //////////////////////////////////////////////////////////////////////
027         //////////////////////////////////////////////////////////////////////
028         {
029    
030         private final Sprite     sprite;
031    
032         private final Rectangle  bounds;
033    
034         private final Clock      clock;
035    
036         private final Rectangle  collisionBounds;
037    
038         private final Rectangle  newPaintBounds;
039    
040         private final Rectangle  oldPaintBounds;
041    
042         //
043    
044         private long  lastUpdateTimeNanos;
045    
046         //////////////////////////////////////////////////////////////////////
047         //////////////////////////////////////////////////////////////////////
048    
049         public  BounceUpdater (
050           Sprite     sprite,
051           Rectangle  bounds,
052           Clock      clock )
053         //////////////////////////////////////////////////////////////////////
054         {
055           NullArgumentException.check ( this.sprite = sprite );
056    
057           NullArgumentException.check ( this.bounds = bounds );
058    
059           NullArgumentException.check ( this.clock  = clock  );
060    
061           collisionBounds = new Rectangle ( );
062    
063           newPaintBounds  = new Rectangle ( );
064    
065           oldPaintBounds  = new Rectangle ( );
066         }
067    
068         //////////////////////////////////////////////////////////////////////
069         //////////////////////////////////////////////////////////////////////
070    
071         public void  update ( JComponent  component )
072         //////////////////////////////////////////////////////////////////////
073         {
074           long  updateTimeNanos = clock.currentTimeNanos ( );
075    
076           if ( updateTimeNanos == lastUpdateTimeNanos )
077           {
078             return;
079           }
080    
081           double  timeDelta
082             = ( updateTimeNanos - lastUpdateTimeNanos )
083             / ( double ) MathConstants.NANOSECONDS_PER_SECOND;
084    
085           lastUpdateTimeNanos = updateTimeNanos;
086    
087           double  x = sprite.getX ( );
088    
089           double  y = sprite.getY ( );
090    
091           double  heading  = sprite.getHeading  ( );
092    
093           double  velocity = sprite.getVelocity ( );
094    
095           double  delta_x = Math.cos ( heading ) * velocity * timeDelta;
096    
097           double  delta_y = Math.sin ( heading ) * velocity * timeDelta;
098    
099           x += delta_x;
100    
101           y += delta_y;
102    
103           int  minX = bounds.x;
104    
105           int  minY = bounds.y;
106    
107           sprite.getCollisionBounds ( collisionBounds );
108    
109           int  maxX = bounds.x + bounds.width  - collisionBounds.width;
110    
111           int  maxY = bounds.y + bounds.height - collisionBounds.height;
112    
113           boolean  headingAlreadyAdjusted = false;
114    
115           if ( x < minX )
116           {
117             x = minX;
118    
119             if ( delta_x < 0.0 )
120             {
121               if ( heading > Math.PI )
122               {
123                 heading = 3.0 * Math.PI - heading;
124               }
125               else
126               {
127                 heading = Math.PI - heading;
128               }
129    
130               headingAlreadyAdjusted = true;
131             }
132           }
133           else if ( x > maxX )
134           {
135             x = maxX;
136    
137             if ( delta_x > 0.0 )
138             {
139               if ( heading < Math.PI )
140               {
141                 heading = Math.PI - heading;
142               }
143               else
144               {
145                 heading = 3.0 * Math.PI - heading;
146               }
147    
148               headingAlreadyAdjusted = true;
149             }
150           }
151    
152           if ( y < minY )
153           {
154             y = minY;
155    
156             if ( delta_y < 0.0 )
157             {
158               if ( !headingAlreadyAdjusted )
159               {
160                 heading = 2.0 * Math.PI - heading;
161               }
162             }
163           }
164           else if ( y > maxY )
165           {
166             y = maxY;
167    
168             if ( delta_y > 0.0 )
169             {
170               if ( !headingAlreadyAdjusted )
171               {
172                 heading = 2.0 * Math.PI - heading;
173               }
174             }
175           }
176    
177           sprite.getPaintBounds ( oldPaintBounds );
178    
179           sprite.setX ( x );
180    
181           sprite.setY ( y );
182    
183           sprite.setHeading ( heading );
184    
185           sprite.getPaintBounds ( newPaintBounds );
186    
187           oldPaintBounds.add ( newPaintBounds );
188    
189           component.repaint ( oldPaintBounds );
190         }
191    
192         //////////////////////////////////////////////////////////////////////
193         //////////////////////////////////////////////////////////////////////
194         }