@@ -69,18 +69,18 @@ module Images =
6969 direction in which Pacman is going. It keeps a mutable state with current step of Pacman's
7070 mouth.
7171 *)
72- let imageAt ( x , y , v ) =
72+ let imageAt ( x : _ ref , y : _ ref , v : _ ref ) =
7373 let p1 , p2 =
74- match ! v with
74+ match v.Value with
7575 | - 1 , 0 -> pl1Img, pl2Img
7676 | 1 , 0 -> pr1Img, pr2Img
7777 | 0 , - 1 -> pu1Img, pu2Img
7878 | 0 , 1 -> pd1Img, pd2Img
79- | _, _ -> ! lastp, ! lastp
80- let x ' = int ( floor( float (! x / 6 )))
81- let y ' = int ( floor( float (! y / 6 )))
79+ | _, _ -> lastp.Value , lastp.Value
80+ let x ' = int ( floor( float ( x.Value / 6 )))
81+ let y ' = int ( floor( float ( y.Value / 6 )))
8282 let p = if ( x' + y') % 2 = 0 then p1 else p2
83- lastp := p
83+ lastp.Value <- p
8484 p
8585
8686module Keyboard =
@@ -93,9 +93,9 @@ module Keyboard =
9393
9494 /// Triggered when key is pressed/released
9595 let update ( e : KeyboardEvent , pressed ) =
96- let keyCode = int e.keyCode
96+ let key = e.key
9797 let op = if pressed then Set.add else Set.remove
98- keysPressed <- op keyCode keysPressed
98+ keysPressed <- op key keysPressed
9999
100100 /// Register DOM event handlers
101101 let init () =
@@ -419,8 +419,8 @@ The following outlines the structure of the function:
419419 let rec update () =
420420 logic ()
421421 render ()
422- if ! dotsLeft = 0 then onLevelCompleted()
423- elif ! energy <= 0 then onGameOver()
422+ if dotsLeft.Value = 0 then onLevelCompleted()
423+ elif energy.Value <= 0 then onGameOver()
424424 else window.setTimeout(update, 1000. / 60.) |> ignore
425425
426426 update()
@@ -457,7 +457,7 @@ let playLevel (onLevelCompleted, onGameOver) =
457457 ### Define the Pacman state
458458 Next, we define the game state. Pacman game uses mutable state, so the following uses
459459 F# reference cells; ` ref 0 ` creates a mutable cell containing ` 0 ` . Later, we will access
460- the value by writing ` ! score` and mutate it by writing ` score := ! score + 1 ` .
460+ the value by writing ` score.Value ` and mutate it by writing ` score.Value <- score.Value + 1 ` .
461461 *)
462462 let pills = maze |> Array.map ( fun line ->
463463 line.ToCharArray() |> Array.map id)
@@ -479,65 +479,65 @@ let playLevel (onLevelCompleted, onGameOver) =
479479 let movePacman () =
480480 // In which directions should pacman go?
481481 let inputs =
482- [| if Keyboard.isPressed 38 (* up *) then
483- yield canGoUp (! x ,! y ), ( 0 ,- 1 )
484- if Keyboard.isPressed 40 (* down *) then
485- yield canGoDown (! x ,! y ), ( 0 , 1 )
486- if Keyboard.isPressed 37 (* left *) then
487- yield canGoLeft (! x ,! y ), (- 1 , 0 )
488- if Keyboard.isPressed 39 (* right *) then
489- yield canGoRight (! x ,! y ), ( 1 , 0 ) |]
482+ [| if Keyboard.isPressed " ArrowUp " then
483+ yield canGoUp ( x.Value , y.Value ), ( 0 ,- 1 )
484+ if Keyboard.isPressed " ArrowDown " then
485+ yield canGoDown ( x.Value , y.Value ), ( 0 , 1 )
486+ if Keyboard.isPressed " ArrowLeft " then
487+ yield canGoLeft ( x.Value , y.Value ), (- 1 , 0 )
488+ if Keyboard.isPressed " ArrowRight " then
489+ yield canGoRight ( x.Value , y.Value ), ( 1 , 0 ) |]
490490 // Can we continue in the same direction?
491491 let canGoForward =
492- match ! v with
493- | 0 ,- 1 -> canGoUp(! x ,! y )
494- | 0 , 1 -> canGoDown(! x ,! y )
495- | - 1 , 0 -> canGoLeft(! x ,! y )
496- | 1 , 0 -> canGoRight(! x ,! y )
492+ match v.Value with
493+ | 0 ,- 1 -> canGoUp( x.Value , y.Value )
494+ | 0 , 1 -> canGoDown( x.Value , y.Value )
495+ | - 1 , 0 -> canGoLeft( x.Value , y.Value )
496+ | 1 , 0 -> canGoRight( x.Value , y.Value )
497497 | _ -> false
498498 // What new directions can we take?
499499 let availableDirections =
500500 inputs
501501 |> Array.filter fst
502502 |> Array.map snd
503- |> Array.sortBy ( fun v' -> v' = ! v )
503+ |> Array.sortBy ( fun v' -> v' = v.Value )
504504 if availableDirections.Length > 0 then
505505 // Choose the first one, prefers no change
506- v := availableDirections.[ 0 ]
506+ v.Value <- availableDirections.[ 0 ]
507507 elif inputs.Length = 0 || not canGoForward then
508508 // There are no options - stop
509- v := 0 , 0
509+ v.Value <- 0 , 0
510510
511511 // Update X and Y accordingly
512- let x ' , y' = wrap (! x ,! y ) ! v
513- x := x'
514- y := y'
512+ let x ' , y' = wrap ( x.Value , y.Value ) v.Value
513+ x.Value <- x'
514+ y.Value <- y'
515515
516516 // Check if Pacman eats a pill at current cell
517517 let eatPills () =
518- let tx = int ( floor( float ((! x + 6 )/ 8 )))
519- let ty = int ( floor( float ((! y + 6 )/ 8 )))
518+ let tx = int ( floor( float (( x.Value + 6 )/ 8 )))
519+ let ty = int ( floor( float (( y.Value + 6 )/ 8 )))
520520 let c = pills.[ ty].[ tx]
521521 if c = '.' then
522522 // Eating a small pill increments the score
523523 pills.[ ty].[ tx] <- ' '
524524 clearCell background ( tx, ty)
525- score := ! score + 10
526- decr dotsLeft
525+ score.Value <- score.Value + 10
526+ dotsLeft.Value <- dotsLeft.Value - 1
527527 Sound.play " Dot5"
528528 if c = 'o' then
529529 // Eating a large pill turns on the power mode
530530 pills.[ ty].[ tx] <- ' '
531531 clearCell background ( tx, ty)
532- bonus := 0
533- score := ! score + 50
534- powerCountdown := 250
535- decr dotsLeft
532+ bonus.Value <- 0
533+ score.Value <- score.Value + 50
534+ powerCountdown.Value <- 250
535+ dotsLeft.Value <- dotsLeft.Value - 1
536536 Sound.play " Powerup"
537537
538538 /// Are there any ghosts that collide with Pacman?
539539 let touchingGhosts () =
540- let px , py = ! x , ! y
540+ let px , py = x.Value , y.Value
541541 ghosts |> Array.filter ( fun ghost ->
542542 let x , y = ghost.X, ghost.Y
543543 (( px >= x && px < x + 13 ) ||
@@ -552,31 +552,31 @@ The `collisionDetection` function implements the right response to collision wit
552552 let collisionDetection () =
553553 let touched = touchingGhosts ()
554554 if touched.Length > 0 then
555- if ! powerCountdown > 0 then
555+ if powerCountdown.Value > 0 then
556556 // Pacman is eating ghosts!
557557 touched |> Array.iter ( fun ghost ->
558558 if not ghost.IsReturning then
559559 Sound.play " EatGhost"
560560 ghost.IsReturning <- true
561- let added = int ( 2. ** ( float ! bonus))
562- score := ! score + added * 200
563- let image = bonusImages.[! bonus]
564- bonuses := ( 100 , ( image, ghost.X, ghost.Y)) :: ! bonuses
565- bonus := min 3 (! bonus + 1 ) )
561+ let added = int ( 2. ** ( float bonus.Value ))
562+ score.Value <- score.Value + added * 200
563+ let image = bonusImages.[ bonus.Value ]
564+ bonuses.Value <- ( 100 , ( image, ghost.X, ghost.Y)) :: bonuses.Value
565+ bonus.Value <- min 3 ( bonus.Value + 1 ) )
566566 else
567567 // Pacman loses energy when hitting ghosts
568- decr energy
569- if ! flashCountdown = 0 then Sound.play " Hurt"
570- flashCountdown := 30
571- if ! flashCountdown > 0 then decr flashCountdown
568+ energy.Value <- energy.Value - 1
569+ if flashCountdown.Value = 0 then Sound.play " Hurt"
570+ flashCountdown.Value <- 30
571+ if flashCountdown.Value > 0 then flashCountdown.Value <- flashCountdown.Value - 1
572572
573573 /// Updates bonus points
574574 let updateBonus () =
575575 let removals , remainders =
576- ! bonuses
576+ bonuses.Value
577577 |> List.map ( fun ( count , x ) -> count-1 , x)
578578 |> List.partition ( fst >> (=) 0 )
579- bonuses := remainders
579+ bonuses.Value <- remainders
580580
581581(**
582582The logic is called from the following single ` logic ` function that includes all the checks:
@@ -585,7 +585,8 @@ The logic is called from the following single `logic` function that includes all
585585 moveGhosts()
586586 movePacman()
587587 eatPills ()
588- if ! powerCountdown > 0 then decr powerCountdown
588+ if powerCountdown.Value > 0 then
589+ powerCountdown.Value <- powerCountdown.Value - 1
589590 collisionDetection()
590591 updateBonus ()
591592
@@ -599,12 +600,12 @@ We start with Pacman and remaining energy:
599600*)
600601 let renderPacman () =
601602 let p = Images.imageAt( x, y, v)
602- if (! flashCountdown >>> 1 ) % 2 = 0
603- then context.drawImage(!^ p, float ! x , float ! y )
603+ if ( flashCountdown.Value >>> 1 ) % 2 = 0
604+ then context.drawImage(!^ p, float x.Value , float y.Value )
604605
605606 let renderEnergy () =
606607 context.fillStyle <- !^ " yellow"
607- context.fillRect( 120. , 250. , float ! energy, 2. )
608+ context.fillRect( 120. , 250. , float energy.Value , 2. )
608609(**
609610The next three functions render ghosts, current score and bonuses:
610611*)
@@ -613,19 +614,19 @@ The next three functions render ghosts, current score and bonuses:
613614 let image =
614615 if ghost.IsReturning then eyed
615616 else
616- if ! powerCountdown = 0 then ghost.Image
617- elif ! powerCountdown > 100 ||
618- ((! powerCountdown >>> 3 ) % 2 ) <> 0 then blue
617+ if powerCountdown.Value = 0 then ghost.Image
618+ elif powerCountdown.Value > 100 ||
619+ (( powerCountdown.Value >>> 3 ) % 2 ) <> 0 then blue
619620 else ghost.Image
620621 context.drawImage(!^ image, float ghost.X, float ghost.Y) )
621622
622623 let renderScore () =
623624 context.fillStyle <- !^ " white"
624625 context.font <- " bold 8px" ;
625- context.fillText( " Score " + (! score) .ToString(), 0. , 255. )
626+ context.fillText( " Score " + ( score.Value ) .ToString(), 0. , 255. )
626627
627628 let renderBonus () =
628- ! bonuses |> List.iter ( fun ( _ ,( image , x , y )) ->
629+ bonuses.Value |> List.iter ( fun ( _ ,( image , x , y )) ->
629630 context.drawImage(!^ image, float x, float y))
630631
631632 let render () =
@@ -639,8 +640,8 @@ The next three functions render ghosts, current score and bonuses:
639640 let rec update () =
640641 logic ()
641642 render ()
642- if ! dotsLeft = 0 then onLevelCompleted()
643- elif ! energy <= 0 then onGameOver()
643+ if dotsLeft.Value = 0 then onLevelCompleted()
644+ elif energy.Value <= 0 then onGameOver()
644645 else window.setTimeout( update, 1000 / 60 ) |> ignore
645646
646647 update()
0 commit comments