Live data from Hacker News

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

pragprog.com

11–20 of 83 posts

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

#11

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…

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…

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

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

#12
post #9

Book is also online: https://bfnightly.bracketproductions.com/ and on Github: https://github.com/amethyst/rustrogueliketutorial

(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.

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

#13

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…

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) {
    
  }

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

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

#14

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…

(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 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.)

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

#16

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.

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.

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

#17

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…

(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 basicall…

> 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>,
  }
(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>>,
  }
It just feels like you're looking for problems to solve.

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

#18
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/

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

#20

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…

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…

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.

Post reply on HN