Back

Hands-On Rust: Effective Learning Through 2D Game Development and Play

248 points13 hourspragprog.com
halvnykterist10 hours ago

I can't help but be heavily skeptical of approaches to a (traditional) roguelike that use ECS. The idea is very entrenched in the rust gamedev community, but for a turn based tile based game there's extremely little benefit and a lot of added complexity. Bob Nystrom has an excellent talk on roguelike architecture [0] and rust as a language itself doesn't prevent any of these approaches. If anything, the existence of sum types as enums make many of them all the more powerful.

[0]: https://www.youtube.com/watch?v=JxI3Eu5DPwE

cardanome8 hours ago

ECS is for me the natural way to design games. I wouldn't even know to design them any other way.

I started game dev with love2d which is a pretty minimalist framework. When I participated in a game jam, I needed a very flexible system that would allow for quick prototyping and would handle many different entities. I ended up writing something which I later realized would be an ECS system. It worked great and I would copy it over for other games.

I know there is that ECS-faction that is talking about performance benefit and stuff but honestly I don't care. I don't even know most of the terminology these people use. I just use ECS to structure my code while being very flexible. I use OO in other domains but it would never occur to me to structure games that way. OO just feels way to brittle for a domain where you do lot's of experimentation and can't really know what you will need and how your entities might end up looking.

pjmlp6 hours ago

ECS and OOP are sides of the same coin, although apparently it is only visible to those that read SIGPLAN papers.

"Component Software: Beyond Object-Oriented Programming"

https://www.amazon.com/-/en/Clemens-Szyperski/dp/0201745720

One of the first publications on the matter.

glowcoil2 hours ago

> There has been an explosive growth in component software technologies since the first edition of this classic book was published. The advent of EJB, J2EE, CORBA 3, COM+ and the .NET framework are evidence of a maturing market in component software that goes 'beyond OOP'.

This book seems to be discussing distributed object systems, which is a sense of the word "component" that has little or nothing to do with the sense used by game developers in reference to the ECS architecture. Distributed object systems are designed to enable an object-oriented design philosophy to be used for a system which spans multiple address spaces or machines. The entity-component-system architecture is a methodology for organizing data layout and program functionality, usually within a single address space on a single machine, where the data associated with a given entity is spread across multiple components or subsystems and associated by index relations (much like a relational database), rather than being all grouped together in one place (as encouraged in OOP).

These two concepts (distributed object systems and ECS) are designed to solve different problems, they are generally used in different scenarios, and they apply at different levels of system organization. There is so little resemblance between the two that I have to conclude someone calling them "sides of the same coin" is either completely unfamiliar with one of them or is being deliberately misleading.

+1
pjmlp51 minutes ago
dgb233 hours ago

Not sure I get what you mean. As I see it, ECS has more of a relational character. Feels more like data pipeline than operations/messages on objects. I think the mental model matters the most here and that depends on how you think of objects. But then any attempt of defining OO objectively seems to be futile, there are conflicting historical and contemporary notions plus a whole bunch of jargon on top, depending on who you're asking.

As an example you could say that Scheme is more object oriented than Java or vice versa and there would be valid, typically cultural reasons for each.

In terms of ECS what kind of happens is that, yes, you have a model of an entity and can think of that as an object, but that is a projection of a set of components or a relation. You're not really talking to the entity as a whole all that much anymore. And it's not just "it satisfies this set of interfaces" either. Your systems literally define data transformations, each on a focused set of related components that matter to a system, which seems kind of the inverse of hiding data behind object interfaces.

pjmlp2 hours ago

That is when data oriented programming gets into the equation.

Classical ECS as it originally appeared on the literature is coding against interfaces, COM or Objective-C protocols style.

So yeah, one composes those interfaces together, there is no class inheritance, only composition, delegation, and a system is composed from a jungle of such components.

It is also a reason why DirectX is COM based, instead of basic Win32 calls.

modernerd9 hours ago

I think Jonathan Blow's take is right:

> ECS only starts to make sense when you are big enough to have multiple teams, with one team building the engine and the other using the engine to make the game; or you are an engine company and your customer makes the game. If that is not your situation, do not rathole. https://twitter.com/Jonathan_Blow/status/1427358365357789199

Most of the arguments I've seen for ECS in Rust suggest it helps to work with memory management/borrowing. For example, here's Patrick Walton's take:

> There's a reason why Rust game engines all use ECS and it's not just because the traditional Unity OO style is out of fashion. It's because mutable everywhere just doesn't work in Rust. Mutex and RefCell explosion. https://twitter.com/pcwalton/status/1440519425845723139.

And here's Cora Sherratt's discussion of ECS options in Rust:

> So why do you need one? Well all ECS developers will claim it’s largely about performance, and show you a mountain of numbers to back it up. The more honest answer probably comes down to the difficulty of making ownership work in Rust without some type of framework to manage the transfer of ownership for you. Rust punishes poor architecture, so ECS’ are here to help. https://csherratt.github.io/blog/posts/specs-and-legion/ (This post also has the best visualisation and explanation of an ECS I've read.)

I've read Hands-On Rust and you could definitely implement the game without an ECS. But at the same time it was useful to play with that pattern because it's in common usage in the Rust community. (Bevy also makes heavy use of it, for example, where it feels pretty lightweight because they made some good design decisions: https://bevyengine.org/news/bevys-first-birthday/#bevy-ecs.)

halvnykterist9 hours ago

I think the idea that you need something like ECS to deal with mutability everywhere is a misconception. Traditional architectures you'd use in C or C++ are all going to more or less have a tree-based ownership graph, and these translate very well to Rust. Long-lived pointers to things that you don't own are a great way to get UAF errors or similar, and having a collection of entities you can look up by ID is a common pattern to use outside of ECS. > But at the same time it was useful to play with that pattern because it's in common usage in the Rust community. And in doing so it perpetuates it. ECS is a good solution for lots of problems (in particular I don't agree with jblow's take) but parading it as _the_ way to make games in Rust feels a lot like how OOP has been championed in the past. If you're going to teach someone how to make games in Rust, doing with extra patterns that don't add much other than complexity (in this case) doesn't seem like a good strategy for teaching or introducing people to the language.

moth-fuzz46 minutes ago

This is an interesting happenstance in the Rust community that I think is largely cultural rather than technical. Backlash against some figurative idea of OOP is popular. ECS is popular as the messianic retort to that OOP figure. But when you look at it from an architectural standpoint, ECS is quite possibly one of the hardest things to do in Rust compared to other designs. Let me get this straight - you want to avoid shared mutability but you have all your gamestate in centralized stores? That systems will necessarily have to have shared, mutable access to? Possibly concurrently? I think it's a good idea architecturally, but also I think it's a tough problem to solve, and I think the claims that Rust lends itself to that architecture are false. It's even tougher in Rust than in other languages, I'd say. And though I've read the source code to many Rust ECS libraries, they all do it in different ways, and all of them feel like hacks.

I definitely feel like the most "rustic" way to do game design, just based on what's easy to do in the language itself without resorting to workarounds, is to have individual actors maintain their individual state, and then have a common interface via a trait that would call update() or render() virtually in a loop or whatever. Then have them message each other via mpsc channels. That's pretty much rust straight from the book, and, it's also a bog standard GameObject architecture straight outta the 2000s.

kvark8 hours ago

Rust has ways to deal with mutability. Three-rs [1] uses a classic scene graph tree, like ThreeJS. It's based on Froggy [2], which is a general low level primitive for building a "traditional" topology of the classes.

[1] https://github.com/three-rs/three [2] https://github.com/kvark/froggy

dgb233 hours ago

I really like Jonathan Blow, but I sometimes wish he would substantiate these kind of claims more so an outsider could learn what he is actually saying and why. I've watched a lengthy video of his on that topic but I didn't get out anything other than "you don't need it". No concrete implementation cases where it gets in the way or how a category of problems is better modeled in a different way.

cardanome2 hours ago

I am beginning to suspect people like him because he speaks slowly with lots of repetition and in a relatively accessible way.

Sure he might have lot's of valuable experience but every video I have watched of him was like a 1 hour rambling opinion piece which could be 3 minutes of actual content.

His video reaction to the rustconf ECS video had some good points but they were very nitpicky and not really justifying the length of the video at all.

modernerd1 hour ago

On why ECS gets in the way for him:

> Because it is far more complicated, thus takes far more work, than what you actually need to do. That work has a large opportunity cost. https://twitter.com/Jonathan_Blow/status/1427378984145154048

To me this has more nuance than, “you ain't gonna need it”. I don't think “concrete implementations” would do all that much to strengthen his argument that unnecessary complexity gets in the way of shipping for indie devs:

> Even 10% friction more than I ever had would have killed me. I wouldn't have been able to make the things I had. Even 5% more friction would have been really bad. https://youtu.be/4t1K66dMhWk?t=3635

And…

> I have, several times, built games where I barely managed to finish. … I've just experienced that too many times to increase friction. I need to decrease friction. https://youtu.be/4t1K66dMhWk?t=3072

And again, in relation to entities rather than Rust's borrow checker:

> If you are trying to focus on the way your entities are set up, you are mis-directing your effort and that's going to make it harder. Try to solve the problem that makes your game interesting. What is it about the gameplay that makes it interesting … that users can see? Focus on that, solve those problems. https://www.youtube.com/watch?v=w7W3xM2tzRA

On what he uses instead of ECS/components in his engines:

> One struct per entity type, with a base struct that is common to all of them. https://twitter.com/Jonathan_Blow/status/1427376307453665280

dkersten4 hours ago

ECS is entrenched in rogue development in general, at least going by r/roguelikedev. It (or at least a component architecture, if not fully blown ECS) seems to be a good fit since these style of games tend to have a lot of composition (in items, effects, behaviour).

Personally, while my experience is a bit limited, I quite like the ECS style. It just makes logical sense to me as a way of composing entities from different parts. The implementation details (cache friendliness or whatever) are not important to me since I've never made anything of a scale where it matters, but that style of developing/designing how things act and interact is logical to me personally. I haven't watched Bob Nystrom's talk yet though (or, actually, I may have, it seems familiar, but I don't remember any details. I plan to watch it tonight).

With that said, many people find the Godot style more natural and it certainly is nice too.

codetrotter3 hours ago

I’ve not yet used Godot. What is the Godot style like? And are there some documents about it and example code of it?

verdagon4 hours ago

Indeed, ECS might not be a good fit for turn-based games.

We explored the topic quite thoroughly in [0] and came to the conclusion that Roguelikes are more suited for something in-between ECS and OO, named just "EC".

ECS is better suited to real-time games, or games which have a lot of iteration over large arrays and parallel (not as in multi-threading, but as in, batchable) computations, where ECS can really shine due to its data layout. Most turn-based games like roguelikes don't iterate over large arrays in the same way.

With EC on the other hand, you're a little more free to group components into their parent entity, and use interfaces (traits), which can make things more understandable.

Whether idiomatic Rust likes EC is an open question though. Idiomatic Rust tends to dislike heap allocation and virtual dispatch, both which can make life a lot easier for Roguelike games, which tend to prioritize flexibility and features, and don't need the data-oriented optimization.

Additionally, a lot of people suggest using ECS in Rust because that's the only architecture that the borrow checker doesn't fight you in, for various reasons.

[0]: https://www.reddit.com/r/roguelikedev/comments/i3xekn/ec_vs_...

brundolf27 minutes ago

> Idiomatic Rust tends to dislike heap allocation and virtual dispatch

Maybe Rust the way most people end up writing it, but Rust the language has no issue with these things. I think the idioms come more from the fact that Rust empowers you to avoid these things, not that it's poorly-suited to them.

nulldata5 hours ago

ECS might have a higher initial complexity overhead, but once you scale up, ECS can really help you keep complexity at bay.

There's a great talk [0] from the Overwatch developers where they talk about how they built Overwatch using the ECS architecture. They barely mention performance at all, but instead talk about how it helped deal with complexity.

[0] https://www.gdcvault.com/play/1024001/-Overwatch-Gameplay-Ar...

bcrosby955 hours ago

I've coded MUDs for about 25 years now, and I use a lot of these patterns in my code. Nice to see someone else thinks its useful.

I think a key strategy that is not touched on too much in the talk is flexibility in your effect system, whatever your effect system may be. It should be trivial to take an effect (heal, damage, stat boost, etc) and let anything in your game apply it to actors with just a few lines of code: items, spells, tiles, regions, the whole game, etc.

As an example, lots of games will specifically give certain classes hps/mana/better chance to hit/new skills as they gain levels.

I just use my effect system for this. Now I can have items that give skills too, because items use the same effect system.

dkersten4 hours ago

Do you know of any articles or resource that go into your style a bit deeper? I'd love to hear more on how your effects system works and how that compares to a component-based or ECS architecture.

thebracket8 hours ago

(Author here) Bob makes some good points, so I'd like to share my $0.02 on the ECS debate. The posters below who point out that a lot of Rust setups use ECS to avoid mutability issues are correct (although internally Bevy is an ECS that maps its own node graph) - and that certainly helps - but it's not the whole picture.

I think it's important to separate the EC from the S in ECS. Entity-Component storage is basically a fast, in-memory database. It's a great way to store global state, and provides for really efficient querying. Using it as a database gives you some advantages:

* Composition over inheritance (especially in Rust, which doesn't really have inheritance - although you can fake it with traits). It becomes easier to glue on new functionality without realizing that you need to rearrange your object tree, and there's real performance boosts to not doing virtual function calls or dynamic casting to see what an object is.

* Replication; if you want to replicate state across multiple nodes, a good ECS can really help you.

* Mutability; as mentioned above, you don't need mutable access to everything at all times, and your code is definitely safer if you have explicit mutability control.

* Surprising flexibility; Rust EC setups typically let you put anything into a component. I have one slightly crazy setup that stores an Option<Enum> as a component with the enum featuring a number of different union setups.

So what about systems? Sometimes systems have some real advantages:

* For simulation type games, it's great to be able to add a simulation feature and have it apply everywhere. For example, when I added gravity to Nox Futura it instantly worked for player characters, NPCs, and objects. (It also worked on flying creatures, killing them instantly - but I fixed that).

* It really helps with parallelism. Your systems declare the data to which they will write, allowing the ECS to order your systems in such a way that you get parallelism without having to think about it too much (especially in Rust).

* If you're in a team, it's a great way to break out work between team-members.

* It's often helpful for finding bugs, because functionality of one type is localized to that system. You can get the same result by being careful in a non-system setup.

Sometimes, systems aren't so great. It can be really tricky to ensure that linked events occur in the correct order. You can make a bit of a mess when you want something to work one way for one type of entity and another for a different type.

But here's the thing: the systems part is optional. You can easily have your main loop query the EC data-storage directly and work like a traditional game loop - without losing the benefits of the storage mechanism. If you prefer, you can attach methods to components and call those. Or you can build a message-passing system and go that way. There's no real right way to do it. Once you've got the hang of your ECS's query/update model, you can tailor the game logic however you want. (I happen to like systems, but that's a personal choice more than a "you must do this" belief).

(Edit: My formatting was awful, sorry.)

halvnykterist7 hours ago

> Composition over inheritance (especially in Rust, which doesn't really have inheritance - although you can fake it with traits)

This does not require ECS, you can happily have something like

  struct Entity {
      components: Vec<Box<dyn Component>>,
  }
(Nor do I think this is a good way of setting up a traditional roguelike)

> Replication; if you want to replicate state across multiple nodes, a good ECS can really help you

I'm not sure what you exactly mean by nodes here, but making something serializable in Rust for easy replication is hardly an issue when we have access to tools like serde.

> Mutability; as mentioned above, you don't need mutable access to everything at all times, and your code is definitely safer if you have explicit mutability control

Addressed above, but while ECS solves the mutability issue it's not a unique way of solving it and bringing it in to deal with that is overkill at the very least.

> Surprising flexibility; Rust EC setups typically let you put anything into a component.

Again, you can do this with regular old components too. This is also an oversold feature of components / mixins / anything like this in general, I think. You can never "just add a component", you need to fix all the issues that come with that, like making sure that gravity doesn't kill your birds.

> For simulation type games, it's great to be able to add a simulation feature and have it apply everywhere.

Yes, but that's not what a turn based tile based game is. Generally you want to iterate over things in order - gravity (if a roguelike has such a thing) gets applied on the player's turn, and only for the player. If you step over a ledge you don't wait for the "gravity" system to kick in and apply gravity to all entities, it is resolved in the same instant for only the entity that has just moved

> It really helps with parallelism.

Sure, although gameplay logic is not what's going to have to be parallel in a roguelike. Building up pathfinding maps and similar is useful to do in parallel, but ECS doesn't really help you with that.

> If you're in a team, it's a great way to break out work between team-members.

Not a particular strength of ECS, and if anything I could see issues arising from the fact that you basically have dynamic typing when it comes to what behaviors an entity has.

> But here's the thing: the systems part is optional.

If you're not doing query-based ECS with systems there's also no particular reason to not use vecs of components within entity structs.

I believe what you're doing here is adding a bunch of complexity to something that could be much simpler, and it really does the language a disservice.

As a final note, in the excerpt about items you have this justification for not using an enum instead of components:

  Each item you’re adding provides only one effect. It’s tempting to
  create a generic UseEffect component containing an enumeration.
  Enums can only have one value—if you want to make an item with
  multiple effects, you’d be out of luck. It’s a good idea to separate
  effects into their own components in case you decide to create an
  item that does more than one thing.
Not only does this violate YAGNI, it's trivial to work around:

  enum ItemEffect {
      Heal(i32),
      Poison(i32),
      Explode,
      MultiEffect<Vec<Box<dyn ItemEffect>>>,
  }
It just feels like you're looking for problems to solve.
MaulingMonkey2 hours ago

    struct Entity {
        components: Vec<Box<dyn Component>>,
    }
At this point you're effectively just hand-rolling your own ECS - and perhaps being in denial about it by touting the fact that the ECS is half implemented at best - rather than eschewing an ECS outright, IMO. If you want to skip the ECS, embrace the natural typing of the language - then you don't need to build something to query and filter components, and can instead just use the language's built-in constructs:

    struct Entity {
        pub position: Option<XY>,
        pub sprite:   Option<SpriteId>,
        pub scripts:  Vec<ScriptRef>,
        //...
    }
    
    fn render_world(entities: &[Entity]) {
        for entity in entities {
            if let Entity { position: Some(xy), sprite: Some(sprite), .. } = entity {
                // ...
            }
        }
    }
Entity may eventually become a merge hazard on larger teams, and Entity enumeration without archetype filtering may eventually become a performance hazard if done too frequently and naively, but this kind of approach can work fine for many smaller projects.
halvnykterist1 hour ago

The crucial difference between having a vector of components is in access patterns - in ECS you iterate over entities that have a given set of component, using queries, with entities that have vectors of components you're still iterating over entities. For something like a roguelike you're generally just dealing with one entity at a time, so this is a very important distinction.

That said, I don't think just having a vector of components is good design, you can do a lot better than that. I think the most natural thing to do in most roguelikes is to have an "Entity" type that's shared between players and monsters and has things that you'd expect those things to have, along with an inventory and potentially some kinds of tags governing behavior. Type Objects etc fit nicely into that kind of scheme.

>and Entity enumeration without archetype filtering may eventually become a performance hazard if done too frequently and naively, I'm specifically talking about turn based tile based games, here, so iterating over all entities matching a given set of components is rarely going to be a performance concern. It's far more important to make sure you're efficient when it comes to things like AI routines and pathfinding.

thebracket6 hours ago

We should probably agree to disagree; your approach is just as valid as mine. My first attempt at a roguelike in Rust ( https://github.com/thebracket/rustyroguelike ) was a straight-from C++ approach, using dynamic traits and a lot of casting. It was my first try at using Rust, and is pretty bad - but at least it completed the "r/roguelikedev does the tutorial" event. Going from OOP to a non-inheritance language was quite the leap.

You absolutely can have an entity structure containing a vector of dynamic component types. It can get quite messy when you start having a lot of component types. When your entity runs, it has to look at the data in its components. That either means that component is a big enum (no need for dyn and Box there), or component is a trait and you're going to be doing a bunch of dynamic casting to find out what components an entity has when it ticks. Either can work (as can having an Option for each component type, which replaces the dynamic cast with an `if let`). Ultimately, there's not a lot of difference between an entity iterating its components and calling methods on components (or branching based on the components it has) and running a query to retrieve the components you want and acting on them. It's not that different from a NoSQL database (everything in a node graph) vs. a relational database (tables keyed to an identifier) - both work, each has their strengths and weaknesses. (I also really didn't want to try and teach dynamic casting early in the book!)

Some specific points from your reply:

By "replication", I meant network replication. You can get the same benefits by tracking changes within an entity/component, but it's really handy when a single storage system does that for you. Not that useful to a traditional single-player roguelike, but a nice tool to have.

> Yes, but that's not what a turn based tile based game is. Generally you want to iterate over things in order - gravity (if a roguelike has such a thing) gets applied on the player's turn, and only for the player. If you step over a ledge you don't wait for the "gravity" system to kick in and apply gravity to all entities, it is resolved in the same instant for only the entity that has just moved

That very much depends upon what you're creating. (Nox Futura is a Dwarf Fortress like). In the gravity example, it was solved by remembering to exclude the Flying component from the gravity query. The roguelike example in Hands-on Rust actually runs the player and monsters in different phases, but re-uses a lot of systems in the process. Matching on the turn state and executing systems isn't all that different to matching on the turn state and running tick functions on the entities included in that turn - especially if you have an energy cost/initiative type system breaking out the moves (the tutorial I created does this). Both Hands-on Rust and the tutorial effectively use message-passing for chaining events together.

> if anything I could see issues arising from the fact that you basically have dynamic typing when it comes to what behaviors an entity has

You have the exact same problem with a dynamic vector of components.

> If you're not doing query-based ECS with systems there's also no particular reason to not use vecs of components within entity structs.

It mostly boils down to preference. I find Query<(MonsterAI, Position, LikesToEatPlayers)> easier to work with than having each entity iterate a component list, query the type of each component and then act accordingly.

> As a final note, in the excerpt about items you have this justification for not using an enum instead of components:

Again, we're solving the same problem in similar ways. There's really not a whole lot of difference between matching the enum and iterating MultiEffect and querying if an entity has components. Either way, you have code that says "oh, it explodes" and makes a boom.

In other words, we both prefer different ways to accomplish exactly the same thing. Neither of us is right or wrong, there's plenty of ways to skin a cat. Hands-on Rust is as much about teaching Rust and gamedev in general as it is roguelikes in particular; if you want a big, working roguelike - the tutorial ( https://bfnightly.bracketproductions.com/ ) does that.

pizza2349 hours ago

> The idea is very entrenched in the rust gamedev community

I don't think it's very entrenched, although it's certainly present. The reason for this perception, I guess, is that Bevy (which is based on ECS) is all the rage.

Amethyst was ECS as well, but it's dead now (and Bevy is essentially its successor). Veloren is ECS though, and active.

The remaining major engine (AFAIK) is RG3D, but it's not ECS. Macroquad provides a node graph (but it's a smaller engine).

All the other game engines are comparatively small, and they don't provide storages/ECS engines.

(edit: added Veloren)

halvnykterist9 hours ago

I think Kyren's 2018 CustConf talk [0] caused it to become popular earlier. Arewegameyet has an entire section for ECS crates, with 10 different entries. I'm aware of multiple smaller homegrown solutions, too.

https://kyren.github.io/2018/09/14/rustconf-talk.html

rtoway8 hours ago

Bevy, while an ECS based library, can easily be used to program a game in a more traditional way (excuse my formatting):

struct Player { health: Health, }

  // ECS style
  fn update_player(query: Query<&mut Player>) {
    
  }

  // Traditional "OOP" style
  impl Component for Player {
        fn update() {
        
        }
   }
anothernewdude9 hours ago

The reason ECS is so common for roguelikes, is because they provide a simulationist experience. The main draw of several roguelikes is having enemies on the same footing as the player, and a good way to do that is to have them use the exact same systems. It's also a good way to make interesting interactions between environment and objects happen.

Also, having collections of entities works well for Rust's borrow checker.

ffhhj55 minutes ago

ECS is nothing compared to the eclipsing aspects of games that a gamedev has to solve:

* Structures persistency (save/load/stream)

* Optmized seamless world expansion

* Where to get assets and content from (licenses, generated, etc.)

* Affordable and responsive multiplayer

jyriand2 hours ago

Sorry, what is ESC?

uDontKnowMe5 hours ago

Consistently interesting content coming out of Pragmatic Bookshelf publishers these days. Recently, I have particularly enjoyed the Ray Tracer Challenge (https://pragprog.com/titles/jbtracer/the-ray-tracer-challeng...) and Web Development in Clojure (https://pragprog.com/titles/dswdcloj3/web-development-with-c...)

greenail6 hours ago

I don't think most non-rust programmers know what ECS is.

ECS is a pattern to manage composable logic and shared behavior. very very loosely like splitting logic in to class level and object level.

runevault5 hours ago

Lots of game developers know what ECS is. It existed before rust gamedev became a major thing. Unity even has an (experimental to be clear) ECS engine you can use to replace traditional monobehavior style objects.

greenail5 hours ago

fair, but I had to lookup what ECS was so I though I'd save others a bit of googling.

runevault3 hours ago

Yeah explaining it is great. Just don't want people thinking it is only a Rust thing.

dopu7 hours ago

Looks pretty good! I will say, as someone who programs in their day job and has been trying for ages to get into game dev as a hobby, love2d [0] has been excellent for getting started. My github has a few repos of previous attempts at making simple games (in .cpp, .rs, etc) which I abandoned from the amount of work it took.

If you're in a similar boat, I would recommend checking the framework out. Lua's a pleasure to program in and you can focus on the game development itself instead of getting bogged down in the details of rust / cpp. In fact I've been thinking lately about how easy it would be to use it for things other than games -- quick prototyping of graphical simulations, psychophysics experiments, etc.

[0]: https://love2d.org/

Zolomon10 hours ago

I worked through this book a couple of weeks ago and I had a blast. I heartily recommend it to roguelike fans that haven’t tried out participating in the 7DRL game jam yet.

ttymck2 hours ago

It is a very good learning guide. Keep in mind I am someone who negotiates the borrow checker by adding-and-removing */&/to_owned() rather haphazardly.

I found it especially satisfying to port the game from racketlib/rltk to bevy afterwards.

rtoway37 minutes ago

I was thinking of following the book but with Bevy. How do you replace bracket-lib?

myth_drannon7 hours ago

It's a great book but I struggled with an additional overhead of ECS library usage. Don't know if it would have been better just roll out it's own simple logic for ECS , but then it would probably double the length of the book.

thebracket7 hours ago

Page count was a real concern. I wanted to introduce Rust newcomers to easy concurrency, and keep the data-storage side of things manageable (storing a big list of dynamic objects with traits gets messy fast and leads to a lot more borrow-checker fighting). Using an ECS let me dodge the latter bullet, at the expense of a bit of complexity. (I made sure Flappy didn't need an ECS)

Bevy didn't exist when I started writing, or I'd have probably used it. Legion is a great ECS, but it's heavier than I'd like - and Bevy makes a lot of things really easy.

TylerE3 hours ago

This concerns me a bit.. when I've made (failed) attempts to learn Rust in the past the borrow checker was always the sticking point.

baq2 hours ago

It needs a mindset change. The thing is trying to help you. It points out issues that you didn’t think about. It’s naturally difficult to think about things you’ve never had to think about before. It also turns out that architecting software in certain ways (like ECS) makes it easier to think less about borrowing.

vjust7 hours ago

His explanations seem very clear and simple, I'd dig into it, just to get a better understanding of rust, and the game dev part also seems do-able, unlike other authors where they dive into some complex pieces causing frustration to the learner.

thebracket8 hours ago

(Author here) That's the Roguelike tutorial I created, not the Hands-on Rust book. The two are quite different beasts, with a bit of overlap.

Hands-on Rust is designed for the newcomer to Rust, and carefully maps tutorial sections through teaching beginner-to-intermediate Rust concepts. It starts with some basic Rust exercises, works through a Flappy Bird clone, and then uses Roguelike development to teach a lot of underlying Rust concepts. It also teaches gamedev, and tries to do so in a way you can reuse in other games.

The tutorial is all Roguelike, all the time - focused on building a working roguelike.

rudedogg4 hours ago

Congratulations on releasing your book. I watched one of your talks about procedural generation[0] and really enjoyed it, thanks!

Mentioning this here since the tutorial linked above has a lot of procedural generation content

[0] https://www.youtube.com/watch?v=TlLIOgWYVpI

igh4st6 hours ago

The book sounds awesome to get your hands dirty with Rust :)

is there a promo code for Latin-american countries?

thebracket6 hours ago

I'm not sure what promos are active right now (I just got back from vacation). It will be included in the November Thanksgiving sales. You could also email support@pragprog.com - they would be able to help.

igh4st6 hours ago

I'll reach out to them, thanks!

cius6 hours ago

I recently finished this book and highly recommend it. Very fun stuff, a decent introduction to rust, and does a great job of setting the reader up for exploring further. Kudos to Mr. Wolverson.

dudul6 hours ago

I started reading this book a few months ago. It is pretty good, I really like learning while working on a "sort of real world" project.

However, being completely new to Rust I find that the author doesn't spend enough time discussing the language, it's syntax and nuances. It is hard to talk both about rust alongside video game design techniques.

I put it down after reading 1/4th of it. I'm planning to spend some time on a book that focuses on the language first and then get back to it ;)

timClicks1 hour ago

That's a very difficult balance as an author writing a project-based book for a language. It's really difficult to know how much time to spend where: the language (Rust), the projects background (gamedev patterns) or the project code.