
Using Rust for Game Development [video] - tpush
https://www.youtube.com/watch?v=aKLntZcp27M
======
raphlinus
I found this excellent talk to be complementary to my talk[1] on data-oriented
GUI in Rust, not to plug my own work too much.

I found a lot of common ground:

* Trying to write object-oriented code in Rust doesn't work well. Writing data-oriented code does.

* "Fighting the borrow checker" is a sign you might be doing it wrong. Try data-oriented approaches instead.

* Use a structure-of-arrays rather than an array-of-structures.

* Use what I call "state splitting" to borrow mutable references to just the state you need; this works well with the structure-of-arrays approach and is a powerful motivator to use it.

* To build graph-like structures, reach for a Vec of components, and indexes into the Vec for relationships, as your first choice. Self-references, arena allocators, and Rc are viable alternatives, but you should have a good reason to use them instead of Vec.

* Some form of dynamic typing is useful to keep your system loosely coupled (though we ended up with very different forms of dynamic typing, see below).

* Data-oriented approaches have taken root in the C++ gaming community, mostly motivated by performance, but adapt well to Rust, and some of the ideas may be useful in domains beyond gaming.

There were some other points that went beyond what I talked about, but could
fit in well:

* A "generational index" is a good way to avoid use-after-free style errors that result from the use of a stale index. The slotmap crate can help.

And now for the things that are different.

* The exact nature of dynamic typing is different. An ECS usually uses a registry of the different component types (anymap is a useful crate) and is quite open-ended in adding new types of components. My xi-win-ui, by contrast, has two main component types, Widget and listener, and does dynamic dispatch on a Widget trait.

This naturally raises the question, which is better? From my perspective, both
are valid. The pure ECS approach definitely makes sense when the components
are interacting with each other in diverse ways (collisions, damage, etc). In
a GUI, the components are mostly interacting with the framework, and have
diverse behaviors within standardized interfaces (input, layout, paint).

Thus, one point of my talk is that you don't have to reject all vestiges of
object oriented programming, it's perfectly reasonable to hybridize, using
data-oriented approaches for state splitting and graph structure, and dynamic
dispatch for the behavior variation.

My talk also went deeper into the ideas of "data flow rather than control
flow" and the use of an event or command data structure rather than method
calls. I'm not sure how deeply these ideas apply to games, but wouldn't be
surprised if they do.

[1] video:
[https://www.youtube.com/watch?v=4YTfxresvS8](https://www.youtube.com/watch?v=4YTfxresvS8)
, slides: [https://docs.google.com/presentation/d/1aDTRl5R-icAF38Di-
qJ4...](https://docs.google.com/presentation/d/1aDTRl5R-icAF38Di-
qJ4FzAl3pLlutTKVFcr3mUGgYo/edit?usp=sharing)

~~~
anderspitman
I highly recommend watching Raph's talk for anyone writing Rust apps that
manage non-trivial state. Ah heck just watch it no matter what it's great.

~~~
raphlinus
Aww, thanks :)

------
nightcracker
I'm the author of slotmap
([https://github.com/orlp/slotmap](https://github.com/orlp/slotmap)) briefly
mentioned at the end. I'm working hard on the requested 'independent
allocation' (or secondary maps as I'm currently leaning on), and will have it
ready soon.

~~~
rapsey
How is it different from slab crate?

~~~
nightcracker
[https://docs.rs/slotmap/0.2.0/slotmap/#why-not-
slab](https://docs.rs/slotmap/0.2.0/slotmap/#why-not-slab)

------
gamegoblin
Not Rust specific, but in the same train of thought, here is an _excellent_
series of articles going into other issues with OOP and game development, and
touches on a few similar topics of cross-cutting concerns and their
interaction with interface/class design:

[https://ericlippert.com/2015/04/27/wizards-and-warriors-
part...](https://ericlippert.com/2015/04/27/wizards-and-warriors-part-one/)

[https://ericlippert.com/2015/04/30/wizards-and-warriors-
part...](https://ericlippert.com/2015/04/30/wizards-and-warriors-part-two/)

[https://ericlippert.com/2015/05/04/wizards-and-warriors-
part...](https://ericlippert.com/2015/05/04/wizards-and-warriors-part-three/)

[https://ericlippert.com/2015/05/07/wizards-and-warriors-
part...](https://ericlippert.com/2015/05/07/wizards-and-warriors-part-four/)

[https://ericlippert.com/2015/05/11/wizards-and-warriors-
part...](https://ericlippert.com/2015/05/11/wizards-and-warriors-part-five/)

~~~
lackbeard
I'll have to re-read this series, as it's been a while but I remember feeling
dissastified after finishing it the first time. I think the conclusion was
basically: yup, programming is hard, no matter what you do you're going to
wind up with a big mess!

~~~
phantarch
That's an easy sentiment to come away with from every article in the series
except the very last.

The final one does offer (imo) a pretty clean solution to the problem he's
been exploring, which boils down to viewing the rules of the game as the class
definitions and using the things in the game world as data to be plugged in to
the rules, rather than the other way around.

------
mrec
Just watched this yesterday. I really like the pragmatic tone ("you don't have
to go all the way, you can stop at any of these points and be fine"), and I
love the "egoless" style of presentation. Illustrating your point using your
_own_ mistakes is much more compelling than picking on some artificial
strawman.

------
arconis987
The generational index idea was exactly what I needed for a search index
project I’ve been working on. Makes it much easier to safely insert and delete
from a memory arena.

Also, fascinating that Rust’s borrow checker sort of encourages you over time
to adopt an entity component system architecture instead of a naive OO
architecture.

~~~
faitswulff
> Also, fascinating that Rust’s borrow checker sort of encourages you over
> time to adopt an entity component system architecture instead of a naive OO
> architecture.

Is this true outside of gamedev contexts?

~~~
bluejekyll
I'm not familiar with the parent comment, but after seeing this talk at
RustConf, I've been strongly considering this pattern as a better way of
storing associated data to an entity than OO design, especially in regards to
high-scale systems where portions of an Entity might be stored across
different datastores.

The idea of operating on individual components of an entity is very compelling
in those cases, it's not even novel. We often have done this by pulling data
out of datastores in parallel array like requests. The difference with this
model is that it creates an elegant interface over the data for an entity that
isn't a bastardized version of OO, instead just the data and structures you
need present in the context in which your working.

As a non-gamedev, I found this really compelling.

------
erlend_sh
I encourage anyone interested in game development with Rust to check out the
yet-to-be-formalised working group:

[https://internals.rust-lang.org/t/a-working-group-for-
rust-g...](https://internals.rust-lang.org/t/a-working-group-for-rust-game-
development/8240?u=erlend_sh)

At the moment the main focus is just to get organised around some common
tooling that everyone can get behind. At this point I'd say the most impactful
project to contribute to is gfx-rs.

------
Jare
This is a fantastic talk about game architecture, regardless if you are
interested in Rust or not.

------
agumonkey
I read some 2015 review of rust from viva64 where they used benchmarkgame to
show rust is still 3x C. Nowadays benchmarkgame has Rust and C in the same
numbers. That's quite a feat.

~~~
vvanders
I've mentioned it before but there's a chance for Rust to get better than most
C code with the ability to implicitly mark mut& as restrict.

Restrict is one of those very, very sharp tools that's usually only reserved
for cases where you've profiled and done the extensive work to guarantee non-
aliasing pointers. The fact that it's just implicit as part of the ownership
design of Rust is pretty bad-ass.

~~~
kibwen
AIUI it seems that one of the issues that Rust is having right now is that it
actually has more precise information than LLVM is really capable of taking
advantage of, which makes sense given that LLVM was originally intended to
take advantage only of C's coarser restrict semantics. It's sort of a funny
situation where the fact that Rust _could_ improve on C's optimization
capabilities is the same reason that it _can 't yet_ do so: it's using an
optimizer designed for C!

That said, I'm hardly an expert here and the situation on the ground may have
changed since last I looked (or I may be completely misunderstanding the
discussions that I've peeked into). An example of the problem in this GitHub
issue: [https://github.com/rust-
lang/rust/issues/53105](https://github.com/rust-lang/rust/issues/53105)

~~~
Manishearth
Yeah, this is true.

We do the equivalent of telling the compiler that things don't alias at
function boundaries (i.e. restrict) and not much more.

Nobody writes C code with restrict all over the place, which means that not
only is this the finest grained level we can give this info to LLVM, it
doesn't even necessarily support it well! We had to turn it off for &mut for a
long time because of a bunch of bugs.

The weird thing is, to be able to do most optimizations LLVM does its own
alias analysis anyway! (I don't know the details).

A lot of program analysis research is focused on improving alias analyses
which are usually slow, imperfect, and global. Rust's aliasing info is "free"
(you don't need to compute anything extra to get it), local, and perfect
(ish). We really could get a lot of wins from doing our own aliasing-aware
analyses, or by reordering the code in such a way so as to make it easier for
LLVM (e.g., hoisting reads and writes to function boundaries so llvm just sees
a bunch of locals)

------
epage
For me, this was the introduction to ECS that made me "get it" and I'm slowly
morphing my Rust implementation of the Liquid template language over to an ECS
architecture.

------
pcwalton
This is a really good talk. The name undersells it: it's really "how to stop
fighting the borrow checker" in general and not specific to games.

------
Koshkin
Rust: too little, too late.

~~~
steveklabnik
Why?

------
zerr
So far interesting, but it is very annoying that cynicism became the standard
way to drive talks.

