refactor in model and render domains. Update README
Stuff got ugly so some more refactoring. I want rendering completely independent from the game logic, i.e. so that becomes a pure projection from the state (for some value of pure). Also added the main game idea in the README and added a plan.
This commit is contained in:
parent
525e671d41
commit
8222f5548f
4 changed files with 141 additions and 101 deletions
62
README.md
62
README.md
|
@ -1,11 +1,34 @@
|
||||||
# Chickadee Game Template
|
# Bloatrunner
|
||||||
|
|
||||||
This repository provides a template to use as a starting point for
|
A Lode Runner clone where you have to manage your waistline bloat.
|
||||||
making a new game using
|
|
||||||
[Chickadee](https://dthompson.us/projects/chickadee.html)! It
|
|
||||||
includes all the autotools boilerplate so you don't have to worry
|
|
||||||
about that nonsense too much.
|
|
||||||
|
|
||||||
|
As a *Bloatrunner* you have to collect keys to open the gate at the top of the level. However running costs energy, and as in any endurance event energy management and correct fueling is of utmost importance. By running your glycogen reserves in your muscles will deplete and need to be replenished either from food or from fat reserves.
|
||||||
|
|
||||||
|
Your running kit has some small pockets to store a few gels or packets of gummi bears for fast energy replenishment. You will find replacements from time to time. In addition there will be other food items distributed over the levels.
|
||||||
|
|
||||||
|
However as in real life it seems that most food items are unhealthy and for some reason irresistable so they are consumed immediately. Similarly for some reason it seems that food turns immediately into fat and takes forever to burn off. And too much fat makes you slow and even worse might make passing the finish gate a squeeze or plainly impossible.
|
||||||
|
|
||||||
|
And then there are the _others_, which for some reason can run without getting tired, eat without getting fat, and generally make a nuisance of themselves. Close contact with these makes you lose the will to live and turns you into a couch potato, ceasing to be a _Bloatrunner_.
|
||||||
|
|
||||||
|
A freak accident involving some radioactive meteorite allows you to create craters at will, well, more like potholes. But big enough to let the _others_ fall in so you can pass over their head.
|
||||||
|
|
||||||
|
So now, go out, collect the keys and maintain a healthy diet!
|
||||||
|
|
||||||
|
## Game Plan
|
||||||
|
|
||||||
|
- [x] start project organisation
|
||||||
|
- [x] select some assets to start with
|
||||||
|
- [x] animate hero
|
||||||
|
- [x] figure out tile maps
|
||||||
|
- [ ] create hero entity
|
||||||
|
- [ ] implement hero movement
|
||||||
|
- [ ] create other entity
|
||||||
|
- [ ] add keys and portal
|
||||||
|
- [ ] add foods and bloat indicator
|
||||||
|
- [ ] scale hero waist related to bloat level
|
||||||
|
- [ ] create more levels
|
||||||
|
- [ ] some level celebration/animation
|
||||||
|
|
||||||
## Using Guix
|
## Using Guix
|
||||||
|
|
||||||
We *highly recommend* using [Guix](https://guix.gnu.org/) to manage
|
We *highly recommend* using [Guix](https://guix.gnu.org/) to manage
|
||||||
|
@ -13,12 +36,24 @@ your development environment. Once Guix is installed, getting all of
|
||||||
the dependencies you need to develop is *easy*. Just run `guix shell`
|
the dependencies you need to develop is *easy*. Just run `guix shell`
|
||||||
from the root directory of this repository and you'll be good to go!
|
from the root directory of this repository and you'll be good to go!
|
||||||
|
|
||||||
|
In a hosted guix you can ensure you are in your profile by setting the
|
||||||
|
environment in a `.envrc` file
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
export GUIX_PROFILE="/home/pti/.config/guix/current"
|
||||||
|
source "$GUIX_PROFILE/etc/profile"
|
||||||
|
export GUIX_LOCPATH="$HOME/.guix-profile/lib/locale"
|
||||||
|
use guix -l guix.scm
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Building from source
|
## Building from source
|
||||||
|
|
||||||
|
```
|
||||||
Assuming Guile and Chickadee are installed on your system, a fresh
|
Assuming Guile and Chickadee are installed on your system, a fresh
|
||||||
project can be built like so:
|
project can be built like so:
|
||||||
|
|
||||||
```
|
|
||||||
./boostrap.sh
|
./boostrap.sh
|
||||||
./configure
|
./configure
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
|
@ -53,6 +88,19 @@ port 37146. We recommend using the
|
||||||
it using `M-x connect-to-guile`. Once Geiser connects to the REPL,
|
it using `M-x connect-to-guile`. Once Geiser connects to the REPL,
|
||||||
the game can be modified while it runs!
|
the game can be modified while it runs!
|
||||||
|
|
||||||
|
When the environment is set as indicated above and the emacs direnv module
|
||||||
|
is enabled, we can run `geiser-guile` as usual and everything should work as
|
||||||
|
expected.
|
||||||
|
|
||||||
|
To restart the game on crash I use *watchexec* to observe the folder and restart
|
||||||
|
on crash when the code is updated. That avoids scrolling errors so I can read the
|
||||||
|
error and immediately see if it is fixed on saving.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ watchexec -e .scm ./pre-inst-env run-game
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Bundling
|
## Bundling
|
||||||
|
|
||||||
If you are setup to produce redistributable bundles of Chickadee games
|
If you are setup to produce redistributable bundles of Chickadee games
|
||||||
|
|
|
@ -1,17 +1,6 @@
|
||||||
;;; 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.
|
|
||||||
|
|
||||||
(define-module (game main)
|
(define-module (game main)
|
||||||
#:use-module (game level)
|
#:use-module (game model level)
|
||||||
|
#:use-module (game render level)
|
||||||
#:use-module (chickadee)
|
#:use-module (chickadee)
|
||||||
#:use-module (chickadee math rect)
|
#:use-module (chickadee math rect)
|
||||||
#:use-module (chickadee math vector)
|
#:use-module (chickadee math vector)
|
||||||
|
@ -21,48 +10,26 @@
|
||||||
#:use-module (chickadee graphics text)
|
#:use-module (chickadee graphics text)
|
||||||
#:use-module (chickadee graphics tile-map)
|
#:use-module (chickadee graphics tile-map)
|
||||||
#:use-module (system repl coop-server)
|
#:use-module (system repl coop-server)
|
||||||
#:use-module (srfi srfi-64)
|
|
||||||
#:export (launch-game))
|
#:export (launch-game))
|
||||||
|
|
||||||
(define sprite-position (vec2 156.0 176.0))
|
|
||||||
(define sprite-texture #f)
|
|
||||||
(define tile-texture #f)
|
|
||||||
(define tile-atlas #f)
|
|
||||||
(define hero-texture #f)
|
(define hero-texture #f)
|
||||||
(define hero-atlas #f)
|
(define hero-atlas #f)
|
||||||
(define text-position (vec2 0.0 280.0))
|
(define hero-position (vec2 32.0 32.0))
|
||||||
(define tile-index 0)
|
|
||||||
(define tile-map #f)
|
|
||||||
(define level #f)
|
(define level #f)
|
||||||
(define repl #f)
|
(define repl #f)
|
||||||
|
|
||||||
(define sprite-batch #f)
|
|
||||||
|
|
||||||
(define (load)
|
(define (load)
|
||||||
(set! tile-texture (load-image "assets/images/simples_pimples.png"
|
(render-level-load)
|
||||||
#:transparent-color black))
|
|
||||||
(set! tile-atlas (split-texture tile-texture 16 16))
|
|
||||||
(set! hero-texture (load-image "assets/images/lr_penguin2.png"))
|
(set! hero-texture (load-image "assets/images/lr_penguin2.png"))
|
||||||
(set! hero-atlas (split-texture hero-texture 32 32))
|
(set! hero-atlas (split-texture hero-texture 32 32))
|
||||||
(set! tile-map (load-tile-map "assets/levels/level1.tmx"))
|
|
||||||
(set! sprite-batch (make-sprite-batch tile-texture #:capacity 1000))
|
|
||||||
(set! level (level-parse-file "assets/levels/level-1.map"))
|
(set! level (level-parse-file "assets/levels/level-1.map"))
|
||||||
|
(render-level-set! level)
|
||||||
(set! repl (spawn-coop-repl-server)))
|
(set! repl (spawn-coop-repl-server)))
|
||||||
|
|
||||||
(define (update dt)
|
(define (update dt)
|
||||||
(poll-coop-repl-server repl)
|
(poll-coop-repl-server repl)
|
||||||
(set-vec2-y! sprite-position
|
(set-vec2-x! hero-position
|
||||||
(floor-remainder (+ (vec2-y sprite-position) (* 50.0 dt)) 400.0))
|
(floor-remainder (+ (vec2-x hero-position) (* 50.0 dt)) 608.0)))
|
||||||
(set-vec2-x! text-position
|
|
||||||
(floor-remainder (+ (vec2-x text-position) (* 25.0 dt)) 640.0)))
|
|
||||||
|
|
||||||
(define (draw-tile i)
|
|
||||||
(let ((x (* 16 (remainder i 40)))
|
|
||||||
(y (* 16 (quotient i 40))))
|
|
||||||
(draw-sprite
|
|
||||||
(texture-atlas-ref tile-atlas (+ i 3000 ))
|
|
||||||
(vec2 x y)
|
|
||||||
#:scale (vec2 1.0 1.0))))
|
|
||||||
|
|
||||||
(define (draw-hero i)
|
(define (draw-hero i)
|
||||||
(let ((x (* 64 (remainder i 8)))
|
(let ((x (* 64 (remainder i 8)))
|
||||||
|
@ -75,51 +42,14 @@
|
||||||
(draw-text (format #f "~A" i) (vec2 x y) #:color white))
|
(draw-text (format #f "~A" i) (vec2 x y) #:color white))
|
||||||
)
|
)
|
||||||
|
|
||||||
(define (level-tile-index tile)
|
|
||||||
(case tile
|
|
||||||
((empty) 3800)
|
|
||||||
((brick) 3750)
|
|
||||||
((wall) 3709)
|
|
||||||
((ladder) 3350)
|
|
||||||
((goal) 3404)
|
|
||||||
(else 3326)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(define (draw-level level)
|
|
||||||
(sprite-batch-clear! sprite-batch)
|
|
||||||
(for-each
|
|
||||||
(lambda (row)
|
|
||||||
(for-each
|
|
||||||
(lambda (column)
|
|
||||||
(let*
|
|
||||||
((x (* 16 column))
|
|
||||||
(y (* 16 row))
|
|
||||||
(tile (level-tile-at level column row))
|
|
||||||
(texture-region (texture-atlas-ref tile-atlas (level-tile-index tile))))
|
|
||||||
(sprite-batch-add! sprite-batch (vec2 x y)
|
|
||||||
#:texture-region texture-region)))
|
|
||||||
(iota (level-width level) 0)))
|
|
||||||
|
|
||||||
(iota (level-height level) 0))
|
|
||||||
(draw-sprite-batch sprite-batch))
|
|
||||||
|
|
||||||
(define (draw _alpha)
|
(define (draw _alpha)
|
||||||
(draw-level level)
|
(render-level-draw level)
|
||||||
(let ((hero-position (vec2+ text-position (vec2 -8.0 16.0)))
|
(let ((hero-index (+ 56 (remainder (inexact->exact (floor (vec2-x hero-position))) 8))))
|
||||||
(hero-index (+ 56 (remainder (inexact->exact (floor (vec2-x text-position))) 8))))
|
|
||||||
(draw-sprite
|
(draw-sprite
|
||||||
(texture-atlas-ref hero-atlas hero-index)
|
(texture-atlas-ref hero-atlas hero-index)
|
||||||
hero-position))
|
(vec2+ hero-position (vec2 16.0 0.0))))
|
||||||
|
|
||||||
;; (draw-tile-map tile-map)
|
|
||||||
|
|
||||||
;;(do ((i 0 (+ i 1)))
|
|
||||||
;; ((>= i 1000))
|
|
||||||
;; (draw-tile i))
|
|
||||||
;; (do ((i 0 (+ i 1)))
|
|
||||||
;; ((>= i 64))
|
|
||||||
;; (draw-hero i))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
(define (launch-game args)
|
(define (launch-game args)
|
||||||
|
@ -128,12 +58,3 @@
|
||||||
#:draw (lambda (alpha) (draw alpha))))
|
#:draw (lambda (alpha) (draw alpha))))
|
||||||
|
|
||||||
|
|
||||||
(test-begin "tile draw")
|
|
||||||
|
|
||||||
(test-equal "tile index"
|
|
||||||
(level-tile-index 'empty)
|
|
||||||
3800)
|
|
||||||
|
|
||||||
(test-equal (level-tile-index 'brick) 3750)
|
|
||||||
|
|
||||||
(test-end "tile draw")
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
(define-module (game level)
|
(define-module (game model level)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 pretty-print)
|
#:use-module (ice-9 pretty-print)
|
||||||
#:use-module (ice-9 textual-ports)
|
#:use-module (ice-9 textual-ports)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-9)
|
#:use-module (srfi srfi-9)
|
||||||
#:use-module (srfi srfi-64)
|
#:use-module (srfi srfi-64)
|
||||||
|
|
||||||
#:export (level-width
|
#:export (level-width
|
||||||
level-height
|
level-height
|
||||||
level-tiles
|
level-tiles
|
||||||
|
@ -14,9 +13,7 @@
|
||||||
level-goal
|
level-goal
|
||||||
level-parse-file
|
level-parse-file
|
||||||
level-tile-at
|
level-tile-at
|
||||||
)
|
))
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
(define-record-type <level>
|
(define-record-type <level>
|
||||||
(%make-level width height tiles goal player entities)
|
(%make-level width height tiles goal player entities)
|
74
game/render/level.scm
Normal file
74
game/render/level.scm
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
(define-module (game render level)
|
||||||
|
#:use-module (game model level)
|
||||||
|
#:use-module (srfi srfi-64)
|
||||||
|
#:use-module (chickadee graphics color)
|
||||||
|
#:use-module (chickadee graphics sprite)
|
||||||
|
#:use-module (chickadee graphics texture)
|
||||||
|
#:use-module (chickadee math vector)
|
||||||
|
#:export (render-level-load
|
||||||
|
render-level-draw
|
||||||
|
render-level-set!
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
(define tile-texture #f)
|
||||||
|
(define tile-atlas #f)
|
||||||
|
(define tile-index 0)
|
||||||
|
(define tile-map #f)
|
||||||
|
(define sprite-batch #f)
|
||||||
|
|
||||||
|
;; load the tile texture and split it into a tile atlas
|
||||||
|
(define (render-level-load)
|
||||||
|
(set! tile-texture (load-image "assets/images/simples_pimples.png"
|
||||||
|
#:transparent-color black))
|
||||||
|
(set! tile-atlas (split-texture tile-texture 16 16))
|
||||||
|
(set! sprite-batch (make-sprite-batch tile-texture #:capacity 1000))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; map tile symbols to tile indices in the tile atlas
|
||||||
|
(define (level-tile-index tile)
|
||||||
|
(case tile
|
||||||
|
((empty) 3800)
|
||||||
|
((brick) 3750)
|
||||||
|
((wall) 3709)
|
||||||
|
((ladder) 3350)
|
||||||
|
((goal) 3404)
|
||||||
|
;; render visual reminder of unknown tile
|
||||||
|
(else 3326)))
|
||||||
|
|
||||||
|
|
||||||
|
;; update the sprite-batch for the passed level
|
||||||
|
(define (render-level-set! level)
|
||||||
|
(sprite-batch-clear! sprite-batch)
|
||||||
|
(for-each
|
||||||
|
(lambda (row)
|
||||||
|
(for-each
|
||||||
|
(lambda (column)
|
||||||
|
(let*
|
||||||
|
((x (* 16 column))
|
||||||
|
(y (* 16 row))
|
||||||
|
(tile (level-tile-at level column row))
|
||||||
|
(texture-region (texture-atlas-ref tile-atlas (level-tile-index tile))))
|
||||||
|
(sprite-batch-add! sprite-batch (vec2 x y)
|
||||||
|
#:texture-region texture-region)))
|
||||||
|
(iota (level-width level) 0)))
|
||||||
|
|
||||||
|
(iota (level-height level) 0)))
|
||||||
|
|
||||||
|
;; render the level tiles
|
||||||
|
(define (render-level-draw level)
|
||||||
|
(draw-sprite-batch sprite-batch))
|
||||||
|
|
||||||
|
|
||||||
|
(test-begin "tile translation")
|
||||||
|
|
||||||
|
(test-equal (level-tile-index 'empty) 3800)
|
||||||
|
(test-equal (level-tile-index 'brick) 3750)
|
||||||
|
(test-equal (level-tile-index 'wall) 3709)
|
||||||
|
(test-equal (level-tile-index 'ladder) 3350)
|
||||||
|
(test-equal (level-tile-index 'goal) 3404)
|
||||||
|
(test-equal (level-tile-index 'unknown) 3326)
|
||||||
|
|
||||||
|
(test-end "tile translation")
|
Loading…
Reference in a new issue