Survivor is a graphical action game for the Linux terminal. It is havily inspired by Vampire Survivors.
The player controls an automatically attacking character, with the goal to survive for as long as possible. At the start the character's only weapon is a shield that damages nearby enemies. Killed enemies drop diamonds that can be collected to gain XP. When the blue XP bar at the top of the screen is full the player receives a random perk:
- Damage is increased by 10%
- Max health is increased by 10%
- Movement speed is increased by 10%
- Shield radius is increased by 10%
- Pickup radius is increased by 10%
- Experience from diamonds is increased by 10%
- Weapon cooldown is decreased by 10%
- Full health is restored
- The player recovers +0.2HP per second
- Get an additional axe
- Get an additional knive
- Get an additional shuriken
- Get an additional whirlwind
The game is written in rust and does not have any dependencies outside the
standard library and libc. You can run cargo run
to build and execute it.
- Arrow keys / wasd / hjkl: move
- Space: stop moving
- q: quit
The sprites are based on artwork from Vampires Dawn 2.
I had wanted to create a graphical action game for the terminal for a long time. This kind of game felt like a good fit for the particular restrictions that come with the terminal.
Also, Vampire Survivors takes a full minute to load and then full saturates the CPU on my laptop, even in the menu. I wanted to prove to myself that that is not necessary.
Terminals do not have a concept of key release events. That is actually a major reason why it is so hard to create games for the terminal. There are proposals to add proper keyboard events, but so far they have not gained much traction.
Each cell of the terminal is subdivided into 2x3 pixels. This way we can get a decent resolution. However, each cell can only have two colors. Artifacts happen when the game tries to draw more then two colors into a single cell.
The game is designed to run on 30fps. The amount of computation that needs to be done scales with the size of the window. So if you get a bad frame rate, there is a good chance that it will improve if you reduce the window size.
The aspect ratio of pixels depends on the font. You can adjust
win::ASPECT_RATIO
to compensate for that.
src/main.rs
contains the main loop.src/game.rs
contains most of the game logic.src/input.rs
,src/random.rs
, andsrc/term,rs
wrap unsafe libc functions for low level functionality.src/enemies.rs
contains all the enemy types as well as the waves in which they appear.src/sprites.rs
contains all graphics. The sprites are stored in ppm files and converted to rust arrays by theinclude_ppm!()
macro. That way all graphics are included in the binary. The color of the first pixel in a sprite is considered transparent.src/win.rs
contains some drawing primitives as well as the conversion between logical positions and screen pixels.
Most game logic is expressed as f32
. Positions represet the logical center of
objects. When drawing to the screen, the f32
positions are converted to
usize
pixels. Game logic is mostly independent of pixels though. The only
exceptions are that enemy spawn and despawn outside of the screen, so they
depend on the screen size.
- Let the player pick a perk on level up
- Improve balancing
- Add tarain
- More enemy waves
- Sound