A simple space shooter game. Runs in the terminal using characters-based UI. Fully written in Rust, using the "ruscii" library.

Overview

Thrust - a terminal shooter game

Originally created as a project for the "Missing Semester" course at JKU Linz (338.006).

The game is entirely written in the Rust programming language and uses the ruscii library for handling user input, the basic event loop and colored drawing.

rustcii is a multi-platform crate, so the game should run on Linux, macOS and Windows.
Note, that for parsing user input on Linux, the X11 Server is (unfortunately) required.

Game description

The hero is a spaceship starting at the bottom of the screen. It can move around freely in all directions. Initially every 2 seconds an enemy spawns at the top of the screen. Every 10 seconds the spawn frequency increases (until a maximum value).
As the enemies move downwards, you should attempt to destroy as many as you can.
Once an enemy escapes (by reaching the ground) this will damage the player's health.
Every destroyed enemy drops a random goodie that can be picked up by touching it.
The game keeps track of how many enemies were destroyed by the player and accumulates a total score.
The game is over, once the player's health reaches 0.

Controls

Use W S A D to move the spaceship.
Pressing Space toggles the ship's auto-shoot.
Both Esc and Q will quit the game.

Implementation details

The game is capped at 20 frames per second.
The field size is 60 characters in x-direction and 32 in y-direction.
Due to characters in a terminal generally being twice as high as wide, the player moves two times as fast in the horizontal direction than the vertical one. This can lead to problems shooting enemies with width 1 and can cause involuntary skipping elements.
As following the ship is 3 characters long and fires 3 shots at once each time. This makes it easier to catch goodies and hit enemies.

HUD

On the left of the game field the health and shield bar are drawn.
At the top of the field the current score is displayed.
A border is drawn around the game field, to make it clear where enemies appear/disappear and shots disintegrate.
Embedded in the border the current FPS counter is displayed.

Goodies

Destroying an enemy leads to the drop of a goodie on its current position.
A goodie is one out of three types:

  • : RepairKit -- heals the ship by 5 health (max 100)
  • O: ShieldBoost -- increases the current shield charge by 10 points (max 100)
  • ^ or Y or T: ShipUpgrade -- causes a ship and main weapon change

Ship types

By picking up a ship upgrade, the type of weapon changes. There are by now 3 different ones:

  • ^ -> /^\ -> shoots 3 straight usual | shots; These disappear once they hit something
  • Y -> Y+Y -> shoots 4 diagonal shots and one usual straight shot
  • T -> TuT -> shoots 3 powerful shots which destroy and go through enemies

Damage

Different types of events hurt the ship and its shield in different magnitude.

  • hit by enemy shot -- 5 damage to shield or health
  • collision with enemy -- 50 damage to shield or health
  • enemy escapes (ground) - 15 direct damage to health, bypasses the shield

Even if the shield is on minimum (5), it will block the full collision damage. When having 5 shield, you can hit an enemy to quickly destroying it instead of receiving 15 direct damage.

Dependencies

  • ruscii (and sub-dependencies) for input handling, the event loop, and rendering the game
  • rand to choose random goodies and new enemies' horizontal spawn positions

Usage

To compile the game, the rust package manager and compiler cargo is required.
To run the game, you can clone this repository and execute:

cargo run

Debugging is complicated, because stdout is used to display the interface.
It is, however, possible to log messages to stderr using eprintln! and run the app while redirecting the error stream to a file (instructions from):

export RUST_BACKTRACE=1
cargo run 2> my_stderr

For simply trying out the app, Windows and Linux binaries are pre-compiled and provided in the releases section.

Test environment

All development and testing was done under Arch Linux (Kernel 6.1.4-arch1-1) with:

  • cargo 1.65.0
  • rustup 1.25.1
  • rustc 1.65.0
  • edition = "2021"
  • ruscii = "0.3.2"
  • rand = "0.8.5"

For minimum input lag when rendering many elements and best performance the alacritty terminal emulator was used for running the application.

Effort and research

A lot of effort went into researching and trying out different terminal/console game engines. Due to personal recommendations, I wanted to avoid the complexity and learning curve of the ncurses library (this is probably the best library for creating terminal based UIs out there).

One of the first Google search results when searching for "terminal game engine" are

The first was poorly documented and would require the C# programming language (in which im rusty).

An alternative C# framework would have been:

This seemed to be more optimized for general terminal UI building, not focused on games.

I've decided to use Termloop, written in Go and started getting familiar with the Golang language a bit. When I was finally starting implementation, I've realized that this engine does not support key-down/key-up events. Thus moving in two directons at once (diagonally) would be practically impossible. Also, it was a bit laggy.

I've then investigated some other libraries that would support these traits, like:

It seemed promising, but complex. Especially the WASM support catched my eye.

There seemed to be many frameworks in Rust, so I've compared some of them.

Finally, I've decided to use ruscii as a base framework.
It had key-down/key-up events, while being simple enough to understand.
Furthermore there was a demo application that corresponded to a simple version of what I planned to create.

So I've (re-)learned myself the Rust programming language.

After all this research, I spent about another 30 hours of development time in my IDE to create this game.

Demos and screenshots

The following 3 screenshots shows how a gameplay moment might look like with the three different ship types.

  • default shot type (3 straight frontal ones), 50 health, 20 shield, 50 score

with default ship and shot

  • spread shot (4 diagonal ones, 1 straight), 75 health, 15 shield, 130 score, several goodies

with spread shot ship

  • strong shot (3 strong, straight, surviving shots), 55 health, 50 shield, 115 score, shield goodie

with strong shot ship

  • game over screen, final score 215

game over screen

Future work and ideas

Many more hours can be put into the game to better optimize it and make it more interesting.

Ideas for the game:

  • more goodies: like rapid shot
  • different ship sizes and coloring art
  • stronger (and bigger) enemies, that require more than one hit (and change color according to health)
  • bosses
  • pre-defined levels and progress
  • saving the local high-score to a file and display/update the current best
  • enter name
  • loading screen with tutorial/instructions
  • super weapon (goodie?) like bomb that clears (parts of the) screen damaging all enemies
  • ...

Further ideas for the projects:

  • use WASM to compile for browser support
  • deploy to a Kubernetes cloud service and provide public IP to play
  • try to port the game to different frameworks (like doryen-rs) and experiment with performance and features
  • compile a macOS version
  • make asciinema live demo
  • ...
You might also like...
2-player game made with Rust and
2-player game made with Rust and "ggez" engine, based on "Conway's Game of Life"

fight-for-your-life A 2-player game based on the "Conway's Game of Life", made with Rust and the game engine "ggez". Create shapes on the grid that wi

rpg-cli is a bare-bones JRPG-inspired terminal game written in Rust
rpg-cli is a bare-bones JRPG-inspired terminal game written in Rust

rpg-cli is a bare-bones JRPG-inspired terminal game written in Rust. It can work as an alternative to cd where you randomly encounter enemies as you change directories.

Victorem - easy UDP game server and client framework for creating simple 2D and 3D online game prototype in Rust.

Victorem Easy UDP game server and client framework for creating simple 2D and 3D online game prototype in Rust. Example Cargo.toml [dependencies] vict

My first attempt at game programming. This is a simple target shooting game built in macroquad.

sergio My first attempt at game programming. This is a simple target shooting game built in macroquad. Rules Hit a target to increase score by 1 Score

Find out what takes most of the space in your executable.

cargo-bloat Find out what takes most of the space in your executable. Supports ELF (Linux, BSD), Mach-O (macOS) and PE (Windows) binaries. WASM is not

Helper functions and structs for working with 2D space in Bevy.

About Baffled by quaternions? Want to accelerate an object in 2D? Wish that there was a simple way to work with grids? Just want to know if two axis-a

A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it techinically works
A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it techinically works

rustetris A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it tech

Safe, fully-featured bindings to the Tracy profiler

Complete Rust bindings for the Tracy profiler. Getting Started Just add the following to your Cargo.toml: [dependencies.tracy] package = "tracy_full"

A Client/Server game networking plugin using QUIC, for the Bevy game engine.
A Client/Server game networking plugin using QUIC, for the Bevy game engine.

Bevy Quinnet A Client/Server game networking plugin using QUIC, for the Bevy game engine. Bevy Quinnet QUIC as a game networking protocol Features Roa

Releases(0.2.0)
Owner
Mathias Wöß
IT and Programming Enthusiast
Mathias Wöß
A simple implementation of Conway's Game of Life using Fully homomorphic Encryption

Game of life using Fully homomorphic encryption A simple implementation of Conway's Game of Life built using Zama's concrete-boolean library. Build Ju

Florent Michel 4 Oct 3, 2022
Fish Fight is a tactical 2D shooter. Made with Rust-lang and Macroquad 🦀🌶

Fish Fight Introduction Fish Fight is a tactical 2D shooter, played by up to 4 players online or on a shared screen. Aim either left or right; the res

Fish Fight 732 Jan 1, 2023
A space-themed shoot 'em up game.

Zenith A space-themed shoot 'em up game made with Bevy. Building from source After you clone this repository, ensure you have Rust installed. Dependin

Amelia Clarke 22 Dec 15, 2022
A quick and dirty Space Invaders type game in Bevy, with attached tutorial.

This article is in-development and will be released in full form soon. It'll appear on Medium (my publisher likes that), with this as a the accompanyi

Herbert 17 Oct 18, 2022
Terminal-based Snake game written in Rust without dependencies (for educational purposes).

RustSnake This is a simple terminal-based Snake game implemented in Rust without dependencies. To start the game type cargo run. Control the snake usi

Florian Wickert 88 Jan 6, 2023
A Chess Engine written in Rust that runs natively and on the web!

About The Project chess-rs is a Chess Engine written from scratch in Rust that runs natively and on web! Live Demo: https://parthpant.github.io/chess-

Parth Pant 109 Apr 6, 2023
Solana Game Server is a decentralized game server running on Solana, designed for game developers

Solana Game Server* is the first decentralized Game Server (aka web3 game server) designed for game devs. (Think web3 SDK for game developers as a ser

Tardigrade Life Sciences, Inc 16 Dec 1, 2022
Blackmarlin is a chess engine fully written in Rust.

Blackmarlin WIP UCI Chess Engine Blackmarlin is a chess engine fully written in Rust. Make sure to compile the chess engine with cargo build --release

null 50 Oct 31, 2022
A game of snake written in Rust using the Bevy game engine, targeting WebGL2

Snake using the Bevy Game Engine Prerequisites cargo install cargo-make Build and serve WASM version Set your local ip address in Makefile.toml (loca

Michael Dorst 0 Dec 26, 2021
A terminal based game engine

ccdb: The cmd game engine (Thats also multi threaded) How to use Tutorial Multi threading If you want to use multi threading you have to use ACore The

null 34 Oct 19, 2022