@@ -51,16 +51,18 @@ export default function SuikaGamePage() {
5151 * This earns the player points (score).
5252 */
5353const CHAIN = [
54- { r : 10 , color : 'red' , score : 0 } ,
55- { r : 20 , color : 'orange' , score : 1 } ,
56- { r : 30 , color : 'yellow' , score : 3 } ,
57- { r : 40 , color : 'green' , score : 5 } ,
58- { r : 50 , color : 'blue' , score : 7 } ,
59- { r : 60 , color : 'indigo' , score : 11 } ,
60- { r : 70 , color : 'violet' , score : 20 } ,
61- { r : 80 , color : 'black' , score : 50 } ,
62- { r : 90 , color : 'white' , score : 100 } ,
63- { r : 100 , color : 'gold' , score : 200 } ,
54+ { r : 10 , color : '#ff6b6b' , score : 0 } ,
55+ { r : 20 , color : '#ff8e53' , score : 1 } ,
56+ { r : 30 , color : '#ffbe0b' , score : 3 } ,
57+ { r : 40 , color : '#8ac926' , score : 5 } ,
58+ { r : 50 , color : '#06ffa5' , score : 7 } ,
59+ { r : 60 , color : '#118ab2' , score : 11 } ,
60+ { r : 70 , color : '#7209b7' , score : 20 } ,
61+ { r : 80 , color : '#d90429' , score : 50 } ,
62+ { r : 90 , color : '#ef233c' , score : 100 } ,
63+ { r : 100 , color : '#ffd60a' , score : 200 } ,
64+ { r : 110 , color : '#003566' , score : 500 } ,
65+ { r : 120 , color : '#000814' , score : 1000 } ,
6466]
6567
6668type Entity = {
@@ -107,6 +109,7 @@ function start(signal: AbortSignal, ctx: CanvasRenderingContext2D, setScore: (up
107109 nextId = Math . floor ( Math . random ( ) * max + 1 )
108110 } , { signal } )
109111
112+ const WALL_THICKNESS = 10
110113 const CONTAINER_WIDTH = 700
111114 const CONTAINER_HEIGHT = 1000
112115 const containerX = ctx . canvas . width / devicePixelRatio / 2 - CONTAINER_WIDTH / 2
@@ -119,21 +122,27 @@ function start(signal: AbortSignal, ctx: CanvasRenderingContext2D, setScore: (up
119122 lastTime = time
120123 if ( dt > 1 ) return // skip frame if too much time has passed
121124
122- const steps = Math . floor ( dt / 0.1 )
125+ const steps = 20
123126
124127 for ( let step = 0 ; step < steps ; step ++ ) {
125128 const dti = dt / steps
126129
127130 // Update entities
128131 for ( const entity of entities ) {
129- entity . vy += 0.4 * dti // gravity
132+ entity . vy += 0.7 * dti // gravity
133+
134+ // Apply damping to reduce vibration
135+ const damping = ( 1 - 0.04 * dti )
136+ entity . vx *= damping
137+ entity . vy *= damping
138+
130139 entity . x += entity . vx * dti
131140 entity . y += entity . vy * dti
132141
133142 // floor collision
134- if ( entity . y + entity . r > window . innerHeight ) {
135- entity . y = window . innerHeight - entity . r
136- entity . vy *= - 0.3
143+ if ( entity . y + entity . r > window . innerHeight - WALL_THICKNESS ) {
144+ entity . y = window . innerHeight - WALL_THICKNESS - entity . r
145+ entity . vy *= - 0.5
137146 }
138147
139148 // wall collisions
@@ -197,8 +206,14 @@ function start(signal: AbortSignal, ctx: CanvasRenderingContext2D, setScore: (up
197206
198207 // Collision detected - separate entities
199208 const overlap = minDist - dist
200- const separationX = ( dx / dist ) * overlap * 0.5
201- const separationY = ( dy / dist ) * overlap * 0.5
209+
210+ // Allow small overlap (slop) to prevent micro-corrections
211+ const slop = 0.5
212+ if ( overlap < slop ) continue
213+
214+ const correctedOverlap = overlap - slop
215+ const separationX = ( dx / dist ) * correctedOverlap * 0.5
216+ const separationY = ( dy / dist ) * correctedOverlap * 0.5
202217
203218 a . x += separationX
204219 a . y += separationY
@@ -229,10 +244,10 @@ function start(signal: AbortSignal, ctx: CanvasRenderingContext2D, setScore: (up
229244 ctx . clearRect ( 0 , 0 , window . innerWidth , window . innerHeight )
230245
231246 // Draw walls
232- ctx . fillStyle = 'black '
233- ctx . fillRect ( containerX - 10 , containerY - 10 , 10 , CONTAINER_HEIGHT + 20 ) // left
234- ctx . fillRect ( containerX + CONTAINER_WIDTH , containerY - 10 , 10 , CONTAINER_HEIGHT + 20 ) // right
235- ctx . fillRect ( containerX - 10 , containerY + CONTAINER_HEIGHT , CONTAINER_WIDTH + 20 , 10 ) // bottom
247+ ctx . fillStyle = 'white '
248+ ctx . fillRect ( containerX - WALL_THICKNESS , containerY - WALL_THICKNESS , WALL_THICKNESS , CONTAINER_HEIGHT + WALL_THICKNESS * 2 ) // left
249+ ctx . fillRect ( containerX + CONTAINER_WIDTH , containerY - WALL_THICKNESS , WALL_THICKNESS , CONTAINER_HEIGHT + WALL_THICKNESS * 2 ) // right
250+ ctx . fillRect ( containerX - WALL_THICKNESS , innerHeight - WALL_THICKNESS , CONTAINER_WIDTH + WALL_THICKNESS * 2 , WALL_THICKNESS ) // bottom
236251
237252 // Draw hand
238253 {
@@ -250,7 +265,7 @@ function start(signal: AbortSignal, ctx: CanvasRenderingContext2D, setScore: (up
250265 ctx . fillStyle = base . color
251266 ctx . globalAlpha = 0.5
252267 ctx . beginPath ( )
253- ctx . arc ( window . innerWidth - 50 , 50 , base . r , 0 , Math . PI * 2 )
268+ ctx . arc ( containerX + CONTAINER_WIDTH + WALL_THICKNESS + 10 + base . r , base . r + 10 , base . r , 0 , Math . PI * 2 )
254269 ctx . fill ( )
255270 ctx . globalAlpha = 1
256271 }
0 commit comments