A game engine for building games for CLIs
Project description
Spaceship Engine: Comprehensive User Guide
This guide explains how to build terminal/ASCII games with the Spaceship Engine. It covers architecture, APIs, workflows, patterns, performance considerations, and a complete tutorial that develops a basic top‑down exploration game.
1. Introduction
The Spaceship Engine is a lightweight framework for building real‑time ASCII games in the terminal. It provides:
- A main loop that handles initialization, per‑frame updates, input polling, and rendering.
- A camera and renderer that compose entities into a frame buffer and draw an efficient terminal diff.
- An
Entitybase class with a built‑inSpritefor ASCII art and z‑ordering. - A simple HUD system with templated values and alignment.
- Keystroke polling that exposes the set of keys currently held.
- Math and constants utilities for grid size, character aspect ratio, and vectors.
2. Project Structure
A recommended layout for a game project using the engine is the following:
spaceship/# the engine (as provided)
game.py
render/
camera.py
entity.py
hud.py
render.py
sprite.py
input/
input.py
utils/
constants.py
math.py
my_game/ # your game code
main.py
Place the engine directory on the Python path (same parent folder as your game) so you can import spaceship... modules directly.
3. Engine Architecture Overview
3.1 Game
Game owns the lifecycle of your program.
- Construct with
Game(init_hook, update_hook, [border=True/False, border_template]). - Call
run()to enter the loop. - Use
add_entity(entity)andremove_entity(entity)to manage scene content. - Exposes
HUD,camera,input, and the currententitieslist.
3.2 Entity
Entity represents a world object with:
position: Vector— world coordinates.sprite: Sprite— ASCII art, with optional center marker and priority.update(dt: float)— override in subclasses; returnsuper().update(dt).kill()— mark for removal.
3.3 Sprite
Sprite renders multi‑line ASCII art:
- Call
load(raw: str | tuple[str, ...], priority: int = 1). - A single tab character
\tinside the art defines the visual center. This aids alignment and camera transforms. priority(z‑order): larger values render on top of smaller values.- An few examples for a raw string would be:
"""
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⡴⣆⠀⠀⠀⠀⠀⣠⡀ ᶻ 𝗓 𐰁 .ᐟ ⣼⣿⡗⠀⠀⠀⠀
⠀⠀⠀⣠⠟⠀⠘⠷⠶⠶⠶⠾⠉⢳⡄⠀⠀⠀⠀⠀⣧⣿⠀⠀⠀⠀⠀
⠀⠀⣰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣤⣤⣤⣤⣤⣿⢿⣄⠀⠀⠀⠀
⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀\t⣧⠀⠀⠀⠀⠀⠀⠙⣷⡴⠶⣦
⠀⠀⢱⡀⠀⠉⠉⠀⠀⠀⠀⠛⠃⠀⢠⡟⠀⠀⠀⢀⣀⣠⣤⠿⠞⠛⠋
⣠⠾⠋⠙⣶⣤⣤⣤⣤⣤⣀⣠⣤⣾⣿⠴⠶⠚⠋⠉⠁⠀⠀⠀⠀⠀⠀
⠛⠒⠛⠉⠉⠀⠀⠀⣴⠟⢃⡴⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
"""
"""
╱|、
(˚ˎ。7
|、\t˜〵
じしˍ,)ノ
"""
3.4 Camera
The camera converts world space to screen space and applies character‑aspect compensation. You can:
- Set
camera.positionto pan or follow an entity. - Switch
camera.mode(e.g., centered vs top‑left origin) depending on how you want coordinates interpreted.
3.5 Renderer
The renderer composes entity sprites into a frame buffer, compares against the previous frame, and prints only the differences using ANSI cursor control. It also draws HUD layers before and after the world.
3.6 HUD
The HUD prints formatted text rows at the top and bottom of the screen.
- Use
HUDElement(template: str, values: dict, align: HUDAlignment). - Add elements with
game.HUD.add_top_hud(...)oradd_bottom_hud(...). - Update dynamic values via
HUDElement.set_value(key, value).
3.7 Input
The input subsystem polls the keyboard and exposes game.input.keys_held, a set of keys currently pressed during the frame. Read it inside your update(dt) methods.
3.8 Math and Constants
Vector(x: float = 0, y: float = 0)supports addition, subtraction, float scaling (v * 1.0), and dot product (v * v2). Prefer floating‑point for speed/time scaling.- Global constants cover grid size and character aspect ratio. Adjust character aspect to match your terminal’s font proportions.
4. Development Workflow
- Create your
Gamewithinitandupdatehooks. - In
init, add entities, set camera mode/position, and register HUD elements. - Implement entity subclasses and override
update(dt). - Poll input in
update(dt)to move entities, trigger actions, and modify state. - Update HUD values as state changes.
- Run and iterate.
5. Core API Reference (Practical)
5.1 Game
Game(init_hook: Callable, update_hook: Callable)run()— starts loopadd_entity(e: Entity) -> Entity— registers and returns the entityremove_entity(e: Entity)— detaches from the scene- Properties:
hud,camera,input,entities
5.2 Entity
- Constructor:
Entity(game: Game, position: Vector) - Methods:
update(dt: float),kill() - Fields:
position: Vector,sprite: Sprite
5.3 Sprite
load(raw, priority=1)whererawis either a string or a tuple containing a single triple‑quoted stringpriority: int— z‑layer order- Optional center marker: single in the art
5.4 HUD
HUDElement(template, values, align)HUD.add_top_hud(elem),HUD.add_bottom_hud(elem)HUDElement.set_value(key, value)
5.5 Input
game.input.keys_held— read‑only set of keys for the current frame
5.6 Camera
camera.position: Vectorcamera.mode— origin mode (center, top‑left, etc.)
6. Patterns and Best Practices
- Always call
super().update(dt)at the end of your overriddenupdatemethod unless you have a specific reason not to. This preserves any base‑class housekeeping. - Use floating‑point speeds (e.g.,
60.0), then scale displacement bydteach frame. - Keep ASCII sprites rectangular with consistent line widths.
- Use sprite
priorityto layer HUD‑like in‑world indicators (arrows, bullets, effects) above background sprites. - Centralize frequently updated HUD elements by keeping references to their
HUDElementinstances. - If vertical motion appears distorted, adjust the
CHAR_ASPECTconstant inconstants.py. - For portability, ensure the keyboard polling library has the necessary permissions on your OS (mainly for Linux).
7. Debugging Checklist
- Nothing draws: ensure the sprite was loaded with non‑empty art and that your entity is added to the game.
- Input is unresponsive: verify OS permissions and that you read
keys_heldinsideupdate. - Misalignment: use the tab center marker in sprites or choose an appropriate camera mode.
- Flicker or unexpected redraws: check that your terminal supports ANSI cursor movement and that you are not printing elsewhere.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spaceship_engine-0.2.0.tar.gz.
File metadata
- Download URL: spaceship_engine-0.2.0.tar.gz
- Upload date:
- Size: 18.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4eee5948003291507cb386b9aef5bcfced08f609bd2742849ef13b09eacfb166
|
|
| MD5 |
d0fe5ae279fa6f7a65d99a3f373070af
|
|
| BLAKE2b-256 |
ffa8093a1d726c429dbd3438cabae39daa5661a5c4b73747f34215de48aaf819
|
Provenance
The following attestation bundles were made for spaceship_engine-0.2.0.tar.gz:
Publisher:
publish-pypi.yml on Falingunit/spaceship
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spaceship_engine-0.2.0.tar.gz -
Subject digest:
4eee5948003291507cb386b9aef5bcfced08f609bd2742849ef13b09eacfb166 - Sigstore transparency entry: 731899039
- Sigstore integration time:
-
Permalink:
Falingunit/spaceship@2f2e92b611d289f911720898c7dbca2d1e01d661 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Falingunit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@2f2e92b611d289f911720898c7dbca2d1e01d661 -
Trigger Event:
push
-
Statement type:
File details
Details for the file spaceship_engine-0.2.0-py3-none-any.whl.
File metadata
- Download URL: spaceship_engine-0.2.0-py3-none-any.whl
- Upload date:
- Size: 18.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf66d43a083a7b47335691e8a79c340abe100f0ad6328087e82ee043853c8d61
|
|
| MD5 |
42f31076e26a4180e4064e450d2012ae
|
|
| BLAKE2b-256 |
4ca0fec6b68c602d7e630ceed99919ed642ba503197a4e887fcca52f29b1121f
|
Provenance
The following attestation bundles were made for spaceship_engine-0.2.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on Falingunit/spaceship
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
spaceship_engine-0.2.0-py3-none-any.whl -
Subject digest:
bf66d43a083a7b47335691e8a79c340abe100f0ad6328087e82ee043853c8d61 - Sigstore transparency entry: 731899040
- Sigstore integration time:
-
Permalink:
Falingunit/spaceship@2f2e92b611d289f911720898c7dbca2d1e01d661 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Falingunit
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@2f2e92b611d289f911720898c7dbca2d1e01d661 -
Trigger Event:
push
-
Statement type: