A scrolling shooter, built with PICO-8
This is a PICO-8 game, which I made during Basic Shmup Showcase event organised by Lazy Devs Academy.
You can play it on https://beetrootpaul.itch.io/dart-07 and on https://www.lexaloffle.com/bbs/?tid=49480 .
If you want to take a look at the codebase, please visit https://github.com/beetrootpaul/dart-07 (the code inside PICO-8 carts of this game is minified, therefore not suitable for reading).
Keyboard:
- press & hold
x
to fire - press
c
to trigger a shockwave (if available) - press
p
to open the pause menu
Virtual controller (in browser, on a mobile device):
- press & hold
❎
to fire - press
🅾️
to trigger a shockwave (if available) - press
➖
to open the pause menu
Physical game controllers are supposed to work as well, even in a browser. Button mapping varies between models.
Your task is to pilot Dart-07 unit on a secret mission on Emerald Islands.
Destroy enemies along the way to increase your score, grab power-ups left by them and survive a boss fight in order to complete a mission.
There are 5 types of power-ups you can grab, each of them either makes your life easier or, if cannot improve further, increases your score:
- +1 heart – you can have max 10 hearts; you lose one whenever you take damage
- fast movement – increases player's movement speed; does not accumulate; lost on a damage
- fast shoot – increases shooting speed; does not accumulate, but can be combined with the triple shoot; lost on a damage
- triple shoot – you shoot 3 bullets instead of 1, but on a little but slower rate; does not accumulate, but can be combined with the fast shoot; lost on a damage
-
shockwave charge – allows you to trigger a destructive shockwave around you (with use of "c" / "
🅾️ " button); you can have max 4 shockwave charges
In your HUD you see:
- left-top: mission progression (the higher the ship's icon is placed, the close to the boss you are)
- right-top: your score, which you gain by destroying enemies and grabbing power-ups in case they cannot bring any improvement
- right-middle: power-ups you gathered (excluding hearts and shockwave charges)
- left-bottom: hearts left; you die when all hearts are gone
- right-bottom: shockwave charges left; you can trigger a shockwave if you have at least 1 charge left
- top-middle, during boss fight: boss' health (yes, you are supposed to bring it down to zero 😉)
In this game I focused on learning various bits of PICO-8 API.
Some of the topics I tackled in this game are:
- multi-cart setup: this game consists of many carts – 1 main cart for the title screen etc., and 1 cart for each
mission (the game contains only a single mission, but the code architecture is ready to have more of them). Each
mission has its own sprites and music, as well as a code responsible for available enemy types, including their attack
and movement patterns. Common SFXs and sprites are copied from the main cart to missions carts with use
of MEMCPY and a user data memory
area (
0x4300-0x55ff
), preserved across loaded carts). Moreover, I implemented this in a way which allows me to use same codebase to load both locally developed carts as well as those published to Lexaloffle BBS. - missions defined as a map – level shape and enemy pattern are defined as sprites in a PICO-8 map, but in a simplified form (in order to fit all needed data there). Dedicated piece of code is responsible for translating sprites from map into a mission gameplay, including proper placement of edge land/structure tiles.
- circular clipping: during shockwave a ring of inverted colors propagates from the player. To achieve that I had to learn how to implement circular clipping masks in a CPU-performant way.
- dithered fade-in/out transition: basically a set of rectangles filled with FILLP patterns, moving over screen.
- high score: usage of PICO-8's API to read and store data persisted on a host machine
- code minification: with my code style (full of spaces and long names), I found it easy to hit PICO-8's characters' count limit. Therefore I forked and modified luamin tool and incorporated it into this game's build flow, resulting with characters' count reduced by around 50%.
PICO-8 version used to develop this game: 0.2.5c
Quick start:
- (optional) Install nvm
- (optional) Run
nvm install
to setup proper Node.js version - (once) Run
npm install
to download dependencies - Run
npm start
to start a watcher which generates minified Lua sources for the game every time a file is changed. Please be aware all files has to be included (#include
) manually in the cart's Lua itself. - Start PICO-8 and load dart-07.p8 cart
Optionally, to build without minification: npm run watch-and-build-as-is
To build dist packages:
- remove cart data file from PICO-8 cart data folder (as set in
$HOME/Library/Application Support/pico-8/config.txt
) - then run
npm run dist
To update the sprite sheet of, for example, mission 1:
- edit
graphics/spritesheet_mission_1.aseprite
in Aseprite (please remember you have to use official standard 16 PICO-8 colours so they will match on import) - export to PNG with scale 100%
- load cart and run
import graphics/spritesheet_mission_1.png
orimport dart-07/graphics/spritesheet_mission_1.png
( depends on what your current working directory is)
This game is made with PICO-8, which imposes a token count limit
(which can be checked in console with info
command).
It means, in a lot of situations a code clarity had to be sacrificed
in order to squeeze one more enemy or to implement a high score feature ¯\_(ツ)_/¯
I release this game under MIT license for sake of simplicity and to allow people learn from it.
But, aside from that (therefore I cannot enforce it on you 🙃), if you find this repository useful or use it publicly in any way, I would be happy to see myself credited. You can found my social media profiles etc. on http://beetrootpaul.com , or just link to that webpage 🙂
I implemented this game on my own, as well as drew all sprites and composed all SFXs and music. But there are some resources I found super useful and used some of them I used in the codebase as well. With huge thanks, here are those:
#easingcheatsheet
cart by ValerADHD with copy-paste ready easing functions. See: https://www.lexaloffle.com/bbs/?tid=40577- Circular Clipping Masks tutorial by Krystman
- Lua minification tool
luamin
by Mathias Bynens - Pico-8 Music Tutorials by Gruber
- Mission selection screen is now hidden in order to not expose an unfinished work
- added score is shown in place of destroyed enemy and picked powerup (in case it won't have any other effect)
- increase shooting speed for a combination of triple shoot and fast shoot powerups (to make it easier to notice the change in the speed)
- increase screen shake player on damage to make it easier to realized the damage happened; remove screen shake on shockwave trigger
- fix ship sprite on the mission selection screen
- HTML5: place PICO-8 game controls closer to the game itself in order to allow narrower iframe size
- new powerup type: fast movement
- fixed diagonal speed of a player's ship by dividing it by
1.41
- fast movement, fast shoot, and triple shoot have their status visible in a HUD
- more health for mission 1 boss and mission 1 big enemy
- shake camera on a shockwave trigger
- lower volume of player shooting
- show a win screen after first mission (the completed one)
- print version number on a title screen
- complete game mechanics
- complete mission 1
- complete screens outside missions (but without music for a win screen after mission 3)
- implemented persisted high score
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.