aboutsummaryrefslogtreecommitdiff
path: root/demo/shmup.scm
diff options
context:
space:
mode:
authorGene Pasquet <dev@etenil.net>2026-04-05 19:47:05 +0100
committerGene Pasquet <dev@etenil.net>2026-04-05 19:47:05 +0100
commit027053b11a3a5d861ed2fa2db245388bd95ac246 (patch)
tree84dfd90642bb6d8eb4e0e3fa3a9d651ba29b41e8 /demo/shmup.scm
parent927f37639a3d5a0d881a5c8709f2cf577aadb15e (diff)
Progress
Diffstat (limited to 'demo/shmup.scm')
-rw-r--r--demo/shmup.scm133
1 files changed, 133 insertions, 0 deletions
diff --git a/demo/shmup.scm b/demo/shmup.scm
new file mode 100644
index 0000000..ae7748d
--- /dev/null
+++ b/demo/shmup.scm
@@ -0,0 +1,133 @@
+(import scheme
+ (chicken base)
+ (chicken random)
+ (only srfi-1 filter)
+ (prefix sdl2 "sdl2:")
+ (prefix sdl2-ttf "ttf:")
+ (prefix sdl2-image "img:")
+ downstroke/engine
+ downstroke/world
+ downstroke/physics
+ downstroke/input
+ downstroke/entity
+ downstroke/assets
+ downstroke/sound)
+
+(define *frame-count* 0)
+
+(define (make-bullet px py)
+ (list #:type 'bullet #:x px #:y py #:width 4 #:height 8 #:vx 0 #:vy -6))
+
+(define (make-enemy rx)
+ (list #:type 'enemy #:x rx #:y 0 #:width 16 #:height 16 #:vx 0 #:vy 2))
+
+(define (make-player)
+ (list #:type 'player #:x 280 #:y 360 #:width 16 #:height 16 #:vx 0 #:vy 0))
+
+(define (entities-overlap? a b)
+ (aabb-overlap?
+ (entity-ref a #:x 0) (entity-ref a #:y 0)
+ (entity-ref a #:width 0) (entity-ref a #:height 0)
+ (entity-ref b #:x 0) (entity-ref b #:y 0)
+ (entity-ref b #:width 0) (entity-ref b #:height 0)))
+
+(define (find-dead entities)
+ (let ((bullets (filter (lambda (e) (eq? (entity-ref e #:type) 'bullet)) entities))
+ (enemies (filter (lambda (e) (eq? (entity-ref e #:type) 'enemy)) entities))
+ (dead '()))
+ (for-each
+ (lambda (b)
+ (for-each
+ (lambda (en)
+ (when (entities-overlap? b en)
+ (set! dead (cons b (cons en dead)))))
+ enemies))
+ bullets)
+ dead))
+
+(define *game*
+ (make-game
+ title: "Demo: Shoot-em-up" width: 600 height: 400
+
+ preload: (lambda (game)
+ (init-audio!)
+ (load-sounds! '((shoot . "demo/assets/jump.wav"))))
+
+ create: (lambda (game)
+ (game-scene-set! game
+ (make-scene
+ entities: (list (make-player))
+ tilemap: #f
+ camera: (make-camera x: 0 y: 0)
+ tileset-texture: #f)))
+
+ update: (lambda (game dt)
+ (let* ((input (game-input game))
+ (scene (game-scene game))
+ (entities (scene-entities scene))
+ (player (car (filter (lambda (e) (eq? (entity-ref e #:type) 'player))
+ entities))))
+ (set! *frame-count* (+ *frame-count* 1))
+ ;; Move player
+ (let* ((player (entity-set player #:vx
+ (cond ((input-held? input 'left) -4)
+ ((input-held? input 'right) 4)
+ (else 0))))
+ (player (apply-velocity-x player))
+ (player (entity-set player #:x
+ (max 0 (min 584 (entity-ref player #:x 0))))))
+ ;; Fire bullet
+ (when (input-pressed? input 'a)
+ (play-sound 'shoot)
+ (scene-add-entity scene
+ (make-bullet (+ (entity-ref player #:x 0) 6) 340)))
+ ;; Spawn enemy every 60 frames
+ (when (zero? (modulo *frame-count* 60))
+ (scene-add-entity scene
+ (make-enemy (+ 20 (* (pseudo-random-integer 28) 20)))))
+ ;; Update player in scene
+ (scene-entities-set! scene
+ (cons player
+ (filter (lambda (e) (not (eq? (entity-ref e #:type) 'player)))
+ (scene-entities scene)))))
+ ;; Move non-player entities
+ (scene-update-entities scene
+ (lambda (e)
+ (if (eq? (entity-ref e #:type) 'player)
+ e
+ (entity-set
+ (entity-set e #:x (+ (entity-ref e #:x 0) (entity-ref e #:vx 0)))
+ #:y (+ (entity-ref e #:y 0) (entity-ref e #:vy 0))))))
+ ;; Remove collisions
+ (let ((dead (find-dead (scene-entities scene))))
+ (scene-filter-entities scene
+ (lambda (e) (not (memq e dead)))))
+ ;; Remove out-of-bounds
+ (scene-filter-entities scene
+ (lambda (e)
+ (let ((y (entity-ref e #:y 0)))
+ (or (eq? (entity-ref e #:type) 'player)
+ (and (> y -20) (< y 420))))))))
+
+ render: (lambda (game)
+ (let* ((renderer (game-renderer game))
+ (scene (game-scene game))
+ (entities (scene-entities scene)))
+ (for-each
+ (lambda (e)
+ (let ((type (entity-ref e #:type 'unknown))
+ (x (inexact->exact (floor (entity-ref e #:x 0))))
+ (y (inexact->exact (floor (entity-ref e #:y 0))))
+ (w (entity-ref e #:width 16))
+ (h (entity-ref e #:height 16)))
+ (set! (sdl2:render-draw-color renderer)
+ (case type
+ ((player) (sdl2:make-color 255 255 255 255))
+ ((bullet) (sdl2:make-color 255 255 0 255))
+ ((enemy) (sdl2:make-color 255 50 50 255))
+ (else (sdl2:make-color 100 100 100 255))))
+ (sdl2:render-fill-rect! renderer
+ (sdl2:make-rect x y w h))))
+ entities)))))
+
+(game-run! *game*)