RubyConf 2022

Building a Commercial Game Engine using mRuby and SDL

What does it take to build a cross platform game engine in Ruby? How do you render to the screen? How is the simulation and rendering pipeline orchestrated? Why is Ruby a viable option is to begin with? These questions and more will be answered by Amir. Be a part of this renaissance and see how Ruby can be used for so much more than server side web development.

RubyConf 2022

00:00:00.000 ready for takeoff
00:00:16.920 all right hopefully everyone's in the right place building a commercial game engine with Ruby right now the the
00:00:24.180 standard license for the game engine is available for free you can download it just Google dragonruby itch.io and
00:00:29.939 you'll get a full commercial license use it for whatever you want make money off of it get a huge Studio
00:00:36.420 hire a bunch of people then buy the pro license right that's the plan right
00:00:41.820 okay so um uh been in the game industry for I guess a decade now 10 years and uh
00:00:48.600 when uh when a Game Dev asks me oh yeah I build all my games in in Ruby uh this
00:00:54.780 is the uh it's usually the question that I get and um over over that time I've uh I've
00:01:03.660 fine-tuned the perfect response right
00:01:09.479 and uh usually that ends up they usually walk away or they we start having a productive conversation and um and say
00:01:17.220 yeah but no seriously a mirror like why would you do this and um the answer is actually pretty
00:01:22.680 simple I don't want to be miserable in building video games I just I've been coding for 23 years now
00:01:30.900 and I'm telling you I don't want to use a programming language that is horrible and frustrating to use so I just don't
00:01:38.460 want to be miserable doing it and this is the dream right you're a kid you're like I want to build a video game that's
00:01:43.860 where you get into coding and then and then you have to use languages that are not fun
00:01:49.799 and I think Ruby gives you that perspective um the other interesting thing about Ruby that makes it good for video games
00:01:56.100 that Ruby's art when we talk about Ruby we say oh it's a beautiful language you
00:02:02.880 hear that all the time who who calls a language beautiful it's expressive right it makes me happy
00:02:09.720 and there's there's facets of that that correlate to art it scares me yeah somewhere can be kind
00:02:15.900 of scary um but um I think that's I think that's intrinsic in the language itself
00:02:23.580 and um one of the most important things is that Ruby begets innovation
00:02:28.739 think about how just the past 25 years that Ruby's been around how it's changed the landscape of technology and how we
00:02:35.160 build software right we would still be using Spring today if it wasn't for Ruby
00:02:40.440 right and um that's that's a it's an important
00:02:45.720 aspect to uh to what I think makes Ruby so powerful especially in the context of game development
00:02:52.080 and um just to kind of show you the this idea of innovation these aren't PowerPoint slides this is actually the
00:02:59.040 game engine running running PowerPoint slides
00:03:04.620 but we're going to do something better now and um and here's the better thing
00:03:21.540 let me go in and I'll go ahead and change let's make the boat a little bit faster and it's acceleration faster the
00:03:39.319 bring it back to regular speed um got a built-in Rebel so I can actually
00:03:45.659 do one plus one equals two I can go back to a boring slide
00:03:54.540 back at the beginning of my presentation okay so this is what I mean by
00:04:00.900 innovation that's what I mean by the quality that
00:04:06.360 that exists with Ruby and what is possible with the language okay the game industry is completely utterly stagnant
00:04:14.459 when it comes to their uh when it comes to their tool chains and um and uh what I've learned is that Ruby
00:04:20.940 takes it to the next level makes what's I've been told that's not possible you
00:04:26.160 cannot Hot Load your environment while retaining game State and they see it and they're like but it's not fast enough
00:04:33.180 and then I show them Dragon Ruby rendering 20 000 Sprites on the screen
00:04:38.880 at 60 frames per second while Unity gets nine and they're like that's not possible what about physics and then I
00:04:46.259 show them many-to-many Collision of 1500 objects at 60 frames a second while Unity gets one frame per second and they
00:04:53.580 still don't believe me and um and we're going to go into a little bit of detail of how that's
00:04:59.280 possible okay so um this is how the game engine started and it always starts easy right how hard
00:05:06.600 can this be and um so we have a we have a strong dependency
00:05:12.240 on uh sdl sdl stands for simple Direct Media layer and uh it's completely
00:05:18.600 battle hardened cross-platform multimedia Library okay the valve steam client is built using
00:05:25.919 sdl your your mini consoles for SNES PSX all those things are powered by sdl
00:05:33.680 pretty much every commercial like large AAA games large AAA commercial game
00:05:39.360 engines are powered by this really crazy amazing Library and what you're seeing here is stl's
00:05:46.919 approach to cross-platform uh creation of a window all right that's how it creates a window
00:05:52.320 create a window 1280x720 for its resolution render back
00:05:58.080 uh show the window render a black background and present it okay
00:06:05.160 so that's how it started I was like sweet I got sto working I can create a window on every platform PC Mac Linux
00:06:11.400 iOS Android console I have games on the Nintendo switch that use Ruby wasm
00:06:18.139 steam deck got that support so I have a window creating but I have to do something with
00:06:23.460 that right so how does Ruby involved in this um mruby is really really amazing in
00:06:30.419 this regard because it's embedded that's what the m stands for so I get I get
00:06:38.280 chipset architectures available to me through the compilation process in this case clang
00:06:45.539 and it lets me Target these devices arm 64 arm32 and this was this was being
00:06:51.479 done in 2013 right wasm has a back-end compiler because we use M Ruby
00:06:57.060 we can make we can make a Watson game and this can be deployed to wasm Raspberry Pi also we support Raspberry
00:07:03.360 Pi so the way M Ruby works and there's a little bit of Machinery that you have to use you create your Ruby file
00:07:11.819 and then you run it through mruby-b-0 blah blah blah
00:07:17.819 and what this does is it creates a it creates the bit code as a C file so it
00:07:23.520 converts converts and Ruby programming to to Ruby byte code and then you compile your application by
00:07:30.960 referencing that bytecode so you require mruby.h open it and then
00:07:38.039 load your bytecode and you compile your program together and now you have something that can load up load
00:07:43.620 approving so I have a window I can load up Ruby but now how do I call
00:07:49.380 it how do I call this tick method okay and then this is your game Loop so
00:07:56.220 every video game has a game Loop uh it's your uh we call it a Sim simulation Loop
00:08:01.800 and then you're you have a render Loop that does all the rendering but our simulation Loop runs at 60 hertz so you
00:08:09.060 sleep for 16 milliseconds between each each Loop of your simulation and here we're using the M Ruby C API to
00:08:17.280 actually construct a ruby object so I I have my object class mrb underscore class underscore get
00:08:23.879 of object and then I call new on it by calling mrb underscore fun call
00:08:29.280 I love that it's fun fun call um you take your runtime class or object
00:08:34.919 class that's a comp that's a typo that should be object class sorry they call New on it and
00:08:42.000 takes in zero arguments okay so I've I have a new Ruby object it's great
00:08:48.180 and here's your here's your event Loop for sdl you pull for events see if quit was
00:08:53.880 provided if it is then you quit otherwise on that object that was created with new you call the tick
00:09:00.360 function passing in Xerox zero arguments and that's how you invoke Ruby from C
00:09:09.480 and the cool thing is that you can do all of Ruby from C you want to create a you want to create a class you can
00:09:15.899 define a class that is wired into into C functions it's literally how Ruby and M
00:09:22.200 Ruby are built right you look at array.c this is what you see there so this is how it started right here's
00:09:27.959 here's a little bit of the API um so you have some initialization we give you this environment parameter
00:09:34.740 called args because Pirates you can call it whatever you want we have the state variable which is kind
00:09:41.459 of an open struct that retains your game State across across invocations of tick remember this is executing at 60 frames
00:09:47.880 per second right let's set a Sprite angle a spin we have output options
00:09:55.140 you pass you just shovel objects into it if a response to these values you can give it a class you can give it a tuple
00:10:01.680 a hash a struct what have you this creates a label at this location
00:10:08.399 this creates a Sprite with the angle set to the Sprite angle that was defined here
00:10:15.120 if I press enter it either starts the spin or stops the spin and if it's spinning I increase the
00:10:22.740 Sprite angle so the next time that it comes in it's retained at state and this value will get updated
00:10:29.040 so you will see a Sprite spinning on the screen right
00:10:34.680 and that's what basically Powers where's my there it is
00:10:41.820 and that's what powers the screen so this is running at 60 frames per second all the ripples all that is is being
00:10:47.760 communicated at that rate okay as far as rendering it's Hardware
00:10:53.399 bound so as far as as fast as my Hardware can render the screen the scene it will render it
00:11:02.459 so this is how it started it's never How It Ends and um and we're getting into the aspect
00:11:09.720 of what is a runtime when does a library or like a small little little
00:11:15.120 enhancement to M Ruby become more than more than just the enhancement and review
00:11:21.480 and um this is what the dragon Ruby runtime looks like I'm not going to talk through
00:11:28.200 this entire thing I just wanted to create this thing so I can do some like cool zooming stuff
00:11:33.660 and again this this is kind of like the cool part of using a game engine to create your slides Prezi eat your heart
00:11:39.540 out freaking awesome that's the only reason I created this thing but um but at a high level uh so
00:11:48.120 talking about what's the difference between a language I mean like a a library a framework a
00:11:53.760 runtime a language one of the key differentiators of of a dragon Ruby is
00:11:58.980 the simulation thread so um you think about node.js having an event Loop well this this runtime
00:12:05.940 instance the dragon movement type effectively has an event Loop right so we come in every 16 UH 60
00:12:12.899 second uh 16 milliseconds and and run this event load for you this gives you uh some nice things I can aggressively
00:12:18.899 GC for you on your behalf because I know your time slice is just that long I can
00:12:24.240 drop I can shut down the VM do a GC for you because I know your run your code's not running and then bring
00:12:30.120 it back up so it's it's a it's a really powerful concept asynchronicity is beneficial here too
00:12:36.060 because you can send out an HTTP request that's an async request and then you don't have to worry about
00:12:41.940 any kind of promises or callbacks because the next time you enter you enter the this uh this tick you can
00:12:48.540 check to see if the request is finished and then perform processing on it completely simplifies this this idea of
00:12:55.560 a async async programming fibers would fibers benefit from this also you have a
00:13:01.620 fiber you can take the fiber for one iteration and then come back and take it again for the next iteration there's a
00:13:07.079 lot of power there all right so that's something that differentiates ourself from from the
00:13:13.980 rest of the rubies we've added expanded the core load quite a bit
00:13:19.560 Fizz FS is our file access you don't have standard lib on a console
00:13:25.920 or web IOS and Android are different they're sandboxed you can't just call file.read
00:13:32.519 it won't work it will explode because you don't have the standard living in these environments so we had to add our
00:13:39.540 own cross-platform standard lib cvars for cvars for configuration matrices are
00:13:45.720 lovm intrinsics Jason parsing XML parsing are built in HTTP is built in
00:13:52.260 required did not exist in mrb we had to add that and then we've got a single
00:13:57.300 single header C libraries that kind of expand on math core Libs and some of that other stuff see it's already
00:14:03.420 getting boring it's like oh God stop talking um our render thread is Hardware bound
00:14:08.880 which is good so it runs it renders as fast as you allow this is where you process our textures audio shaders
00:14:15.060 HTTP support for our 2D rendering Pipeline and then of course this runs on VR also so we've got uh you can build VR
00:14:22.139 games that are hot loaded in Ruby it's pretty freaking cool and I can show you that um so we've got a rendering pipeline
00:14:29.040 as far as the tool chain you call this function to package your game and create your
00:14:35.220 your binaries for wasm PC Mac Linux Raspberry Pi and then IOS and Android
00:14:40.860 and Oculus and the resulting binary the entire runtime is 4.5 megabytes the
00:14:47.519 entire thing is 4.5 megabytes which is which is kind of insane I think our logo our visual assets for the logo and some
00:14:54.600 of the other stuff are actually bigger than the actual runtime um but uh it's because we can be so lean
00:15:01.199 and and because we can Leverage The Power of clang and the compiler and the elbow VM infrastructure that allows us
00:15:06.300 to do this you can expand it if Ruby's not fast enough you can create your own foreign
00:15:11.940 function interfaces to see you pass it through this uh bind bind process and it'll create the glue for
00:15:17.880 you so you can invoke those C functions through the Ruby itself and finally we're working on something
00:15:23.459 called firestorm um because of course dragons so the obvious name is Firestorm you've gotta
00:15:29.459 you gotta keep that we're gonna we're gonna create a command line based version and we're going to have a rate we're going to create rake guess what
00:15:35.579 we're calling it come on Drake see it's just it's so
00:15:41.579 perfect it's so perfect um but yeah I imagine having having a cross-platform zero dependency
00:15:48.899 x copy Deployable you can put in a zip Drive run a program that does your build automation for you right no no
00:15:56.160 installations required so just to speak a little bit about firestorm
00:16:02.579 I'm gonna go into my Rebel and here's game.rb right and we've got this compiler thing where
00:16:08.639 we just dump uh dump the stuff to the screen okay so these are the op codes that
00:16:14.040 you're seeing for that for that boat body mcboatface game that we were looking at
00:16:19.560 and um the really interesting thing about M Ruby and how it differentiates itself from uh the C Ruby runtime is
00:16:27.180 that it's three it's op code based but it's register based so instead of being a stack based
00:16:33.000 virtual machine it's a register-based virtual machine and the llvm infrastructure that exists
00:16:38.519 and what clang is built on and how it's optimized and why it's so fast is because the lvm is a register-based
00:16:44.759 virtual machine so it uses something called Static single assignment my eyes glazed over usually at this
00:16:50.820 point too and because of static single assignment you get some you get some optimization from that it can do some
00:16:57.180 dead code elimination kind of compress the uh compress your op codes so because M Ruby is register based and
00:17:04.860 because llvm is register base we have a one-to-one mapping to llvm and their op
00:17:10.020 codes for the most part there's caveats with how jumps are handled in while loops It's Tricky details right hand wavy but
00:17:18.660 the theoretical aspect is that because because mrb is so in line with what llvm
00:17:23.939 provides out of the box our jet ends up being optimization passes provided directly by lovm
00:17:31.260 right so that's that's the next level that we're that we're taking uh taking the runtime to and it kind of happened
00:17:37.919 by accident right we didn't know that I didn't know when I first did my hello world that mruby was registered based
00:17:43.740 but um it ends up we'll be able to greatly benefit from that okay
00:17:49.020 so that's that's the gist of this picture and we have a whole 12 minutes to talk about fun and cool stuff now
00:17:57.419 um so uh just to just to give you or we can just leave if you if you just hate me and you want to go that's that's also
00:18:03.480 fine um so uh we have a phenomenal Community uh so our if you go to our Discord
00:18:09.780 server you're going to find you're going to find new Ruby devs because they've never done Ruby before and you see the
00:18:15.059 magic again in their eyes it's just it's really really great it feels good
00:18:21.240 um and some of our community members end up making tweet carts where you just do
00:18:26.400 code golf with with Ruby in the API and they're like hey Amir can you add this
00:18:31.740 this instead of calling args.appos dot solos can we just call it sld exclamation point like why would you
00:18:37.980 ever want to do this because I want to make a tweet card I'm like fine I'll add it and so we added and so this
00:18:45.240 well no no no no no that I just gave it away sorry this creates this
00:18:54.299 and this makes this
00:19:00.539 that makes where I use Hadouken
00:19:07.320 and um this monstrosity makes Breakout
00:19:14.160 and so there's there's a lot of like this is what it goes back to the art The Innovation right we're so stuck in our
00:19:20.820 ways with software craftsmanship and the way Ruby exists today and this is how we're supposed to build software and we
00:19:26.760 don't have the freedom and the ability to like rethink and play around and I
00:19:32.220 want Dragon Ruby to be that facet to be that uh to be that Avenue for for you to build build things that are just fun and
00:19:39.000 stupid okay all right 10 minutes for questions
00:19:46.500 foreign questions yes
00:20:02.820 that's a good question so I brought up our comparison and performance comparison between Ruby and unity and uh
00:20:09.780 the question was well how how are you getting that speed and unity is not able to and that goes back to that issue that
00:20:16.980 the tool chain and the environment is stagnant Unity has no competition they own they own the space so their
00:20:24.480 motivation to make it faster to make it better is somewhat Limited they'll do what needs to be done to uh to build out
00:20:31.620 their environment and a part of that part of the challenge that Unity has is that they've been around for a very long time they're built off of a mono runtime
00:20:39.299 which is over a decade old at this point there's a bit of cruft there and then they've added features and bloat and
00:20:45.480 more features and bloat and then you're just left with a lot of heavy stuff in that environment
00:20:50.580 so because of that your render pipeline is really really weighted your physics
00:20:56.220 pipeline is really really heavy and it just builds up the other aspect is that
00:21:01.799 Dragon Ruby is primarily 2D we're not we're playing around with 3D for VR stuff just because I want to make Space
00:21:08.340 Invaders as a 2d game that comes at me and and it looks awesome but we're intrinsically 2D for Unity 2D was added
00:21:16.200 after the fact so all those things kind of add up and you're just you're left with the hodgepodge of of what's
00:21:21.720 possible because uh because we we said okay we want to be lean mean we're right
00:21:27.660 against the metal with sdl that allows us to be as fast as we are
00:21:32.940 you're welcome any other questions yes
00:21:43.679 uh what are what are some games that are built with dragon Ruby that uh y'all have probably played but don't know that
00:21:48.720 you've played um so uh I am I used to be able to say that I'm the only Ruby Game Dev but now
00:21:55.200 we've got thousands of us which is great um but as far as my commercial uh
00:22:00.240 commercial games I have uh my air quotes claim to fame uh where's where's the
00:22:12.000 version.net so these are the titles that I've built
00:22:17.100 using using Dragon Ruby the biggest one would be a noble Circle
00:22:22.320 it was it was actually published about in The New York Times so it was the best-selling iOS game back in 2013.
00:22:30.120 I've been to this the page way too many times uh wait here's new yorking New Yorker
00:22:37.799 yeah a dark room the best selling game that I can't explain so um across all my titles I'm at 3.1 million downloads
00:22:45.120 and sales and stuff and um uh I've got four or five games on top of that of
00:22:51.600 course a dark room that's our that's our Discord server they're awesome you should go there
00:22:57.539 a dark room in 10 Nintendo switch there we go
00:23:02.640 so yeah and this is this is on the Nintendo switch right now
00:23:07.860 just personable but um usually when I get that question they'll say well what about games that
00:23:13.260 other people have built I'm like okay if you want that I I don't have anything at that point right
00:23:19.620 right but um but yeah I want y'all to be able to build this stuff I want you all be to explore you all are going to be
00:23:25.620 the next I want you y'all need to be the big studio right I'm I'm just the small guy
00:23:30.960 that builds stupid little things and and trolls people yes
00:23:41.820 that's a good question so so how do you get started with with dragon Ruby or even begin to get into
00:23:47.760 game development um so you wanna you wanna download the engine right
00:23:53.159 so you do dragonruby itch.io and like I said it's it's available uh
00:24:00.480 it's available on sale zero through the conference you'll get a zip file you double click to unzip it and in
00:24:06.780 there there's a there's a 100 plus sample apps that kind of incrementally gets you through through putting a label
00:24:13.380 on the screen to something you know fairly exam uh fairly Advanced so if I one of my sample apps break
00:24:20.760 uh this is my local Dev environment which is why I'm just staging a sample up I think it's called moving
00:24:27.059 moving a Sprite cool so there's a sample app called moving a Sprite I'm glad I'm glad that worked and that's
00:24:33.240 all it is all right so it shows you how to move a spike okay after that we've got more advanced
00:24:38.880 reference implementations so this is a full-blown game that's
00:24:44.580 available in the in the engine itself so a bunch of reference implementations
00:25:12.799 ah that felt that was great it was great so I'm just gonna go to cow game over
00:25:20.700 return take that game
00:25:27.419 what are you talking about see I'm freaking fantastic at this thing foreign
00:25:38.760 so uh we've got a lot of uh a lot of sample games in there also and um the
00:25:44.580 the sample ups are ordered uh by simplest to increasing difficulty so you
00:25:49.679 just start at the directory with zero zero underscore and then work through it um Lori uh right here in the in the
00:25:56.159 front row um she's uh she's got a dragon ruby.school which is which is your your
00:26:01.620 nice you know guided guided video series on on how to build video games
00:26:06.659 so a lot of options there and and I mean a part of it's like Ruby Ruby is one of
00:26:12.480 those places where the community is kind so come to the Discord we're always there to help lots of people there to
00:26:18.840 help doesn't matter yes
00:26:36.919 that's a good question so the question is that uh we're we're currently on 2D we're moving into 3D what impact do we
00:26:44.220 have on performance how does it affect the complexity of your game what does that all look like okay and this is
00:26:51.720 something so this exact game that you uh that you saw there for Flappy Dragon I'm
00:26:56.880 gonna I swear he wasn't a plant so I'm going to bring up the the VR
00:27:02.820 version of this so we've got a local uh we've got a
00:27:08.340 simulation environment for for VR it's not perfect you can see that it kind of does horrible scale and whatnot so
00:27:14.640 here's the game running in VR and as far as the Sprites you have an additional property which is
00:27:21.120 the Z property so you can take a 2d game and still fail miserably at completing
00:27:26.460 it um uh you can take your 2D game and make it
00:27:31.799 an Oculus game and then what you're seeing here is that these are all just Sprites but they have an X and Y
00:27:37.200 rotation right and then um we let you we'll let you walk around the
00:27:43.679 the actual like the actual uh space so you can see yourself dying from
00:27:50.460 behind um and um and that's kind of how we're
00:27:56.100 taking it so would you would you make would you make the next uh Final Fantasy remaking this no I would not recommend
00:28:02.820 that but can you start playing around and making like a a nice little uh you know Charming little uh VR game
00:28:09.480 absolutely right and that's what we're that's what we're trying to explore let's see where we can go with this let's see how we can
00:28:15.480 innovate but uh we'll be fast we'll get there
00:28:20.640 one minute 45 seconds any other questions yes
00:28:27.720 I'm glad you enjoyed it sure so um I actually have someone
00:28:35.460 that's played one of my games in the audience that's amazing that's amazing um
00:28:40.980 yeah foreign ever buys anything at full price it's
00:28:46.080 like I got to put it at like 69 67 cents for anyone and pick it up um so um the development process for uh
00:28:53.159 for a dark room especially for the Nintendo switch was exactly why I created Dragon Ruby I I don't want to
00:28:59.279 compile move it to a device deploy it there run it and go through that process so um the drive the machinery and dragon
00:29:07.380 really allows for remote Hot Load so you can put you can have your game running on your device save a file and it will
00:29:13.440 update on the device and um you can if you've got a steam you can see that you can actually see that in action with the
00:29:19.799 uh with the standard license and that's kind of how I evolved it so you just you
00:29:25.500 start with just the simplest pieces of the game single file get some things on
00:29:30.779 the screen play around with it you've got this live environment where you can use the rebel to
00:29:36.120 change and invoke functions to take yourself back if you make a mistake and that that's kind of the iteration
00:29:42.480 process with respect to video games so um one thing I want to do is make sure
00:29:47.820 the visuals look good so we you had a logical resolution of 720P you don't have to worry about we handle
00:29:53.700 all the HD scaling and stuff so you know that zero zero is at the bottom left and 1280 by 720p is at the bottom 1280 by
00:30:00.960 720 is at the top right and then you build out your game from there and so um it's just that iterative life
00:30:07.080 process that we kind of expect from Ruby and that's kind of how it feels
00:30:12.299 you get a lot of happy mistakes with that live environment you're like why did that happen and then and uh a lot of
00:30:18.659 inspiration there it's really nice you gotta try it it's fun all right we're out of time um I've got
00:30:24.899 stickers I've got stickers the stickers get the clap really