Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Wow! Thanks for the pointer! This is almost /exactly/ what I was hoping for! 

Note in the space invaders example, maybe something in the latest versions of Dr Racket isn't playing well with the compiler, but it won't allow you to use things like "<=" or ">" in an n-ary way, that is, with multiple arguments, e.g. "(<= 40 x (+ base.x 99))". You have to break the expressions up into something like "(or (<= 40 x) (<= x (+ base.x 99)))". Once I fixed that sort of thing in the Space Invaders example it launched and ran perfectly in the browser.

Urlang is pretty nice! There's no format function but most other things work the way I expect them to, and the interface with JavaScript libraries is pretty easy to get along with. This is an implementation of a game loop from a JavaScript game tutorial page and it was pretty straightforward:

#lang at-exp racket
; Implementation of browser game loop from this tutorial:
; https://spicyyoghurt.com/tutorials/html5-javascript-game-development/create-a-pr...
(require urlang urlang/for urlang/extra syntax/parse syntax/stx racket/syntax)
(current-urlang-run?                           #f) ; run using Node?              No: use browser
(current-urlang-echo?                          #t) ; print generated JavaScript?  Yes
(current-urlang-console.log-module-level-expr? #t) ; print top-level expression?  Yes (see console)
(current-urlang-beautify?                      #t) ; invoke js-beautify
(urlang
 (urmodule game-test
   (import alert console this Math isFinite Object window document Date)
   (define context #f) ; Needs to be "global".
   (define timestamp-old #f)
   
   (define (init)
     (let* ((canvas (document.getElementById "the-canvas")))
       (:= context (canvas.getContext "2d")))
     (window.requestAnimationFrame game-loop))
   
   (define (game-loop timestamp)
     (let* ((seconds-passed  (/ (- timestamp timestamp-old) 1000))
            (fps             (Math.round (/ 1.0 seconds-passed)))
            )
       (:= timestamp-old timestamp)
       (:= context "fillStyle" "#fff")
       (context.fillRect  0 0  200 100)
       (:= context "font" "25px Arial")
       (:= context "fillStyle" "black")
       (context.fillText (+ "FPS: " fps) 10 50))
           
     (draw)
     (window.requestAnimationFrame game-loop))
   
   (define (draw)
     (:= context "fillStyle" (if (< 0.5 (Math.random)) "#ff8080" "#0099b0"))
     (context.fillRect  0 100  256 256))
   (init)
))
(define (generate-html)
  @~a{
 <!DOCTYPE html>
 <html lang="en">
   <head> <meta charset="utf-8">
          <title>Game Test</title>
  </head>
  <body>   
     <h1>Game Test</h1>
     <p>Instructions could go here...</p>
     <p><canvas id="the-canvas" width="640" height="480" tabindex="1"/></p>
     <script>@file->string{game-test.js}</script>
 </body>
 </html>})
(require net/sendurl)
(send-url/contents (generate-html))

The "Invaders" example has a Big-Bang style game loop, but I had already started trying to implement this with Javathcript and figured I'd carry it on here.