Skip to content

Commit

Permalink
Spelling check run, add intro, README and LICENSE files.
Browse files Browse the repository at this point in the history
  • Loading branch information
thebracket committed Sep 11, 2019
1 parent 00dd243 commit 950a51f
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 12 deletions.
19 changes: 19 additions & 0 deletions .vscode/spellright.dict
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@

roguelikedev
toml
Github
rustup
Greenskins
renderable
destructuring
renderables
libtcod
Moria
spawner
Qud
AoE
enum
Serde
spawners
saveable
serializer
deserializer
8 changes: 8 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Copyright 2019 Herbert Wolverson (DBA Bracket Productions)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Roguelike Tutorial - in Rust

Welcome to the Roguelike Tutorial - in Rust. This is intended to accompany [rltk_rs](https://github.com/thebracket/rltk_rs), my roguelike terminal library for Rust. You can read the ready-formatted version here: [http://bfnightly.bracketproductions.com/rustbook/](http://bfnightly.bracketproductions.com/rustbook/).
4 changes: 4 additions & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Summary

[Introduction](./chapter_0.md)

*Section 1*

- [Chapter 1 - Hello Rust](./chapter_1.md)
- [Chapter 2 - Entities & Components](./chapter_2.md)
- [Chapter 3 - Walking A Map](./chapter_3.md)
Expand Down
25 changes: 25 additions & 0 deletions book/src/chapter_0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Introduction

---

***About this tutorial***

*This tutorial is free and open source, and all code uses the MIT license - so you are free to do with it as you like. My hope is that you will enjoy the tutorial, and make great games!*

*If you enjoy this and would like me to keep writing, please consider supporting [my Patreon](https://www.patreon.com/blackfuture).*

---

Every year, the fine fellows over at [r/roguelikedev](https://www.reddit.com/r/roguelikedev/new/) run a *Tutorial Tuesday* series - encouraging new programmers to join the ranks of roguelike developers. Most languages end up being represented, and this year (2019) I decided that I'd use it as an excuse to learn Rust. I didn't really want to use `libtcod`, the default engine - so I created my own, [RLTK](https://github.com/thebracket/rltk_rs). My initial entry into the series isn't very good, but I learned a lot from it - you can find it [here](https://github.com/thebracket/rustyroguelike), if you are curious.

The series always points people towards an excellent series of tutorials, using Python and `libtcod`. You can find it [here](http://rogueliketutorials.com/tutorials/tcod/). Section 1 of this tutorial mirrors the structure of this tutorial - and tries to take you from zero (*how do I open a console to say Hello Rust*) to hero (*equipping items to fight foes in a multi-level dungeon*). I'm hoping to continue to extend the series.

I also *really* wanted to use an Entity Component System. Rust has an excellent one called Specs, so I went with it. I've used ECS-based setups in previous games, so it felt natural to me to use it. It's also a cause of continual confusion on the subreddit, so hopefully this tutorial can shine some light on its benefits and why you might want to use one.

I've had a **blast** writing this - and hope to continue writing. Please feel free to contact me (I'm `@herberticus` on Twitter) if you have any questions, ideas for improvements, or things you'd like me to add. Also, sorry about all the Patreon spam - hopefully someone will find this sufficiently useful to feel like throwing a coffee or two my way. :-)

---

Copyright (C) 2019, Herbert Wolverson.

---
4 changes: 2 additions & 2 deletions book/src/chapter_11.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ pub fn player(ecs : &mut World, player_x : i32, player_y : i32) -> Entity {
}
```

The new line (`.marked::<SimpleMarker<SerializeMe>>()`) needs to be repeated for all of our spawners in this file. It's worth looking at the source for this chaper; to avoid making a *huge* chapter full of source code, I've omitted the repeated details.
The new line (`.marked::<SimpleMarker<SerializeMe>>()`) needs to be repeated for all of our spawners in this file. It's worth looking at the source for this chapter; to avoid making a *huge* chapter full of source code, I've omitted the repeated details.

## Serializing components that don't contain an Entity

Expand Down Expand Up @@ -659,7 +659,7 @@ gui::MainMenuSelection::LoadGame => {

# Wrap-up

Ths has been a long chapter, with quite heavy content. The great news is that we now have a framework for loading and saving the game whenever we want to. Adding components has gained some steps: we have to register them in `main`, tag them for `Serialize, Deserialize`, and remember to add them to our component type lists in `saveload_system.rs`. That could be easier - but it's a very solid foundation.
This has been a long chapter, with quite heavy content. The great news is that we now have a framework for loading and saving the game whenever we want to. Adding components has gained some steps: we have to register them in `main`, tag them for `Serialize, Deserialize`, and remember to add them to our component type lists in `saveload_system.rs`. That could be easier - but it's a very solid foundation.

**The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-11-loadsave)**

Expand Down
10 changes: 5 additions & 5 deletions book/src/chapter_2.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This chapter will introduce the entire of an Entity Component System (ECS), whic

## About Entities and Components

If you've worked on games before, you may well be used to an object oriented design (this is very common, even in the original Python libtcod tutorial that inspired this one). There's nothing really wrong with an object-oriented (OOP) design - but game developers have moved away from it, mostly because it can become quite confusing when you start to expand your game beyond your original design ideas.
If you've worked on games before, you may well be used to an object oriented design (this is very common, even in the original Python `libtcod` tutorial that inspired this one). There's nothing really wrong with an object-oriented (OOP) design - but game developers have moved away from it, mostly because it can become quite confusing when you start to expand your game beyond your original design ideas.

You've probably seen a "class hierarchy" such as this simplified one:

Expand All @@ -31,7 +31,7 @@ You'd probably have something more complicated than that, but it works as an ill

Entity Component based design tries to eliminate the hierarchy, and instead implement a set of "components" that describe what you want. An "entity" is a *thing* - anything, really. An orc, a wolf, a potion, an Ethereal hard-drive formatting ghost - whatever you want. It's also really simple: little more than an identification number. The magic comes from entities being able to have as many *components* as you want to add. Components are just data, grouped by whatever properties you want to give an entity.

For example, you could build the same set of mobs with components for: Position, Renderable, Hostile, MeleeAI, RangedAI, and some sort of CombatStats component (to tell you about their weaponry, hit points, etc.). An Orc Warrior would need a position so you know where they are, a renderable so you know how to draw them. It's Hostile, so you mark it as such. Give it a MeleeAI and a set of game stats, and you have everything you need to make it approach the player and try to hit them. An Archer might be the same thing, but replacing MeleeAI with RangedAI. A hybrid could keep all the components, but either have both AIs or an additional one if you want custom behavior. If your orc becomes friendly, you could remove the Hostile component - and add a Friendly one.
For example, you could build the same set of mobs with components for: `Position`, `Renderable`, `Hostile`, `MeleeAI`, `RangedAI`, and some sort of CombatStats component (to tell you about their weaponry, hit points, etc.). An Orc Warrior would need a position so you know where they are, a renderable so you know how to draw them. It's Hostile, so you mark it as such. Give it a MeleeAI and a set of game stats, and you have everything you need to make it approach the player and try to hit them. An Archer might be the same thing, but replacing MeleeAI with RangedAI. A hybrid could keep all the components, but either have both AIs or an additional one if you want custom behavior. If your orc becomes friendly, you could remove the Hostile component - and add a Friendly one.

In other words: components are just like your inheritance tree, but instead of *inheriting* traits you *compose* them by adding components until it does what you want. This is often called "composition".

Expand All @@ -41,7 +41,7 @@ For small games, an ECS often feels like it's adding a bit of extra typing to yo

That's a lot to digest, so we'll look at a simple example of how an ECS can make your life a bit easier.

## Includings Specs in the project
## Including Specs in the project

To start, we want to tell Cargo that we're going to use Specs. Open your `Cargo.toml` file, and change the `dependencies` section to look like this:
```toml
Expand Down Expand Up @@ -148,7 +148,7 @@ gs.ecs.register::<Position>();
gs.ecs.register::<Renderable>();
```

What this does is it tells our `World` to take a look at the types we are giving it, and do some internal magic to create storage systems for each of them. Specs has made this easy; so long as it implemenets `Component`, you can put anything you like in as a component!
What this does is it tells our `World` to take a look at the types we are giving it, and do some internal magic to create storage systems for each of them. Specs has made this easy; so long as it implements `Component`, you can put anything you like in as a component!

## Creating entities

Expand Down Expand Up @@ -562,7 +562,7 @@ This function takes the current game state and context, looks at the `key` varia
player_input(self, ctx);
```

If you run your progam (with `cargo run`), you now have a keyboard controlled `@` symbol, while the smiley faces zoom to the left!
If you run your program (with `cargo run`), you now have a keyboard controlled `@` symbol, while the smiley faces zoom to the left!

![Screenshot](./c2-s3.gif)

Expand Down
2 changes: 1 addition & 1 deletion book/src/chapter_3.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Specs includes a concept of "resources" - shared data the whole ECS can use. So
gs.ecs.insert(new_map());
```

The map is now available from anywhere the ECS can see! Now inside your code, you can access the map with the rather unwieldy `let map = self.ecs.get_mut::<Vec<TileType>>();`; it's available to systems in an easier fasion.
The map is now available from anywhere the ECS can see! Now inside your code, you can access the map with the rather unwieldy `let map = self.ecs.get_mut::<Vec<TileType>>();`; it's available to systems in an easier fashion.

## Draw the map

Expand Down
4 changes: 2 additions & 2 deletions book/src/chapter_5.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This chapter starts with the code from chapter 4.

# Map refactor

We'll keep map-related functions and data together, to keep things clear as we make an ever-more-complicated game. The bulk of this is createing a new `Map` structure, and moving our helper functions to its implementation.
We'll keep map-related functions and data together, to keep things clear as we make an ever-more-complicated game. The bulk of this is creating a new `Map` structure, and moving our helper functions to its implementation.

```rust
extern crate rltk;
Expand Down Expand Up @@ -273,7 +273,7 @@ There's quite a bit here, and the viewshed is actually the simplest part:

* We've added a `ReadExpect<'a, Map>` - meaning that the system should be passed our `Map` for use. We used `ReadExpect`, because not having a map is a failure.
* In the loop, we first clear the list of visible tiles.
* Then we call RLTK's `field_of_view` function, providing the starting point (the location of the entity, from `pos`), the range (from the viewshed), and a sligthtly convoluted "dereference, then get a reference" to unwrap `Map` from the ECS.
* Then we call RLTK's `field_of_view` function, providing the starting point (the location of the entity, from `pos`), the range (from the viewshed), and a slightly convoluted "dereference, then get a reference" to unwrap `Map` from the ECS.

This will now run every frame (which is overkill, more on that later) - and store a list of visible tiles.

Expand Down
2 changes: 1 addition & 1 deletion book/src/chapter_7.md
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ Let's replace `RunState` with something more descriptive of each phase:
pub enum RunState { AwaitingInput, PreRun, PlayerTurn, MonsterTurn }
```

If you're running Visual Studio Code with RLS, half your project just turned red. That's ok, we'll refactor one step at a time. We're going to *remove* the runstate altogether from the main `GameState`:
If you're running Visual Studio Code with RLS, half your project just turned red. That's ok, we'll refactor one step at a time. We're going to *remove* the `RunState` altogether from the main `GameState`:

```rust
pub struct State {
Expand Down
2 changes: 1 addition & 1 deletion book/src/chapter_8.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ ctx.set_bg(mouse_pos.0, mouse_pos.1, RGB::named(rltk::MAGENTA));

This sets the background of the cell at which the mouse is pointed to magenta. As you can see, mouse information arrives from RLTK as part of the context.

Now we'll introduct a new function, `draw_tooltips` and call it at the end of `draw_ui`. New new function looks like this:
Now we'll introduce a new function, `draw_tooltips` and call it at the end of `draw_ui`. New new function looks like this:

```rust
fn draw_tooltips(ecs: &World, ctx : &mut Rltk) {
Expand Down

0 comments on commit 950a51f

Please sign in to comment.