
Making a Game in Rust - b1naryth1ef
https://michaelfairley.com/blog/i-made-a-game-in-rust/
======
vvanders
Great stuff, lines up a lot with what I'd care about as an ex-gamedev and
spending a bit of time with Rust. One minor point:

> First class code hot-loading support would be a huge boon for game
> developers. The majority of game code is not particularly amenable to
> automated testing, and lots of iteration is done by playing the game itself
> to observe changes. I’ve got something hacked up with dylib reloading, but
> it requires plenty of per-project boilerplate and some additional
> shenanigans to disable it in production builds.

Lua is a great fit here and interops with Rust(and just about everything else)
very well.

~~~
eridius
A long time ago I wrote bindings to Lua 5.1
([https://github.com/kballard/rust-lua](https://github.com/kballard/rust-
lua)), but there was a nasty problem where Lua uses longjmp() for errors (it
can be configured to use C++ exceptions, but that doesn't work because you
can't throw those past an extern C boundary without hitting undefined
behavior). longjmp(), of course, will just skip right past the intervening
stack frames, meaning if your Rust code calls into Lua and it throws an error,
then unless you wrapped that call with a lua_pcall, any values that live on
the stack of your Rust function will never call their destructors.

I admit I haven't bothered to research the current state of things, but how do
more recent Lua bindings handle this? Does Lua 5.3 actually have a proper
solution here, or do most bindings just wrap every single call with lua_pcall?
I didn't do that in my bindings because I wanted to offer the full speed of
Lua, but it's certainly an option.

~~~
vvanders
That's still pretty much the state of the world. I think that's a trade-off
that makes sense as long as you're aware that you shouldn't be depending on
drop functionality in callbacks(I would hope that your initial point is
dostring/dofile and let that catch handle things).

Generally I've found that any time you're interacting with an FFI in Rust all
bets are off and you need to be very aware of what your libraries do and what
their runtime looks like(just in C/C++).

~~~
eridius
I had intended to write a compiler plugin for rust-lua that added a lint that
would ensure you have nothing on the stack with Drop when you call a
(potentially-error-throwing) Lua function. But I never got around to doing
that because I stopped using rust-lua (I canned the one project I was doing
that motivated rust-lua in the first place).

------
deckarep
I largely echo the sentiment of using Rust for game development. The world
doesn't need another Flappy Bird clone but that's what I wrote because I ended
up porting a Go version that was using SDL originally by Francesc Campoy from
the Golang team: [https://github.com/campoy/flappy-
gopher](https://github.com/campoy/flappy-gopher)

I was able to build the Rust version fast, and the SDL library is actually
quite usable/stable for most things.

Flappy-Rust has particle effects, the beginnings of parallax-scrolling and
basic collision detection. The rust code ended up being pretty reasonable
however I'm quite sure there are a few places I could have simplified the
sharing of assets.

If anyone is interested in this space check out my repo:
[https://github.com/deckarep/flappy-rust](https://github.com/deckarep/flappy-
rust)

Also please see the README.md where I talk a bit more in-depth about how the
Rust version differs from the Go version.

Here is a .gif preview of the first iteration of the game:
[https://github.com/deckarep/flappy-
rust/blob/master/flappy-r...](https://github.com/deckarep/flappy-
rust/blob/master/flappy-rust.gif)

------
Lerc
It would be nice to have a minimal gameish program as a example for people
learning Rust.

When I teach kids javascript I start with an etch-a-sketch. It's aided by a
simple library to hide the mechanics of the HTML canvas element, context, etc.
This allows it to be small enough that they can view it all in one go and
build upon it.

    
    
        print("Draw with the arrow keys");
    
        var cx=320;
        var cy=240;
    
        function update() {
          // the arrow keys have key codes 37,38,39 and 40
          if (keyIsDown(38)) {    cy-=1;  } 
          if (keyIsDown(40)) {    cy+=1;  }
          if (keyIsDown(37)) {    cx-=1;  }  
          if (keyIsDown(39)) {    cx+=1;  }
      
          fillCircle(cx,cy,6);
        }
    
        run(update);
    
    
    

There might be merit in writing one of these in every language (and a
companion that uses the mouse), maybe placing it on github . With a really
simple program like this you can focus on learning the language while making
something. It's a tough job figuring out how to learn a language while
simultaneoulsy learning how to write the boilerplate needed to get something
onscreen.

~~~
Jare
For simple pixel access and no primitives,
[https://github.com/emoon/rust_minifb](https://github.com/emoon/rust_minifb)
is very compact and neat.

Otherwise rust-sdl2 is batteries included, there may be more ceremony than
html5 canvas but it's easy to hide behind a simple interface. It has many
simple examples.

But, like with C++, as long as the language doesn't come with a standard
graphics library, I doubt the "official" books can really use graphics apps as
a learning tool.

~~~
Lerc
Easy to hide behind a simple interface if you already know the programming
language. My suggestion is that someone perhaps should do just that so that
beginners don't have to learn how to construct a simple interface at the same
time as they are learning the language.

The MiniFB code does seem to be a good starting point for this sort of thing.

~~~
Jare
Yeah, I was just echoing your comment that you provide a small library for
HTML5 canvas-based teaching. If I was going to teach someone Rust, I would
definitely do that, but of course I (the teacher) would need to know enough to
build it in the first place.

I absolutely advocate using graphics and games as the hook to keep people
interested in learning. [1] "The immediacy of many 8-bit computers was
awesome. Instant boot to a graphics-ready command line and program editor. I
was instantly hooked". And that's why, despite the really bad fit, I support
the addition of a 2d std library to C++, and would do likewise for Go, Rust,
etc.

[1]
[https://twitter.com/TheJare/status/860094027370291200](https://twitter.com/TheJare/status/860094027370291200)

------
wyldfire
> The include_* macros are great for “packaging”. Being able to compile small
> assets directly into the binary and eschewing run time file loading is
> fantastic for a small game.

For C/C++/etc devs looking for something similar, BFD objcopy supports an "-I
binary". It will emit an object file with _binary_objfile_start,
_binary_objfile_end and _binary_objfile_size symbols.

But I have got to say that making it a language feature means that Rust is
truly a batteries included language.

~~~
Pxtl
Agreed. I code in C# and there's facility for bundling assets into the binary
but they're handled at the project file level and not the C# file level, and
this means the keys to access this binary content is not available as a
compile-time constant. You're still just passing strings around and hoping
they match.

Having first-class language support for resource files looks fantastic.

~~~
flukus
> and this means the keys to access this binary content is not available as a
> compile-time constant

Isn't that exactly what resource files give you or am I confusing something?
Anything you add in resource files have are accessible as a static variable.

~~~
Sean1708
It looks like you're right (for C# at least): [https://msdn.microsoft.com/en-
us/library/7k989cfy(v=vs.90).a...](https://msdn.microsoft.com/en-
us/library/7k989cfy\(v=vs.90\).aspx#Anchor_2)

------
kibwen
I wasn't even aware that you were allowed to ship Rust code in iOS apps, I
thought that Apple had a whitelist of allowed languages?

EDIT: And for those interested, you might want to check out Rust's recent
inclusion in a AAA title:
[https://www.reddit.com/r/rust/comments/69s225/rust_makes_it_...](https://www.reddit.com/r/rust/comments/69s225/rust_makes_it_into_a_aaa_video_game_as_an_art/)
:P

~~~
wyldfire
Really? How do they know what the representation of the object code was before
compilation? Seems like if they had a whitelist it would be difficult to
enforce.

~~~
bluejekyll
The biggest problem I faced with Rust and macOS/iOS is related to Apple's
requirement for bitcode on all submitted code to the App Store for Watch and
appleTV applications.

This internal Rust discussion focuses on it for more details:
[https://github.com/rust-lang/rust/issues/35968](https://github.com/rust-
lang/rust/issues/35968)

This gist is that Apple is requiring bitcode, but isn't giving easy access to
the LLVM version they use for their own tools. This means there's not a path
forward to support bitcode generation from Rust that would align with Apple's
requirements. This currently only effects iOS on Watch and TV, meaning you can
easily target macOS and iPhone without issue, but I fear that the writing is
on the wall.

~~~
nebabyte
I continue to be amazed that apple is not considered as having a monopoly on
"stores for apple devices".

These are exactly the kind of archaic requirements that would be a nonstarter
or otherwise _kill_ market support for a store given any actual competition.

Instead, they are able to leverage it to try and push their 'approved'
languages and developer environments - furthering anticompetitive lock-in.

Apple making money from selling devices (or even distributing "at a loss"
devices which they benefit from having exist so they can better act as
software vendors) and them making money from their store are two separate
revenue streams, after all.

~~~
eridius
"products made by one brand" isn't a category of products. If they're the only
brand that makes products for a particular category, then they're a monopoly,
but you cannot simply define a category as "stuff made by that company",
because by that logic, every company is a monopoly on stuff made by them.

~~~
dragonwriter
Actually, a makers own products are a distinct market for antitrust purposes
if people empirically don't substitute out of it, as shown by the producer
having market (pricing) power.

I wouldn't be surprised if that's true for Apple for some of its offerings.

~~~
eridius
It's not. The only product you could even try to make the argument for is the
iPhone, but the generally-accepted categorization here is that iPhone and
Android phones (and Windows phones) are part of the same category, which makes
sense because people absolutely do switch between them.

------
alkonaut
> I had two or three false-start attempts at learning Rust where I’d spend a
> few hours with it, not get anything done, and put it down until a few months
> later

This sounds (sort of) encouraging. I was kind of expecting to learn it by
putting in an hour here and there e.g. 2-4h/month. But I'm beginning to think
that might not cut it...

~~~
Manishearth
Go is a language that you can absolutely learn like that, and it's pretty
amazing. (Python, too)

Rust ... isn't. I love Rust, but you do need to put some dedicated time into
learning it. We're hoping to improve this!

~~~
joncampbelldev
Whilst an easy start is nice, any language that you can pick up with no effort
just means you're learning the same language + paradigm that you already know
with a few differing features (in go's case CSP). Nothing wrong with that, CSP
is awesome etc

I'm not a rust dev (definitely interested in picking it up though), but
heavily into clojure and learning haskell slowly on the side. I hear this
complaint a lot from people who think that because they learnt C#, Go, Java
and Swift in a weekend that all languages will be just as quick to stick in
their heads.

~~~
Jare
A lot of people have to unlearn "classic" OOP inheritance in order to learn
Go. That's a significant change in paradigm.

------
lohengramm
I would love to read a detailed explanation of the packaging process for iOS
and Android.

~~~
desdiv
The author should seriously consider factoring out his build scripts and start
a crowd-funding campaign to open source it for X thousands of dollars. Hell, I
don't even know Rust and I'll donate ten bucks.

The five platforms support is bloody impressive.

------
MaulingMonkey
Neat! I was just complaining about the lack of multiplatform Rust games
proving out the concept. If only there were some consoles or handhelds on the
list... although iOS/Android being on the list is somewhat encouraging.

------
Buge
The performance on my Android phone (Nexus 6) is not good. I would have
thought Rust would be fast. The fps is fairly low, a lot lower than Maps or
Chrome, at least when Maps isn't freezing up. And it seems the transitions
between levels might be proportional to fps, because they are irritatingly
long.

~~~
MaulingMonkey
I'd guess any performance problems are probably on the GPU / OpenGL side of
things, which Rust won't help with (nor hurt). The Nexus 6 has a 1440p screen
powered by a mobile GPU maybe a little weaker than _previous_ generation
consoles (~172 gflops max for the Adreno 420, vs e.g. ~220 for the PS3 [1])
that were often handling 720p titles (a quarter of the pixels). _Very_ easy to
exceed your frame budget.

[1] [http://gpuflops.blogspot.com/](http://gpuflops.blogspot.com/)

------
yorwba
About floats implementing _PartialOrd_ and not _Ord_ :

I have not tried out Rust yet, but couldn't this be solved by wrapping the
float in a single-field struct that checks for NaN on construction, implements
_Ord_ using _PartialOrd_ and otherwise passes everything through to the
ordinary float inside?

If this isn't possible, I'm definitely interested in the reasons.

~~~
lifthrasiir
Every calculation will have to check for NaN, so it's a non-starter when you
need a lot of float calculations.

~~~
yorwba
The problem was in the context of looking up _min_by_key_ with the key being a
floating-point number, so I think the only NaN-check necessary should be for
that key. I did not intend to imply that it should be done for all
calculations, only those that need totally-ordered floats. (Or if you are
really sure NaN will never happen, you leave out the check altogether, and
claim total ordering anyway.)

~~~
lifthrasiir
I guess that is a particularly bad use case of specialization, which itself is
proposed as an RFC [1] and approved for implementation. It would look pretty
similar to, say, C++'s `vector<T>` and `vector<bool>` split, because it does
something more than what it should do. Probably the better solution is to
merge PartialOrd and Ord, as the benefit from having two traits has been
always unclear (I personally have no strong opinion against or for that
though).

[1] [https://github.com/rust-
lang/rfcs/blob/master/text/1210-impl...](https://github.com/rust-
lang/rfcs/blob/master/text/1210-impl-specialization.md)

------
esistgut
It is an interesting educational project but staying away from Unreal or
Unity3D is really a tough decision if your project is going to need some more
features that are already developed and well tested in one of these engines.

~~~
golergka
In my experience, the real value of the engines aren't "features", but tools
oriented at level designers and artists. Once you have a project with 10 or
more members, managing art and assets becomes a real headache - and most of
homegrown solutions, as well as open source engines start to fall apart at
this point.

------
newsat13
Great writeup. Eye opening that you can actually write iOS apps with rust.
w00t, totally trying this for my next app. (It's a bit overly bit expensive
for my liking but otherwise I would have given your game a shot).

------
educar
Is there a write-up on how the rust code ends up being embedded in the iOS
app?

------
jlebrech
that's a great twist on the snake game. does rust compile to wasm?

~~~
cjg
Yes, Rust can compile to WASM.

[https://hackernoon.com/compiling-rust-to-webassembly-
guide-4...](https://hackernoon.com/compiling-rust-to-webassembly-
guide-411066a69fde)

~~~
jlebrech
I want to do an experiment with object oriented code that generates view code
in wasm and keeps other code in the server.

------
Ace17
Screenshot, please!

~~~
bronson
Hit the second link in the article for a video: [https://m12y.com/a-snakes-
tale/](https://m12y.com/a-snakes-tale/)

------
remotehack
Did a double take on the title.

------
felipemnoa
This is probably not a popular opinion here in HN but why does it matter what
language you use to make your game in? You can use virtually any language to
make a game. From my point of view the best language for a game is that which
makes you the most productive for cranking out that code. And we all have our
own personal preferences about which language is best, which I think is fine,
you should code with the one that you feel most productive with. At the end of
the day users will not be able to tell the difference. All that matters is
whether your game is fun or not.

~~~
wastedhours
100% agree with you. _However_ \- posts like these might give encouragement to
people who know a language that they can actually accomplish Project XYZ in
said language, especially if there's accepted norms about what types of work a
language is "good for".

~~~
felipemnoa
Although I did not point it out, I'm talking about experienced software/game
developers. A novice can definitely make the mistakes you are mentioning,
which makes your comment a valid point.

