An open API service indexing awesome lists of open source software.

https://github.com/fosskers/aero-fighter

A recreation (in CL) of a friend's old game that he wrote in Turbo Pascal.
https://github.com/fosskers/aero-fighter

common-lisp raylib

Last synced: 4 months ago
JSON representation

A recreation (in CL) of a friend's old game that he wrote in Turbo Pascal.

Awesome Lists containing this project

README

        

#+title: Aero Fighter

[[file:screenshot.png]]

#+begin_quote
Reach God Mode!
#+end_quote

* Table of Contents :TOC_5_gh:noexport:
- [[#history][History]]
- [[#building][Building]]
- [[#library-preparation][Library Preparation]]
- [[#sdl-backend][SDL Backend]]
- [[#repl-loading][REPL Loading]]
- [[#compiling-executables][Compiling Executables]]
- [[#sbcl][SBCL]]
- [[#ecl][ECL]]
- [[#controls][Controls]]
- [[#game-mechanics][Game Mechanics]]
- [[#spawn-schedule][Spawn Schedule]]
- [[#coding-conventions][Coding Conventions]]
- [[#credits][Credits]]

* History

Aero Fighter was a game originally created by a friend of mine over 20 years ago
in [[https://en.wikipedia.org/wiki/Turbo_Pascal][Turbo Pascal]]. For years he has told me how he'd love to dig out its old
floppy disk and somehow get it working again.

In an effort to test the feasability of developing with [[https://github.com/raysan5/raylib/][Raylib]] in Common Lisp, I
have recreated Aero Fighter with many enhancements. It is a simple top-down
shooter game in NES-style. The goal is simple:

#+begin_quote
Reach God Mode.
#+end_quote

And then see how long you can last!

* Building

Aero Fighter can only be built with SBCL and ECL.

** Library Preparation

Before attempting to build Aero Fighter in any way, we must prep its C
dependencies.

#+begin_example
make dev
#+end_example

This will compile Raylib, move =.so= files to their expected locations, and create
certain symlinks. Now you can load Aero Fighter in your REPL, or build
standalone executables.

*** SDL Backend

By default, Raylib is compiled in GLFW-mode. To use SDL instead, run:

#+begin_example
make dev PLATFORM=PLATFORM_DESKTOP_SDL
#+end_example

The value of =PLATFORM= matches that of Raylib itself. Technically you can put
whatever value you want here, but only GLFW and SDL are guaranteed to work with
Aero Fighter.

** REPL Loading

As all dependencies are vendored, [[https://github.com/fosskers/vend][vend]] is recommended for accessing these from a
REPL.

#+begin_example
vend repl
#+end_example

Within Emacs, you can then define an alternate connection scheme for Sly:

#+begin_src emacs-lisp
(setq sly-default-lisp 'sbcl
sly-lisp-implementations '((sbcl ("vend" "repl" "sbcl") :coding-system utf-8-unix)
(ecl ("vend" "repl" "ecl") :coding-system utf-8-unix)))
#+end_src

Make sure to start Sly from the project root.

** Compiling Executables

You can just run =make=, or use a specific compiler like so:

*** SBCL

#+begin_example
sbcl --load build.lisp
#+end_example

*** ECL

#+begin_example
ecl --load build.lisp
#+end_example
* Controls

Given any SNES-like or Xbox 360-like controller:

| Button | Action |
|---------+------------------------|
| D-Pad | Movement |
| Start | Start the Game |
| Select | Switch main controller |
| A | Laser |
| B | Bomb |
| X/Y/L/R | Warp |

Keyboards:

| Key | Action |
|--------+------------------------|
| Arrows | Movement |
| Space | Start the Game / Laser |
| Enter | Bomb |
| Tab | Warp |

* Game Mechanics

** Spawn Schedule

Every frame, something might spawn.

| Thing | Timing | Per-frame Chance |
|-----------+-----------+-------------------|
| Bomb | Every 20s | 4/5000 |
|-----------+-----------+-------------------|
| Blob | Every 2s | (level * 40)/5000 |
| Tank | Every 3s | (level * 25)/5000 |
| Evil Ship | Every 5s | 16/5000 |
| Building | Every 5s | 16/5000 |

Certain other entities have fixed spawn timings.

| Thing | Timing |
|---------------------+-------------------|
| Missile | Every 1s |
| Beam Upgrade | Every 1000 points |
| Difficulty Increase | Every 5000 points |
| Tripwire-Cannon | Every 5000 points |

* Coding Conventions

- Prefix: =@= denotes a smart constructor.
- Postfix: =?= denotes a boolean result from a function.
- Postfix: =!= implies that the function mutates its arguments.
- Top-level =defparameter= values are placed in the =package.lisp=.

Otherwise, we keep things simple: just structs and functions. No CLOS, other
than light use of =defgeneric=.

All dependencies are vendored.

* Credits

Aero Fighter uses hand-written bindings to [[https://github.com/raysan5/raylib/][Raylib]] for windowing, sound effects,
collision, etc. The rest of the game logic is in pure Common Lisp.

| Person | Role |
|--------------+----------------|
| Colin | Code, Graphics |
| JPJ | Concept |
| Gumichan01 | [[https://opengameart.org/content/laser-shot][Sound Effects]] |
| Joel Burford | [[https://joelfrancisburford.itch.io/jrpg-8-bitchiptune-sfx-pack][Sound Effects]] |
| SketchyLogic | [[https://opengameart.org/content/nes-shooter-music-5-tracks-3-jingles][Music]] |