1010
1111namespace BlazorExperiments . UI . Pages ;
1212
13- public partial class NeonSnake {
13+ public partial class NeonSnake : IAsyncDisposable {
1414 const int KeyUp = 38 ;
1515 const int KeyDown = 40 ;
1616 const int KeyLeft = 37 ;
@@ -39,6 +39,7 @@ public partial class NeonSnake {
3939 string _scoreText = "Score: 0" ;
4040 string _bestText = "Best: 0" ;
4141 bool _hudDirty = true ;
42+ bool _loopInProgress = false ;
4243 const string BestScoreKey = "neonSnakeBestScore" ;
4344
4445 public async Task InitializeAsync ( ) {
@@ -72,9 +73,11 @@ public async Task InitializeAsync() {
7273 }
7374
7475 private async ValueTask LoopAsync ( ElapsedEventArgs elapsedEvent ) {
76+ if ( _loopInProgress ) return ;
77+
78+ _loopInProgress = true ;
7579 var now = elapsedEvent . SignalTime ;
7680 var dt = ( now - _lastTick ) . TotalMilliseconds ;
77- if ( dt < 16.67 ) return ;
7881 _lastTick = now ;
7982
8083 var scoreBefore = _snake . Score ;
@@ -89,6 +92,7 @@ private async ValueTask LoopAsync(ElapsedEventArgs elapsedEvent) {
8992 if ( _snake . Score > scoreBefore ) await PlaySoundAsync ( "neonSnakeAudio.playEatSound" ) ;
9093 if ( _snake . Health < healthBefore ) await PlaySoundAsync ( "neonSnakeAudio.playHitSound" ) ;
9194 if ( ! deadBefore && _snake . Dead ) {
95+ await PlaySoundAsync ( "neonSnakeAudio.stopMusic" ) ;
9296 await PlaySoundAsync ( "neonSnakeAudio.playDeathSound" ) ;
9397 await JS . InvokeVoidAsync ( "localStorage.setItem" , BestScoreKey , _snake . BestScore ) ;
9498 }
@@ -101,6 +105,7 @@ private async ValueTask LoopAsync(ElapsedEventArgs elapsedEvent) {
101105
102106 await using var batch = _canvas . Context . CreateBatch ( ) ;
103107 await DrawAsync ( batch ) ;
108+ _loopInProgress = false ;
104109 }
105110
106111 async ValueTask PlaySoundAsync ( string fn ) {
@@ -622,7 +627,8 @@ async ValueTask DrawMonstersAsync(Batch2D ctx) {
622627 await ctx . ArcAsync ( ex , ey , eyeR * 0.52 , 0 , DoublePI ) ;
623628 await ctx . FillAsync ( FillRule . NonZero ) ;
624629 }
625- } else {
630+ }
631+ else {
626632 // Sleeping: closed-eye lines
627633 await ctx . StrokeStyleAsync ( "rgba(180,140,255,0.7)" ) ;
628634 await ctx . LineWidthAsync ( 2 ) ;
@@ -855,14 +861,19 @@ await ctx.FillStyleAsync(0, NeonSnakeGame.Snake.HudH, 0, _screenH,
855861 await ctx . TextAlignAsync ( TextAlign . Start ) ;
856862 }
857863
864+ async ValueTask RestartGame ( ) {
865+ _snake = new NeonSnakeGame . Snake ( _cellSize , _canvas . CellsPerRow , _visibleRows ) ;
866+ _hudDirty = true ;
867+ _lastTick = DateTime . UtcNow ;
868+ _ = PlaySoundAsync ( "neonSnakeAudio.startMusic" ) ;
869+ }
870+
858871 #region Input Handling
859872 void HandleInput ( KeyboardEventArgs e ) {
860873 if ( _snake is null ) return ;
861874
862875 if ( _snake . ShowDeathScreen && ( e . Code == "Space" || e . Key == " " || e . Key == "Spacebar" ) ) {
863- _snake = new NeonSnakeGame . Snake ( _cellSize , _canvas . CellsPerRow , _visibleRows ) ;
864- _hudDirty = true ;
865- _lastTick = DateTime . UtcNow ;
876+ _ = RestartGame ( ) ;
866877 return ;
867878 }
868879
@@ -887,9 +898,7 @@ void HandleInput(KeyboardEventArgs e) {
887898
888899 void HandleTouchStart ( TouchEventArgs e ) {
889900 if ( _snake . ShowDeathScreen ) {
890- _snake = new NeonSnakeGame . Snake ( _cellSize , _canvas . CellsPerRow , _visibleRows ) ;
891- _hudDirty = true ;
892- _lastTick = DateTime . UtcNow ;
901+ _ = RestartGame ( ) ;
893902 return ;
894903 }
895904
@@ -918,4 +927,8 @@ void HandleTouchMove(TouchEventArgs e) {
918927 _previousTouch = e . Touches [ ^ 1 ] ;
919928 }
920929 #endregion
930+
931+ public async ValueTask DisposeAsync ( ) {
932+ await PlaySoundAsync ( "neonSnakeAudio.dispose" ) ;
933+ }
921934}
0 commit comments