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 }