finish first post

parent 39e9e66b
......@@ -5,22 +5,20 @@ draft: false
tags: ["game", "roguelike", "programming"]
---
# This post is still a work in progress
### Introduction
## Introduction
A few weeks ago I began working on a roguelike game.
It's something that I had wanted to do for quite a while, but could never find the time.
I'm learning Rust right now and the best way for me to do that is to find a project that I care about.
It is something that I have wanted to do for quite a while, but could never find the time.
I am learning Rust right now and the best way for me to do that is to find a project that I care about.
So, this is a perfect opportunity finally make a roguelike.
Before I really started working on the roguelike I wanted to make prototypes of a few different systems that I though would be needed.
Before I rushed into it I wanted to make prototypes of a few different systems that I though would be needed.
I wanted to make some sort of name generator, map generator, and find a good library to use for graphics.
### Name Generator
## Name Generator
The most common solution I found to name generation was to get a bunch of names I like, stick them in a Markov chain, and generate names with it.
This seemed to work well enough for me.
### Map Generator
## Map Generator
After reading about a bunch of different map generation algorithms I decided to use the alogorithm described by Bob Nystrom [here](http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/).
![](/img/maze_map_pt1.png)
......@@ -35,20 +33,20 @@ After reading about a bunch of different map generation algorithms I decided to
![](/img/maze_map_pt4.png)
4. remove the dead ends of the mazes
It still needed some tweaking to make the paths less windy and to avoid connections being placed right next to each other, but it was good enough to start working with and I could fix it later.
I have made some tweaks to the maze fill algorithm to reduce the windy-ness since these screenshots were taken, but I didn't want to pull out my current generator and make a wrapper to output each step again.
### Graphics Library
## Graphics Library
While trying out some of the different rust terminal libraries I came across a talk by Josh Ge from Roguelike Celebration ["How to Make a Roguelike"](https://www.youtube.com/watch?v=jviNpRGuCIU).
This led me to the [r/roguelikedev](https://www.reddit.com/r/roguelikedev) community and a [rust version of the libtcod tutorial](https://tomassedovic.github.io/roguelike-tutorial/).
### Early Development
I went through the first four parts of the tutorial to get familiar with the basics of libtcod and to get some ideas for how I want things to be structured.
## Roguelike Tutorial
I went through the first few parts of the tutorial to get familiar with the basics of libtcod and to get some ideas for how I want things to be structured.
I then made some changes so that it would be easier to add things in the future.
### Generic Objects
I liked the idea of using a generic object system from the tutorial, but I didn't like the idea of having to write a new function for each object and tile.
I created ObjectStore and TileStore structs that would load object and tile definitions from json files on creation.
When I need to add a new object or tile it's just a new line in a json file instead of a new function and recompile (which can be very slow in rust).
## Generic Objects
I liked the idea of using a generic object system from the tutorial, but I did not like the idea of having to write a new function for each object and tile.
I created `ObjectStore` and `TileStore` structs that would load object and tile definitions from json files on creation.
When I need to add a new object or tile it is just a new line in a json file instead of a new function and recompile (which can be very slow in rust).
player object definition
```json
......@@ -57,7 +55,7 @@ player object definition
"color":{"r":255,"g":255,"b":255},
"blocks":true,"alive":true,"open_doors":true,
"fighter":{"max_hp":30,"hp":30,"defense":2,"power":5}
},
}
```
wall tile definition
```json
......@@ -68,28 +66,125 @@ wall tile definition
}
```
### Map Generator Trait
<!-- ### Map Generator Trait
I knew that I would need more than just one map generator so I made a trait for map generation and moved my existing map generation code to a MazeMap struct.
```rust
pub trait MapGenerator {
fn generate(&mut self, tile_store: &TileStore, object_store: &ObjectStore, floor: i32) -> ((i32, i32), Vec<Vec<Tile>>);
fn generate(&mut self, tile_store: &TileStore, object_store: &ObjectStore, floor: i32) -> ((i32, i32), Vec<Vec<Tile>>);
}
``` -->
## Event System
I made an `Event` enum that would be returned from many of the `Object` methods.
Example: The `Object` move method can return one or more `Moved`, `ReplaceTile`, `Attack`, or `Message` Events.
```rust
pub enum Event {
// x, y, tile
ReplaceTile(i32, i32, Tile),
// x, y
Moved(i32, i32),
// x, y, dx, dy
Moving(i32, i32, i32, i32),
// x, y, type, amount
Attack(i32, i32, String, i32),
// type, amount
TookDamage(String, i32),
// x, y, name
Died(i32, i32, String),
// player quit
Exit,
SkippedTurn,
Message(String),
// player used up stairs
GoUp,
// player used down stairs
GoDown,
}
```
### Event System
added event system
## Traits
I defined traits for things that I knew would need to be changed in the future.
```rust
pub trait MapGenerator {
fn generate(&mut self, tile_store: &TileStore,
object_store: &ObjectStore,
floor: i32) -> ((i32, i32), Vec<Vec<Tile>>);
}
pub trait Renderer {
fn draw_tile(&mut self, x: i32, y: i32, color: Color);
fn draw_char(&mut self, x: i32, y: i32, char: char, color: Color);
fn draw_bar(&mut self, x: i32, y: i32, width: i32, label: String,
value: i32, max: i32, foreground: Color, background: Color);
fn draw_message(&mut self, x: i32, y: i32, message: &String);
fn clear_panel(&mut self);
fn clear_xy(&mut self, x: i32, y: i32);
fn clear(&mut self);
fn show(&mut self);
fn closed(&self) -> bool;
fn cleanup(&mut self);
fn is_fullscreen(&self) -> bool;
fn set_fullscreen(&mut self, fullscreen: bool);
fn get_key(&mut self) -> Key;
}
pub trait AI {
fn take_turn(&self, x: i32, y: i32, map: &Map,
object_store: &ObjectStore) -> Vec<Event>;
}
```
The current implementations of each trait are:
| Trait | Implementation | Description |
| --- | --- | --- |
| MapGenerator | MazeMap | The algorithm described above |
| MapGenerator | CaveMap | Cellular Automata method described [here](http://www.roguebasin.com/index.php?title=Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels) |
| Renderer | TcodRenderer | Implementation for libtcod |
| Renderer | TermionRenderer | Implementation for termion (terminal ui library) |
| AI | RandomAI | Randomly moves around and attacks |
## Game Loop
My game loop is currently:
1. Render all of the tiles, objects, and ui elements (stats and messages)
1. Update player effects (currently just regenerate health)
1. Handle controls and return events from player actions
1. Run AI for each npc object
1. Process events returned by player and npc objects
- Replace tiles (happens when a door is opened)
- Apply damage to objects
- Go up or down a level
1. Add all messages to the message log
## Changing Levels
I have created a `MapStore` struct that contains a `HashMap<i32, Map>` and added a `HashMap<i32, Vec<Object>>` to the `ObjectStore` to store the map and objects for each level.
When the player uses an up or down stairs I store the current map and objects, check if data exists for the new level, and either retrieve it if it does or generate it if it does not.
I am now trying to decide what I want to do about levels after the player leaves them.
The options I am thinking about right now are:
- Do not do anything, keep things as they were when the player was last on the level (current behavior)
This is the least work, but I am not sure it would make for the best gameplay.
- Continue processing events for all existing levels
This would allow me to have npcs change level to chase the player or run away.
Depending on how much stuff is going on this could also kill performance (dwarf fortress fps death!).
- Continue processing events for just the previous, current, and next levels
Would still let me have npcs change levels, but without as much of a performance hit.
### AI
added move randomly ai
Also, I am wondering if I should pregenerate the maps and npcs intead of doing it when the player reaches a new level.
### Renderer trait
added renderer trait
### Termion Renderer
added termion implementation of renderer trait
## TODO
This week I will be working on the ui. I want to add a ui struct on top of the Render trait so that I don't have have every renderable item keep track of its position on screen.
### Cave Generator
added cave generator
This is where I am at right now. I made this post so that I could put my thoughts in one place and hopefully get some advice on different aspects that I am having trouble with.
### Keys and Colors
removed most tcod imports outside of renderer
\ No newline at end of file
Here are some screenshots of the current game
![](/img/maze_map.png)
![](/img/cave_map.png)
\ No newline at end of file
......@@ -85,6 +85,10 @@
......
......@@ -88,6 +88,10 @@
......
......@@ -17,9 +17,10 @@
<pubDate>Sat, 03 Nov 2018 22:53:40 -0500</pubDate>
<guid>https://blog.csos95.com/blog/untitled_roguelike/</guid>
<description>This post is still a work in progress Introduction A few weeks ago I began working on a roguelike game.
It&amp;rsquo;s something that I had wanted to do for quite a while, but could never find the time.
I&amp;rsquo;m learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.</description>
<description>Introduction A few weeks ago I began working on a roguelike game.
It is something that I have wanted to do for quite a while, but could never find the time.
I am learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.
Before I rushed into it I wanted to make prototypes of a few different systems that I though would be needed.</description>
</item>
</channel>
......
This diff is collapsed.
......@@ -89,6 +89,10 @@
......
......@@ -17,9 +17,10 @@
<pubDate>Sat, 03 Nov 2018 22:53:40 -0500</pubDate>
<guid>https://blog.csos95.com/blog/untitled_roguelike/</guid>
<description>This post is still a work in progress Introduction A few weeks ago I began working on a roguelike game.
It&amp;rsquo;s something that I had wanted to do for quite a while, but could never find the time.
I&amp;rsquo;m learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.</description>
<description>Introduction A few weeks ago I began working on a roguelike game.
It is something that I have wanted to do for quite a while, but could never find the time.
I am learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.
Before I rushed into it I wanted to make prototypes of a few different systems that I though would be needed.</description>
</item>
</channel>
......
......@@ -17,9 +17,10 @@
<pubDate>Sat, 03 Nov 2018 22:53:40 -0500</pubDate>
<guid>https://blog.csos95.com/blog/untitled_roguelike/</guid>
<description>This post is still a work in progress Introduction A few weeks ago I began working on a roguelike game.
It&amp;rsquo;s something that I had wanted to do for quite a while, but could never find the time.
I&amp;rsquo;m learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.</description>
<description>Introduction A few weeks ago I began working on a roguelike game.
It is something that I have wanted to do for quite a while, but could never find the time.
I am learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.
Before I rushed into it I wanted to make prototypes of a few different systems that I though would be needed.</description>
</item>
</channel>
......
......@@ -88,6 +88,10 @@
......
......@@ -17,9 +17,10 @@
<pubDate>Sat, 03 Nov 2018 22:53:40 -0500</pubDate>
<guid>https://blog.csos95.com/blog/untitled_roguelike/</guid>
<description>This post is still a work in progress Introduction A few weeks ago I began working on a roguelike game.
It&amp;rsquo;s something that I had wanted to do for quite a while, but could never find the time.
I&amp;rsquo;m learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.</description>
<description>Introduction A few weeks ago I began working on a roguelike game.
It is something that I have wanted to do for quite a while, but could never find the time.
I am learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.
Before I rushed into it I wanted to make prototypes of a few different systems that I though would be needed.</description>
</item>
</channel>
......
......@@ -17,9 +17,10 @@
<pubDate>Sat, 03 Nov 2018 22:53:40 -0500</pubDate>
<guid>https://blog.csos95.com/blog/untitled_roguelike/</guid>
<description>This post is still a work in progress Introduction A few weeks ago I began working on a roguelike game.
It&amp;rsquo;s something that I had wanted to do for quite a while, but could never find the time.
I&amp;rsquo;m learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.</description>
<description>Introduction A few weeks ago I began working on a roguelike game.
It is something that I have wanted to do for quite a while, but could never find the time.
I am learning Rust right now and the best way for me to do that is to find a project that I care about. So, this is a perfect opportunity finally make a roguelike.
Before I rushed into it I wanted to make prototypes of a few different systems that I though would be needed.</description>
</item>
</channel>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment