{"id":48591909,"url":"https://github.com/nsmryan/rustroguelike","last_synced_at":"2026-04-08T20:02:25.018Z","repository":{"id":39569505,"uuid":"180917790","full_name":"nsmryan/RustRoguelike","owner":"nsmryan","description":"This Rust Roguelike is a Roguelike written in Rust.","archived":false,"fork":false,"pushed_at":"2022-11-13T15:19:59.000Z","size":60343,"stargazers_count":16,"open_issues_count":153,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2023-08-01T04:24:16.692Z","etag":null,"topics":["game","roguelike","rust","sdl2","unity3d"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nsmryan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-12T02:48:24.000Z","updated_at":"2023-07-15T10:54:40.000Z","dependencies_parsed_at":"2022-09-04T11:20:24.350Z","dependency_job_id":null,"html_url":"https://github.com/nsmryan/RustRoguelike","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:github/nsmryan/RustRoguelike","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsmryan%2FRustRoguelike","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsmryan%2FRustRoguelike/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsmryan%2FRustRoguelike/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsmryan%2FRustRoguelike/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nsmryan","download_url":"https://codeload.github.com/nsmryan/RustRoguelike/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nsmryan%2FRustRoguelike/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31571601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["game","roguelike","rust","sdl2","unity3d"],"created_at":"2026-04-08T20:02:22.954Z","updated_at":"2026-04-08T20:02:24.975Z","avatar_url":"https://github.com/nsmryan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rust Roguelike\n\nThis Rust Roguelike is a Roguelike written in Rust. It is a Roguelike with a\nfocus on movement, use of space, stealth, and some resource management. \nIt has themes of deserts, ancient ruins, mechanisms, and the sun.\n\n\nSome unusual aspects that make this game interesting:\n\n    * Intertile walls- walls that are between two tiles instead of within a tile\n    * A varied movement system which allows slow sneaking movement, normal walking, and running,\n    each with different levels of visibility, levels of noise, movement distance, and capabilities (such as\n    jumping over short walls while running).\n    * A stealth system based on noise level and visiblilty, with various factors effecting LoS.\n    * Unusual classes like 'clockwork', 'monolith', 'grass', or 'heirophant' with their own unique skills.\n    * A control scheme designed around simplicity and immediacy, while also providing a high level of\n      information to the player to allow careful consideration of their moves.\n\n\nThis game is in development. It is not in a playable state- if you run the game you will be able\nto play through levels by finding the goal object, picking it up, and carrying it to the exit,\nbut there is no larger goal or game beyond this.\n\n![Image](resources/doc/background.png)\n![Screenshot](resources/doc/screenshot.png)\n\n## Building\n\nThis is tested on Windows and Linux. On Linux (and likely on a Mac, although\nthis is untested), make sure SDL2 is installed including SDL_ttf and SDL_image.\nOn Windows the repository contains the necessary SDL2 files so no installation is\nrequired.\n\nThen just run:\n```bash\ncargo run\n```\nwhich will download all dependencies and get it running. If you are playing and not developing,\nconsider\n```bash\ncargo run --release\n```\nto get a smoother experience, but note that it will take some time the first time it is\nrun (several minutes).\n\n\nThe make file has some convenience commands as well.\n\n## Gameplay\n\n### Key Map\n\nThere are three gameplay modes: cursor mode, direct mode, and use mode.\n\n\nDirect mode is the usual input mode- the movement keys move the player. In\nthis mode the player can run, walk, and sneak.\n\n\nCursor mode is entered using the 'space' key. In cursor mode the movement keys\nmove a cursor around the map. This cursor can be used to inspect tiles, use skills,\nand throw items. Throwing items is accomplished by holding 'alt' and pressing the \nitem's key.\n\n\nUse mode is entered by pressing an item's key. Once in use mode the player can\nselect any of the highlighted tiles. Each item provides different effects and/or movements.\nThere may be no tiles available until the player is in a particular situation.\n\n#### Movement\n\nMove with the number keys. The arrow keys also work, but do not allow diagonal movement.\nNormal movement leaves the player in the standing stance.\n\nThe number '5' key passes your turn.\n\nIf shift is held when moving, you will run in the target direction. Running makes additional\nnoise, but moves two tiles. Once the player runs they are in the running stance.\n\nIf ctrl is held when moving, you will sneak in the target direction. Sneaking\nmakes less noise then other movements, and leaves the player in the crouching stance.\n\n\n#### Stances\n\nThe player can either be in the crouching, standing, or running stance. If the player\nis crouching then they cannot be seen over intertile walls, but they also cannot see\nover itertile walls. Items may be effected by stance, such as the dagger which\ncan only be used while crouching.\n\nStanding and running both allow line of sight over intertile walls. If you\nare crouching and want to stand, pass your turn without holding ctrl.\nIf you are standing or running and want to crouch, pass your turn while\nholding ctrl.\n\n\n#### Items\n\nItems are mapped to 'z' (first item), 'x' (second item), and 'c' (third item).\nWhen an item is used, you may enter use mode. See the documentation above\nfor information on modes.\n\nItems can be thrown by holding alt and pressing their key while in cursor\nmode. This throws them towards the cursor's location.\n\nItems can be picked up with the 'g' key (to 'get' the item).\n\nItems can be dropped by throwing them on the same tile that the player is on,\nor using them in the '5' direction (the 'pass turn' key).\n\n\n#### Skills\n\nSkills are mapped to 'a' (first skill), 's' (second skill), and 'd' (third skill).\nSkills can be used by pressing their key in cursor mode.\n\nCurrently the classes are selected by pressing 'h', although this is more of\na development system then the final concept. You may select a class from a list\nusing the number keys. Pressing 'h' again will allow you to change classes.\n\nOnce a class is selected, press 'j' to see a list of skills. The skills are mapped\nto 'a', 's', and 'd' in the order that they are shown in the list.\n\nThe classes are roughly as follows:\n\n    * Grass is about stealth and hiding. It allows you to lay down grass which reduces\n      noise, to step quietly using shoes made of grass, and to attack stealily with grass daggers.\n      The Grass class' resource is grass tiles.\n    * Monolith is about stone. It allows crushing and reconstructing walls,\n      and passing through walls. The Monolith class' resource is walls and rubble.\n    * Clockwork is about power and mechanism. It allows you to punch a golem with\n      a power first, pushing them back.\n    * Hierophant is about sight and health. It allows you to view hidden tiles,\n      extend your field of view, and heal your health.\n\n#### Menus\n\nThere are several menus that help you understand the game or select options.\n\nThe 'h' key opens the class menu, allowing you to select a class.\n\nThe 'j' key opens the skill menu, listing your current skills. \n\nThe 'i' key opens the inventory menu, listing your current items. \n\nThe 'q' key opens a menu asking if you would like to quit. Pressing 'q' again will\nquit the game.\n\nThe 'esc' key can be used to exit a menu.\n\n\n#### Other\n\nHolding alt and pressing a directional key will 'interact' with the tile in that direction,\nsuch as to disarm or arm a trap.\n\nThe 'o' key shows an information overlay while it is held. This shows golem Fov, attack positions,\nand other information.\n\nThe 'y' will cause your character to yell, making noise.\n\nThe 'q' key will prompt to exit the game, and pressing 'q' again will exit.\n\nThe 't' key is a debugging key which makes you invincible and shows you the map. It\ncan be pressed again to hide the map.\n\nThe 'p' key is a debugging key which regenerates a new level.\n\nThe '[' and ']' keys are using to rewind and replay turns as a debugging aid.\nSee the section on rewinding time for details.\n\n\n### Sound\n\nThe game has a sound system in which different actions make different amounts of\nsound. The golems may hear a sound and investigate its source, possibly causing them\nto discover the player. Actions like running or yelling make a lot of sound, while\nsneaking and using most skills make little to no sound.\n\nSome skills effect the amount of sound movement takes, and the surface of a tile\ncan dampen sounds (grass), or make them louder (rubble).\n\nBefore taking an action, consider the noise it will make. Golems are formitable\nopponents and alterting them to your presence is usually quite dangerous.\nSound can also be used to your advantage such as when throwing a stone or\nother item to lead a golem away from a position.\n\n\n### Traps\n\nThe game contains traps of various types. Walking on a trap triggers it if the \ntrap is armed. Traps can be disarmed by interacting with them, and then armed\nagain by interacting again.\n\nA disarmed trap can be picked up, allowing the player to carry traps around and\nplace and rearm them.\n\n\n### Triggers\n\nIn addition to traps, there are stationary triggers which cannot be disarmed or\npicked up. These will raise or lower a wall when stepped on, and will raise\nor lower the wall again if stepped off and then stepped on again.\n\n\n## Architecture\n\nThe overall architecture of the game is something like this: there is a\nseries of layers to the game, each of which builds on the layers below.\nThese layers are the core code (roguelike_core) which includes AI, the\nmap data structure and algorithms, the basic types, the messages that\neffect gameplay, and more.\n\nAbove the core code is the engine (roguelike_engine). This includes input events,\ntranslation into messages, and message processing, as well as the 'step' function\nthat steps the game logic forward one turn.\n\nAbove the engine is the user interface. In the tile version of the game this\nis an SDL2 system which receives input, draws to the screen, and handles loading\nresources at startup.\n\n\nThis layering is the static architecture of the code. The dynamic architecture \n(meaning, what happens when the game is running), starts with input events\nfrom SDL2, which are, and translated into an internal InputEvent\nstructure (keypresses, mouse movement, etc) for processing.\n\nThis input event is translated into an action (InputAction) that describes what\nthe input does in the game's current state (without changing its state).\nThis translation is internal to the game, and uses the game's state.\n\nThis input action is provided to the step\\_game function of the cleverly named\nGame structure.  \n\nThe step\\_game function dispatches through the game's current state- playing,\nin a menu, etc. This can change the state of the game, and any settings\n(GameSettings), but does not modify the game's data (GameData). It can only place\nmessages in the message queue that is used to execute a turn of the game.\n\n\nOnce the state system has created its messages, and optionally\nchanged its state, the resolution system starts.  This executes each message- \nusing an item, moving, using a skill, etc, which may in turn spawn more\nmessages- until there are no more messages to process.\n\nMessage processing may set the took\\_turn flag for an entitity, and if the\nplayer is marked as having taken a turn then the other entities in the game get\na chance to spawn messages. These messages are themselves resolved until\nno messages are left.\n\nThis is the only place where game actions occur- there are places that generate\nmaps or do other modifications, but each turn is entirely handled as a sequence\nof messages resolved in order.\n\n\n### Types\n\nThe main structures are: \n\n    * Game: this structure holds the GameData, as well as settings, configuration, logging, random\n    number generation- generally data needed to run the game but not necessarily within the game world.\n        * GameData: this structure is simply an Entities and a Map. It is the core structure of the game,\n            holding the entire game world and all its entities. This structure provides some functions such\n            as FOV which take into account both the map and the entities, where the lower level functions\n            can't use both types of information.\n            * Entities: this structure contains all components, and a vector of ids which identify\n            each entity. The id can be used to index a component to get that entities data if it exists.\n            * Map: this is a grid of Tile structures, with information on blocking movement, sight, the\n            types of surfaces, etc. This structure has many functions for FOV, pathing, floodfill, and others.\n        * Config: the game's static configuration, read from config.yaml.\n        * MsgLog: the message log is used to both print a console log for the user (classic Roguelike style),\n        as well as to drive the game's logic. The messages are processed by the game engine to change game\n        state, as well as provided to the display system to change the display state.\n    * InputAction: the input actions are all actions that the player can perform, including navigating menus\n    or quitting the game.\n    * Msg: the messages put in the message log. This contains all changes that can occur to the game state, \n      including movements, attacks, triggering traps, using skills, and starting and ending a turn.\n    * Input: the state of the input system. This type contains information on modifier keys and which other\n      keys are held, and uses this information to map key presses into inputs to the game.\n    * Display: the display state contains SDL2 types, loaded textures, sprite and animation information, as well\n      as screen layout. It is used in render the game to the screen.\n\n\nThere are a number of ancillary structures such as Vaults for parts of maps, GameSettings for mutable data like\nthe current turn or whether the overlay is on, ProcCmd for controlling level generation, and others.\n\n\n### Design\n\nThere are some design considerations that have a sigificant effect on the game's code. One is that no\npart of the codebase keeps links to other parts- it is all a single big data structure (Game), which is\ntaken apart and passed to functions to mutate it and have side effects. This keeps changes to state\nin constrained locations, which helps with finding the location and sequence of state changes.\n\n\nIn addition, many components do not make changes themselves, but emit structures that are then processed.\nThis allows things like recording actions, and testing components. A good example is the input system\nprocessing inputs to game actions, then to messages, and then finally to changes to the game's state.\n\n\nThe game is also split into layered crates within a workspace, such that the roguelike\\_core knows\nabout the core types, but not how the game is displayed or how maps are generated (for example),\nwhile roguelike\\_engine knows about actions, procedural generation, and handling inputs, but not\ndisplaying or the main loop.\n\n\nFinally roguelike\\_main is the main loop, as well as the SDL2 display system.\nThis is split into display data with the animations, textures, screen layout,\netc, and then a rendering function which does all the drawing to the screen\nusing the display data and game's state (Game).\n\n\nThis split allows roguelike\\_lib to compile a binary that is separate from SDL2\nand can be integrated into other systems like Unity, or wrapped in TCL to\nrun in scripts.\n\n\n### Interesting Internal Features\n\nThere are a number of interesting features that are not necessarily visible\nwhen playing the game.\n\n\n#### Action Logs and Replay\n\nThe game records a list of actions taken by the player, which can be replayed for\ndebugging. This allows bugs to be captured in a log and sent to be debugged, and to\nview replays of games.\n\n\n#### Winding and Rewinding Time\n\nThe game has a simple \"undo/redo\" system, implemented by copying the game state\neach time an action is taken. This is not part of the gameplay, but rather a\ndebugging tool.\n\n\nThese states are kept in a stack, and can be popped off with the '[' key. In\naddition to the game's state, the action that caused a transition between game\nstates is stored, so that when the ']' key is pressed that action is replayed,\nallowing both forward and backwards movement.\n\n\nOne interesting nuance here is that you can rewind the game, take a different\naction, and then replay your old actions on top of the new game. This allows\ndebugging certain situations where one path causes a problem and another does\nnot (like using an item before making a move).\n\n\n#### Command Line Interpreter and rl_engine\n\nThe game has a simple command line interface defined in commands.rs. When\ncompiling the 'engine' version of the game (the one used when running within\nUnity), this is the only interface, while in the SDL2 version of the game this\ninterface is available in addition to the game GUI.\n\n\nThis interface exposes simple commands to list ids, query the map, change\nentity states, add entities, etc. This can be driven by other programs such as\nTCL or Unity. The commands print out results in a simple text format that must\nbe parsed by the calling program. All interaction takes place using stdin and\nstdout.\n\n\nThe rl\\_engine version of the game runs exactly as the SDL2 version internally-\nthe logic is driven by the same input events. The difference is only in the\nsource of those events, and the lack of a UI when running the engine.\n\n\n#### Performance Monitoring\n\nThe game generates performance logs as game.log. These contain some basic\n'spans' such as the time taken for logic, display, waiting for a new frame to\nstart, etc. Additional timers can be added to get more detail.\n\n\nA pyimgui tool called analyzer.py can visualize these traces and plot them for\nanalysis.\n\n#### System Level Testing\n\nIn addition to the usual unit tests, which can be run with 'cargo test', the\ngame has system level tests. These tests are created by starting the game\nwith certain flags that cause it to record the player input and its result.\n\nOnce a test has been recorded, it can be replayed to check that it matches the\noriginal play through. This allows testing of the full game, end to end, and\nto check that certain changes do not effect game play (such as performance improvements\nthat are not intended to be visible to the player).\n\nThe play throughs can be tested individually or can be run all togther. The latter\ncreates a system level checkout. When checking a playthrough, the game will report\nwhether there are new messages, missing messages, or a mismatch of messages.\nThis is helpful in cases where the playthrough is identical, but there are simply\nnew things being reported that do not effect the results.\n\nAs the game is modified, these play throughs will become out of date due to \nvalid changes. To mitigate this situation, which in general requires the user\nto redo all the broken play throughs each time they change, there is an option\nto replay all or one of the recorded games and accept the new results as the\n'golden record', replacing the original playthrough.\n\n\n#### Map Density Heatmap\n\nThe game generates a file called map_emptiness_distribution.txt which contains\ndistribution of how densely populated the map is. This can be turned in to a\nheatmap with 'map_distribution.tcl'.  This information is used for guiding\nprocgen to make sure the maps are not to spare or too dense.\n\nThe map is generated using a floodfill algorithm and counting, for each tile,\nhow many other tile's flood fill reach that tile.\n\n\n#### Wave Function Collapse (WFC)\n\nThe game uses the WFC algorithm internally for map generation. The resources\ndirectory contains some wfc_seed_*.png files. These images contain pixels used\nas input to the map generation algorithm.\n\n\n#### Symmetric Shadowcasting\n\nThe Line of Sight (LoS) algorithm used in this game uses the symmetric shadowcasting algoritm.\nThis is a very nice algorithm for LoS on a grid, and was adapted from a Python version\nand turned into a separate Rust crate for use in this game.\n\n\n#### Vaults\n\nThe game makes use of 'vault' files found in resources/vaults. These files\ncontains small maps in a text format with interesting formations of entities\nand tiles. These are stamped into the map during procgen to create structured\nareas within the otherwise randomly generated maps.\n\n\nThe format of the vaults requires twice the number of character as the number\nof tiles in the resulting map. This allows even tiles to indicate the contents\nof a tile, and odd tiles the intertile walls.\n\n\n#### Map Generation\n\nThe map generation algorithm uses the WFC algorithm mentioned above, and detects\nstructures created by the image that the algorithm outputs. It turns these\nstructures into walls of different types, and uses a configuration file to\ndetermine which items/golems/traps/triggers to generate and in what general\nfrequency.\n\nIt also uses the map density information mentioned above to lay down\ngrass in oppertune locations.\n\n## Building for Development\n\nThe game has been developed in two environments:\n\n### Linux\nneeds sdl2, sdl2_ttf, sdl_image\n\n### Windows\n\nTo develop on Windows, first install MSYS2.\n\nuse the Mingw64 shell (the blue one), and install rust, sdl2, sdl2_ttf, sdl2_image:\n\n```bash\npacman -S mingw-x86_64-rust\npacman -S mingw-x86_64-sdl2\npacman -S mingw-x86_64-sdl2_ttf\npacman -S mingw-x86_64-sdl2_image\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsmryan%2Frustroguelike","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnsmryan%2Frustroguelike","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnsmryan%2Frustroguelike/lists"}