lisp-game-jam/game.scm

212 lines
6.6 KiB
Scheme
Raw Normal View History

2024-04-26 18:30:59 +00:00
;;; Copyright (C) 2024 David Thompson <dave@spritely.institute>
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;; http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.
;;; Commentary:
;;;
;;; Example game showing off several common game programming things.
;;;
;;; Code:
(import (scheme base)
(scheme inexact)
(hoot debug)
(hoot ffi)
(hoot hashtables)
(hoot match)
(dom canvas)
2024-05-22 07:26:50 +00:00
(dom console)
2024-04-26 18:30:59 +00:00
(dom document)
(dom element)
(dom event)
(dom image)
(dom media)
(dom window)
(math)
(math rect)
(math vector)
(ces entity)
(ces system)
2024-05-22 06:28:51 +00:00
(ces system renderer)
(ces system-manager)
(ces entity-manager)
(game-core))
2024-04-26 18:30:59 +00:00
;; Data types
(define-record-type <level>
(make-level state player move-left? move-right? move-up? move-down?)
2024-04-26 18:30:59 +00:00
level?
(state level-state set-level-state!) ; play, win, lose
(player level-player)
2024-04-26 18:30:59 +00:00
(move-left? level-move-left? set-level-move-left!)
(move-right? level-move-right? set-level-move-right!)
(move-up? level-move-up? set-level-move-up!)
(move-down? level-move-down? set-level-move-down!))
(define-record-type <player>
(make-player velocity position hitbox weapon-primary)
entity?
(velocity player-velocity player-velocity-set!)
(position player-position player-position-set!)
(hitbox player-hitbox player-hitbox-set!)
(weapon-primary player-weapon-primary player-weapon-primary-set!))
2024-04-26 18:30:59 +00:00
;; Assets
(define image:player (make-image "assets/images/ball.png"))
2024-04-26 18:30:59 +00:00
;; Game data
(define game-width 640.0)
(define game-height 480.0)
(define player-width 22.0)
(define player-height 22.0)
(define player-speed 6.0)
2024-04-26 18:30:59 +00:00
(define (make-player* x y)
(make-player (vec2 0.0 0.0)
(vec2 x y)
(vec2 player-width player-height)
'test-shot))
2024-04-26 18:30:59 +00:00
(define (make-level-1)
(make-level 'play
2024-05-18 21:31:07 +00:00
(make-player* 0.0 0.0)
#f #f #f #f))
2024-04-26 18:30:59 +00:00
;; Game state
(define *level* (make-level-1))
(define (level-clear? level)
2024-05-18 21:31:07 +00:00
#f)
2024-04-26 18:30:59 +00:00
(define (win! level)
(set-level-state! level 'win))
(define (lose! level)
(set-level-state! level 'lose))
2024-05-18 21:31:07 +00:00
(define (update-player-velocity! level)
(let ((speed (* player-speed
(+ (if (level-move-left? level) -1.0 0.0)
(if (level-move-right? level) 1.0 0.0)
(if (level-move-up? level) 0.0 1.0)
(if (level-move-down? level) 0.0 -1.0)))))
(set-vec2-x! (player-velocity (level-player level)) speed)
(set-vec2-y! (player-velocity (level-player level)) speed)))
2024-04-26 18:30:59 +00:00
(define dt (/ 1000.0 60.0)) ; aim for updating at 60Hz
(define (update)
(match (level-state *level*)
('play
(let* ((player (level-player *level*))
(p-velocity (player-velocity player))
(p-position (player-position player))
(p-hitbox (player-hitbox player)))
;; Move player
(set-vec2-x! p-position (+ (vec2-x p-position) (vec2-x p-velocity)))
(set-vec2-y! p-position (+ (vec2-y p-position) (vec2-y p-velocity)))
;; Keep player within the bounds of the game
2024-04-26 18:30:59 +00:00
(cond
((< (vec2-x p-position) 0.0) ; left wall
(set-vec2-x! p-position 0.0))
((> (vec2-x p-position) game-width) ; right wall
(set-vec2-x! p-position game-width)))
((< (vec2-y p-position) 0.0) ; top wall
(set-vec2-y! p-position 0.0))
((> (vec2-y p-position) game-height) ; bottom wall
(set-vec2-y! p-position game-height))))
2024-04-26 18:30:59 +00:00
(_ #t))
(timeout update-callback dt))
(define update-callback (procedure->external update))
;; Rendering
(define number->string*
(let ((cache (make-eq-hashtable))) ; assuming fixnums only
(lambda (x)
(or (hashtable-ref cache x)
(let ((str (number->string x)))
(hashtable-set! cache x str)
str)))))
(define (draw prev-time)
(let ((player (level-player *level*)))
2024-04-26 18:30:59 +00:00
;; Draw background
(set-fill-color! context "#140c1c")
(fill-rect context 0.0 0.0 game-width game-height)
;; Draw player
2024-04-26 18:30:59 +00:00
(let ((w 22.0)
(h 22.0)
(position (player-position player)))
(draw-image context image:player
2024-04-26 18:30:59 +00:00
0.0 0.0 w h
(vec2-x position) (vec2-y position) w h)))
2024-04-26 18:30:59 +00:00
(request-animation-frame draw-callback))
(define draw-callback (procedure->external draw))
;; Input
(define key:left "ArrowLeft")
(define key:right "ArrowRight")
(define key:up "ArrowUp")
(define key:down "ArrowDown")
2024-04-26 18:30:59 +00:00
(define key:confirm "Enter")
(define (on-key-down event)
(let ((key (keyboard-event-code event)))
(match (level-state *level*)
('play
(cond
((string=? key key:left)
2024-05-18 21:31:07 +00:00
(set-level-move-left! *level* #t)
(update-player-velocity! *level*))
2024-04-26 18:30:59 +00:00
((string=? key key:right)
2024-05-18 21:31:07 +00:00
(set-level-move-right! *level* #t)
(update-player-velocity! *level*))
((string=? key key:up)
2024-05-18 21:31:07 +00:00
(set-level-move-up! *level* #t)
(update-player-velocity! *level*))
((string=? key key:down)
2024-05-18 21:31:07 +00:00
(set-level-move-down! *level* #t)
(update-player-velocity! *level*))))
2024-04-26 18:30:59 +00:00
((or 'win 'lose)
(when (string=? key key:confirm)
(set! *level* (make-level-1)))))))
(define (on-key-up event)
(let ((key (keyboard-event-code event)))
(match (level-state *level*)
('play
(cond
((string=? key key:left)
(set-level-move-left! *level* #f))
2024-04-26 18:30:59 +00:00
((string=? key key:right)
(set-level-move-right! *level* #f))
((string=? key key:up)
(set-level-move-up! *level* #f))
((string=? key key:down)
(set-level-move-down! *level* #f))))
2024-04-26 18:30:59 +00:00
(_ #t))))
;; Canvas and event loop setup
(define canvas (get-element-by-id "canvas"))
(define context (get-context canvas "2d"))
(set-element-width! canvas (exact game-width))
(set-element-height! canvas (exact game-height))
(add-event-listener! (current-document) "keydown"
(procedure->external on-key-down))
(add-event-listener! (current-document) "keyup"
(procedure->external on-key-up))
(request-animation-frame draw-callback)
(timeout update-callback dt)