summaryrefslogtreecommitdiff
path: root/lisparuga
diff options
context:
space:
mode:
Diffstat (limited to 'lisparuga')
-rw-r--r--lisparuga/enemy.scm12
-rw-r--r--lisparuga/game.scm184
-rw-r--r--lisparuga/node.scm5
-rw-r--r--lisparuga/player.scm45
4 files changed, 161 insertions, 85 deletions
diff --git a/lisparuga/enemy.scm b/lisparuga/enemy.scm
index aa5335e..06533ea 100644
--- a/lisparuga/enemy.scm
+++ b/lisparuga/enemy.scm
@@ -49,6 +49,7 @@
;;;
(define-asset explosion-sound (load-audio (scope-asset "sounds/explosion.wav")))
+(define-asset hit-sound (load-audio (scope-asset "sounds/hit.wav")))
(define-class <enemy> (<actor>)
(health #:accessor health #:init-keyword #:health)
@@ -56,15 +57,14 @@
(parting-shots #:getter parting-shots #:init-keyword #:parting-shots)
(fire-parting-shots? #:accessor fire-parting-shots? #:init-form #f))
-(define-method (on-kill (enemy <enemy>))
- #t)
-
(define-method (damage (enemy <enemy>) x)
(let ((new-health (max (- (health enemy) x) 0)))
(set! (health enemy) new-health)
- (when (zero? new-health)
- (audio-play (asset-ref explosion-sound)
- #:volume 0.5))))
+ (if (zero? new-health)
+ (audio-play (asset-ref explosion-sound)
+ #:volume 0.5)
+ (audio-play (asset-ref hit-sound)
+ #:volume 0.5))))
(define-method (dead? (enemy <enemy>))
(zero? (health enemy)))
diff --git a/lisparuga/game.scm b/lisparuga/game.scm
index 9e79898..f5b3082 100644
--- a/lisparuga/game.scm
+++ b/lisparuga/game.scm
@@ -23,6 +23,7 @@
(define-module (lisparuga game)
#:use-module (chickadee)
+ #:use-module (chickadee math)
#:use-module (chickadee math rect)
#:use-module (chickadee math vector)
#:use-module (chickadee render color)
@@ -62,7 +63,16 @@
;; scrolling background
(define-class <game> (<canvas>)
(player-control? #:accessor player-control? #:init-value #f)
- (complete? #:accessor complete? #:init-value #f))
+ (complete? #:accessor complete? #:init-value #f)
+ (skip-tutorial? #:accessor skip-tutorial? #:init-value #f))
+
+(define-method (reset (game <game>))
+ (set! (player-control? game) #f)
+ (set! (complete? game) #f)
+ (reset (& game player))
+ (for-each detach (children (& game enemies)))
+ (let ((battle-report (& game battle-report)))
+ (and battle-report (detach battle-report))))
(define-method (initialize (game <game>) initargs)
(next-method)
@@ -81,6 +91,7 @@
#:rank 2
#:capacity 500
#:texture-atlas player-bullet-atlas))
+ (player (make-player player-bullets))
(enemy-bullets (make <bullet-field>
#:name 'enemy-bullets
#:rank 5
@@ -98,11 +109,13 @@
(ui (make <node-2d>
#:name 'ui
#:rank 999)))
+ (set! (rank player) 1)
(attach-to game
(make <sprite>
#:name 'clouds
#:rank 0
#:texture clouds)
+ player
player-bullets
(make <node-2d>
#:name 'enemies
@@ -128,26 +141,11 @@
#:align 'right)
(make <label>
#:name 'lives
- #:position (vec2 2.0 2.0)))
- (start-stage game)))
+ #:position (vec2 2.0 2.0)))))
(define-method (start-stage (game <game>))
- (let ((player (make-player (& game player-bullets))))
- (set! (rank player) 1)
- (attach-to game player)
- (update-ui game)
- (play-stage-1 game)))
-
-(define-method (spawn-enemies (game <game>))
- ;; Test enemies
- (spawn-enemy game (make-utatsugumi 'white 10.0 180.0))
- (spawn-enemy game (make-utatsugumi 'white 30.0 180.0))
- (spawn-enemy game (make-utatsugumi 'white 50.0 180.0))
- (spawn-enemy game (make-utatsugumi 'black 70.0 180.0))
- (spawn-enemy game (make-utatsugumi 'black 90.0 180.0))
- (spawn-enemy game (make-utatsugumi 'black 110.0 180.0))
- (spawn-enemy game (make-utatsugumi 'white 130.0 180.0))
- (spawn-enemy game (make-utatsugumi 'white 150.0 180.0)))
+ (update-ui game)
+ (play-stage-1 game))
(define-method (update-ui (game <game>))
(set! (text (& game ui score))
@@ -178,26 +176,25 @@
(define-method (update (game <game>) dt)
(let ((refresh-ui? #f)
(player (& game player)))
- (when player
- ;; enemy -> player bullet collision
- ;; enemy -> player collision
- (for-each (lambda (enemy)
- (cond
- ((and (collide (& game player-bullets) enemy)
- (dead? enemy))
- (on-kill player enemy)
- (fire-parting-shots-maybe enemy player)
- (explode game enemy)
- (detach enemy)
- (set! refresh-ui? #t))
- ((collide player enemy)
- (set! refresh-ui? #t))))
- (children (& game enemies)))
- ;; player -> enemy bullet collision
- (when (collide (& game enemy-bullets) (& game player))
- (set! refresh-ui? #t))
- (when refresh-ui?
- (update-ui game)))
+ ;; enemy -> player bullet collision
+ ;; enemy -> player collision
+ (for-each (lambda (enemy)
+ (cond
+ ((and (collide (& game player-bullets) enemy)
+ (dead? enemy))
+ (on-kill player enemy)
+ (fire-parting-shots-maybe enemy player)
+ (explode game enemy)
+ (detach enemy)
+ (set! refresh-ui? #t))
+ ((collide player enemy)
+ (set! refresh-ui? #t))))
+ (children (& game enemies)))
+ ;; player -> enemy bullet collision
+ (when (collide (& game enemy-bullets) (& game player))
+ (set! refresh-ui? #t))
+ (when refresh-ui?
+ (update-ui game))
(next-method)))
(define-method (spawn-enemy (game <game>) enemy)
@@ -226,8 +223,7 @@
(update-ui game)))
(define-method (game-over? (game <game>))
- (let ((player (& game player)))
- (and player (dead? player))))
+ (dead? (& game player)))
(define-method (play-stage-1 game)
(run-script game
@@ -244,8 +240,6 @@
(set! (player-control? game) #t)
(show (& game ui)))
-(define *skip-tutorial?* #t)
-
(define-method (do-tutorial (game <game>))
(define* (instruct text continue? #:optional (post-delay 60))
(let ((instructions (make <label>
@@ -259,7 +253,7 @@
(sleep post-delay)
(detach instructions)
(sleep 60)))
- (unless *skip-tutorial?*
+ (unless (skip-tutorial? game)
(sleep 30)
(instruct "use arrow keys to move"
(let ((v (velocity (& game player))))
@@ -269,7 +263,7 @@
(instruct "press Z to shoot"
(lambda ()
(shooting? (& game player))))
- (instruct "press X to change color"
+ (instruct "press X to change energy"
(let ((starting-polarity (polarity (& game player))))
(lambda ()
(not (eq? (polarity (& game player)) starting-polarity)))))
@@ -280,28 +274,72 @@
(instruct "press C to release energy"
(lambda ()
(zero? (energy (& game player)))))
- (instruct "get ready!" (const #t) 120)))
+ (instruct "shoot opposite energy" (const #t) 90)
+ (instruct "deal 2x damage" (const #t) 90)
+ (set! (invincible? (& game player)) #t)
+ (spawn-enemy game (make-utatsugumi 'white 48.0 150.0))
+ (spawn-enemy game (make-utatsugumi 'white 80.0 150.0))
+ (spawn-enemy game (make-utatsugumi 'white 112.0 150.0))
+ (instruct "destroy 3 of same energy"
+ (lambda ()
+ (null? (children (& game enemies)))))
+ (spawn-enemy game (make-utatsugumi 'black 48.0 150.0))
+ (spawn-enemy game (make-utatsugumi 'black 80.0 150.0))
+ (spawn-enemy game (make-utatsugumi 'black 112.0 150.0))
+ (instruct "repeat for chain bonus"
+ (lambda ()
+ (null? (children (& game enemies)))))
+ (set! (score (& game player)) 0)
+ (set! (chain (& game player)) 0)
+ (set! (chain-progress (& game player)) '())
+ (set! (max-chain (& game player)) 0)
+ (set! (energy (& game player)) 0)
+ (set! (invincible? (& game player)) #f)
+ (update-ui game)
+ (instruct "get ready!" (const #t) 120)
+ (set! (skip-tutorial? game) #t)))
(define-method (do-phase-1 (game <game>))
- (define (utatsugumi-sweep x polarity)
- (let loop ((i 0))
- (when (< i 6)
- (let ((utatsugumi (make-utatsugumi polarity x 260.0)))
- (spawn-enemy game utatsugumi)
- (set-vec2! (velocity utatsugumi) 0.0 -3.0)
- (script
- (sleep (* 10 60))
- (detach utatsugumi))
- (sleep 10))
- (loop (+ i 1)))))
- (utatsugumi-sweep 140.0 'white)
- (sleep 60)
- (utatsugumi-sweep 20.0 'black)
- (sleep 60)
- (utatsugumi-sweep 140.0 'white)
- (sleep 60)
- (utatsugumi-sweep 20.0 'black)
- (sleep (* 3 60)))
+ (define (utatsugumi-sweep x dir polarity)
+ (let ((speed 3.0))
+ (let loop ((i 0))
+ (when (< i 6)
+ (let ((utatsugumi (make-utatsugumi polarity x 260.0)))
+ (spawn-enemy game utatsugumi)
+ (set-vec2! (velocity utatsugumi)
+ (* (cos (* pi 1.5)) speed)
+ (* (sin (* pi 1.5)) speed))
+ (script
+ (sleep 5)
+ (let loop ((i 0))
+ (when (< i 25)
+ (let ((theta (+ (* pi 1.5)
+ (* dir i (/ (* pi .5) 25.0)))))
+ (set-vec2! (velocity utatsugumi)
+ (* (cos theta) speed)
+ (* (sin theta) speed))
+ (sleep 3)
+ (loop (+ i 1)))))
+ (sleep 60)
+ (detach utatsugumi))
+ (sleep 15))
+ (loop (+ i 1))))))
+ (utatsugumi-sweep 140.0 -1.0 'white)
+ (sleep 15)
+ (utatsugumi-sweep 20.0 1.0 'black)
+ (sleep 15)
+ (utatsugumi-sweep 140.0 -1.0 'white)
+ (sleep 15)
+ (utatsugumi-sweep 20.0 1.0 'black)
+ (sleep 15)
+ (utatsugumi-sweep 140.0 -1.0 'white)
+ (sleep 15)
+ (utatsugumi-sweep 20.0 1.0 'black)
+ (sleep 15)
+ (utatsugumi-sweep 140.0 -1.0 'white)
+ (sleep 15)
+ (utatsugumi-sweep 20.0 1.0 'black)
+ (sleep 60))
(define-method (do-win (game <game>))
(set! (player-control? game) #f)
@@ -331,21 +369,29 @@
(lambda (c)
(set! (color backdrop) c))
#:interpolate color-lerp))
+ (sleep 30)
+ (attach-to battle-report
+ (make <label>
+ #:rank 999
+ #:text "STAGE CLEAR!"
+ #:align 'center
+ #:position (vec2 80.0 190.0)))
+ (sleep 30)
(attach-to battle-report
(make <label>
#:rank 999
#:text "BATTLE REPORT"
#:align 'center
- #:position (vec2 80.0 180.0)))
+ #:position (vec2 80.0 145.0)))
(sleep 30)
- (add-row 140.0 "SCORE" (number->string (score (& game player))))
+ (add-row 120.0 "SCORE" (number->string (score (& game player))))
(sleep 30)
- (add-row 110.0 "MAX CHAIN" (number->string (max-chain (& game player))))
+ (add-row 100.0 "MAX CHAIN" (number->string (max-chain (& game player))))
(sleep 30)
(attach-to battle-report
(make <label>
#:rank 999
#:text "press ENTER to play again"
- #:position (vec2 80.0 60.0)
+ #:position (vec2 80.0 40.0)
#:align 'center))
(set! (complete? game) #t)))
diff --git a/lisparuga/node.scm b/lisparuga/node.scm
index 2dbbd41..0939336 100644
--- a/lisparuga/node.scm
+++ b/lisparuga/node.scm
@@ -168,8 +168,9 @@ represented as a ratio in the range [0, 1]."
;; First time activating? We must boot!
(unless (booted? node) (boot node))
(set! (active? node) #t)
- (on-enter node)
- (for-each-child activate node))
+ (for-each-child activate node)
+ ;; Activate all children, recursively, before calling on-enter hook.
+ (on-enter node))
(define-method (deactivate (node <node>))
"Mark NODE and all of its children as inactive."
diff --git a/lisparuga/player.scm b/lisparuga/player.scm
index 1265756..6a85cc4 100644
--- a/lisparuga/player.scm
+++ b/lisparuga/player.scm
@@ -54,12 +54,15 @@
fire-homing-missiles
kill-maybe
on-kill
- add-energy))
+ add-energy
+ reset))
(define-asset ship-atlas (load-tile-atlas (scope-asset "images/player.png") 24 24))
(define-asset shoot-sound (load-audio (scope-asset "sounds/player-shoot.wav")))
(define-asset missile-sound (load-audio (scope-asset "sounds/player-missile.wav")))
(define-asset death-sound (load-audio (scope-asset "sounds/player-death.wav")))
+(define-asset energy-max-sound (load-audio (scope-asset "sounds/energy-max.wav")))
+(define-asset max-chain-sound (load-audio (scope-asset "sounds/max-chain.wav")))
(define kill-hitbox (make-hitbox 'kill (make-rect -2.0 -2.0 4.0 4.0)))
(define graze-hitbox (make-hitbox 'graze (make-rect -12.0 -12.0 24.0 24.0)))
@@ -76,6 +79,20 @@
(shooting? #:accessor shooting? #:init-value #f)
(shoot-time #:accessor shoot-time #:init-value 0))
+(define-method (reset (player <player>))
+ (set! (polarity player) 'white)
+ (set-vec2! (velocity player) 0.0 0.0)
+ (set! (score player) 0)
+ (set! (lives player) 3)
+ (set! (energy player) 0)
+ (set! (chain player) 0)
+ (set! (chain-progress player) '())
+ (set! (max-chain player) 0)
+ (set! (invincible? player) #f)
+ (set! (shooting? player) #f)
+ (set! (shoot-time player) 0)
+ (refresh-sprite player))
+
(define-method (dead? (player <player>))
(zero? (lives player)))
@@ -95,7 +112,7 @@
#:index 0
#:origin (vec2 12.0 12.0))))
-(define (shoot player ox)
+(define-method (shoot (player <player>) ox)
(let ((speed 8.0)
(pos (position player))
(bullets (bullet-field player))
@@ -151,12 +168,16 @@
(vec2-mult! v (speed player))))
(define-method (start-shooting (player <player>))
- (set! (shooting? player) #t)
- (set! (shoot-time player) 0))
+ (unless (shooting? player)
+ (set! (shooting? player) #t)
+ (set! (shoot-time player) 0)))
(define-method (stop-shooting (player <player>))
(set! (shooting? player) #f))
+(define-method (refresh-sprite (player <player>))
+ (set! (index (& player ship)) (if (eq? (polarity player) 'white) 0 4)))
+
(define-method (toggle-polarity (player <player>))
(let ((old (polarity player)))
;; If polarity is none it means we are already switching so ignore
@@ -168,8 +189,7 @@
(set! (polarity player) 'none)
(sleep 7)
(set! (polarity player) (if (eq? old 'white) 'black 'white))
- ;; Change sprite
- (set! (index (& player ship)) (if (eq? old 'white) 4 0))))))
+ (refresh-sprite player)))))
(define-method (fire-homing-missiles (player <player>) enemies)
(let* ((e (energy player))
@@ -247,7 +267,12 @@
#t))
(define-method (add-energy (player <player>) n)
- (set! (energy player) (min (+ (energy player) n) 120)))
+ (let* ((old-energy (energy player))
+ (new-energy (min (+ old-energy n) 120)))
+ (set! (energy player) new-energy)
+ (when (and (not (= old-energy new-energy))
+ (= new-energy 120))
+ (audio-play (asset-ref energy-max-sound)))))
(define-method (kill-maybe (player <player>))
(unless (invincible? player)
@@ -255,6 +280,8 @@
(let ((new-lives (max (- (lives player) 1) 0)))
(set! (lives player) new-lives)
(set! (energy player) 0)
+ (set! (chain-progress player) '())
+ (set! (chain player) 0)
(if (zero? new-lives)
(begin
;; to stop the death events from happening over and over
@@ -317,7 +344,9 @@
;; - 7 Chain --- 6,400 points
;; - 8 Chain --- 12,800 points
;; - 9+ Chain -- 25,600 points
- (* (expt 2 (- (min new-chain 9) 1)) 100)))))
+ (* (expt 2 (- (min new-chain 9) 1)) 100)))
+ (when (>= new-chain 9)
+ (audio-play (asset-ref max-chain-sound)))))
;; 1st or 2nd kill of the chain.
((or ('white) ('black) ('white 'white) ('black 'black))
(set! (chain-progress player) current-chain))