Code and the Coding Coders who Code it

Episode 38 - Amir Rajan

Drew Bragg Season 1 Episode 38

Ready to unlock the secrets of game development using Ruby? Join us as we chat with the ingenious Amir Rajan, the mastermind behind the DragonRuby Game Toolkit. Amir takes us on a captivating journey from his corporate days in app development to becoming a trailblazing indie game developer. You'll be amazed at how Amir leveraged Ruby's expressive power to create innovative games and how his monumental success with the iOS port of "A Dark Room" reshaped his career. Prepare to gain an insider's perspective on the unique challenges and rewarding experiences of adapting Ruby for the gaming world.

Ever wondered what it takes to test a real-time game with precision? Amir sheds light on the stark contrasts in testing between app development and game creation. Listen as he breaks down the complexities of managing long-running states, debugging frame-perfect bugs, and implementing replay systems for maintaining consistent gameplay experiences. Using a racing game as an example, Amir explains the intricacies of regression testing in game development, offering a fascinating glimpse into the meticulous world of game testing.

Curious about what it takes to create a successful hyper-niche game? Discover Amir's strategic approach to captivating players within the first 20 seconds and crafting a minimum viable product (MVP) that stands out. Drawing inspiration from literature and focusing on underserved communities, Amir shares the potential of niche game concepts—without competing with big-name studios. He also tackles common misconceptions about Ruby's speed, demonstrating with DragonRuby how a well-implemented runtime can rival even the fastest engines. This episode is packed with invaluable insights for both aspiring and seasoned developers, bridging the gap between app and game development in innovative ways.

Send us some love.

Honeybadger
Honeybadger is an application health monitoring tool built by developers for developers.

Support the show

Ready to start your own podcast?
This show is hosted on Buzzsprout and it's awesome, not to mention a Ruby on Rails application. Let Buzzsprout know we sent you and you'll get a $20 Amazon gift card if you sign up for a paid plan, and it helps support our show.

Speaker 1:

Hello everyone and welcome to another episode of Code and the Code Encoders. Who Code it? I'm your host, drew Bragg, and I'm thrilled today to be joined by Amir Rajan from DragonRuby Ruby community as a whole. Anyone who's not familiar with you, could you do a brief introduction about what you do?

Speaker 2:

I'm Amir Rajan and the short version is I'm a code hobo and I just kind of work on random things and sometimes interesting things happen. I'm a code hobo and I just kind of work on random things and sometimes interesting things happen. And one of those interesting things happens to be DragonRuby Game Toolkit, which is a game engine built on Ruby, and I've been doing indie game development like commercial, full-time indie game development with Ruby for the past 10 years now, and so I've got six commercial titles, my claim to fame being a port of a dark room, which hit the number one spot in the iOS app store, number two on Android has a console release and I just last year released to Steam, and so I'm a game dev using Ruby.

Speaker 1:

That's super awesome and not something you hear every day. I also love code hobo as like a word for describing like I don't work on one particular thing, I just move from code base to code base. That's awesome I am so interested in. I'm not a game developer. If I ever had anything resembling free time, I would love to give it a try, but that's a lot of math and that was how I got into programming was cheating on math tests, so maybe not. But also the idea of being able to use Ruby for game development is so awesome. So was it? You were a game developer and wanted to use Ruby, or you were Ruby-ous and wanted to build games, and that's how everything was born.

Speaker 2:

Ruby, especially dynamic languages, specifically Ruby. People talk about Ruby and they say it's a beautiful language or it's an expressive language and there's like an artistic flair to the language that when I started doing game dev with Ruby like versus app development it's like working with oil paints, I think of. Like statically type languages are like C sharp, you're working with marble and a chisel, you make a mistake and the correction is so difficult and the exploration's much harder. But with Ruby it's just working with oil paints. You just kind of work with the canvas and nudge things around. And the dynamic capabilities of the language, the DSL, the expressivity of the language it really works really well for game dev and a lot of those nuances is what I discovered when starting to build games with the language itself.

Speaker 1:

So how did that come to be? As far as I'm a Rubyist, I want to build games. Okay, now what?

Speaker 2:

What was the spark that was like I can do it this way, or like was it just nonstop investigation until I was doing corporate development right out of college and I got really burned out and I was like I'm just going to take a sabbatical and just kind of do my own thing for a little bit, live off the savings, and then, once I'm refreshed, then go back into a cubicle writing tax software. And so I'm going to build a game. And there's a product called Ruby Motion which allows you to use Ruby for building iOS apps. And I was like, okay, I can do iOS development. And I found a game on web-based game called A Dark Room it's like an incremental kind of ASCII-based roguelike built by Michael Townsend and I emailed him and said, hey, let me port this over to iOS and see if we can do something. So then I used RubyMotion Ruby and started porting this game over. And then that's kind of how it started. And then I was like, wow, game dev is actually kind of fun. It's interesting, surprise, surprise.

Speaker 2:

And so after that I started building additional commercial titles, especially with the success of the first game.

Speaker 2:

And then it came into like, okay, well, with respect to Ruby motion and just building games with Ruby, you're right, it was kind of like that exploratory process where you make a lot of mistakes, trying to discover like patterns, and I had a mental like do, a huge mental shift from like app development to game development and there were a lot of challenges there. But then I think it was like, yeah, from 2013 to 2017 was when I built a lot of commercial titles and then I was like, okay, I'm seeing these patterns emerge and I'm seeing the things that I like about Ruby and I don't like about existing game engines and those eventually codified into Dragon Ruby. So like from 2013 to 2017 was just building commercial games and the onus of being cross-platform and then releasing to the Nintendo Switch was that final straw that broke the camel's back. I was like, okay, I need to really think about what this environment will look like. And then all those lessons I learned just got extracted or codified into the engine that you see today. That's so cool.

Speaker 1:

That's such a neat starting with this app-based game and then moving into. Okay, we're going to go full steam ahead, building a game engine that becomes DragonRuby.

Speaker 2:

The really interesting part, especially in this domain, is like Ruby's a very mature language, especially for app development, and so there's a lot of established patterns and a lot of ways you do things, like of course, you're going to build your controller or your MVC application in this specific way. And with respect to game dev, there's established patterns, but they're always in the context of I'm using a statically typed, rigid language that can't do what ruby can do, and so trying to just take those same patterns and apply to the language ended. I was like wait, this feels excessive, like there's no reason to have, uh, all these like different aspects of boilerplate and they establish patterns.

Speaker 1:

And then that discovery process was it has that same feel of upheaval, from like using spring to rails right, look at all the stuff I'm not doing kind of vibe to it so the way that the episodes normally work because that ended up being like a really long intro because I was just so excited to start picking your brain about dragon ruby but normally the way that the show works is I will ask you three questions in addition to like the nine I just asked you what are you working on?

Speaker 1:

Yeah, what are you working on? What kind of blockers do you have? It could be a current blocker. Or if you don't have one, like what's a recent blocker, how'd you go around solving it? And then the last one is what's something cool, new or interesting that you've recently learned or discovered or built? It doesn't have to be coding related I have a feeling it might be in this case but it doesn't have to be so, just to make sure we don't get lost, because I will go down so many rabbit holes if we don't stick to the program. Amir, what are you?

Speaker 2:

working on? What am I working on? So I have a game in pre-production and it's called the Little Probe and have you read we Are Legion, we Are Bob. No, it's a great book. So think, hitchhiker's Guide to the Galaxy meets Von Neumann Probes. So Von Neumann Probes is this idea of your own consciousness is put into a machine and then that machine can replicate. So then you start replicating your consciousness across time and then can search the universe. So the Little Probe is a metroidvania where you're a Von Neumann probe exploring a dead civilization and a dead planet and you get power-ups and all the different facets of platforming and kind of think Metroid, right, it's a Metroidvania, and that's what I'm working on.

Speaker 2:

As far as, like, the hurdles, the biggest hurdle it's math, it's always math, it's always math, it's always math. That's one of the reasons why I do 2D games is because the math is way simpler. I was afraid of math, but it really isn't that bad. You need to have a good trick foundation. So if you know trigonometry, trigonometry, geometry and algebra, those things together gives you pretty much 80% of what you need for building 2D games. So the most recent hurdle I had was ramps Ramp collision like how do you move up a ramp but keep the player pinned to the ground while gravity is being applied and stuff. But I figured it out, I figured it out. There are quite a few blog posts out there that kind of show different approaches to using ramp collision and the math around that. But that was my most recent hurdle.

Speaker 1:

Yeah, that's a blocker that not a lot of people have said on this show, because most of my guests do app development. What do you think the biggest difference between the mental model you use for doing app development and the mental model you use for game development is?

Speaker 2:

I think the biggest difference is you have long running state when it comes to a game and that state is updated at 60 times a second. So if you think like a controller action, it feels kind of transaction. You got the HTTP request coming in, you rehydrate, you have some short running state for the life of that function, maybe you have some session stuff, but outside of that you're in and out and that's it. But for game dev, this game object, this singleton, stays around for hours. It could pretend you know someone having a long play session that ends up staying around for hours and then the facet of it being at 60 frames per second or running this function at so many times.

Speaker 2:

When it comes to debugging, the common debugging approaches are like the testing approaches that we use for app dev. It's much harder for game dev because you make an action and it's 80 frames later that the bug or like some compounding stuff ends up surfacing to your app. And where the bug appears is not necessarily the frame where the cause exists. So you're not dealing with only backtraces but time traces to try to figure out where something breaks. So yeah, your approaches to testing and regression. It's different.

Speaker 1:

What do you do for testing in game dev? Can you unit test a game? Can you do a system test? Because I can think of how I test a web-based application, but, like you just said, when you're testing a web-based application, you're testing essentially a part of a transaction, right? That sounds like it would be a lot more difficult to test bits of the game in isolation. But maybe that is how you do it. How does that work?

Speaker 2:

So I think for turn-based games where it's kind of like a tactical if you get like a tactical top-down RPG or something like that a lot of the testing practices that you would use for app dev mostly apply right, and the reason for that is that you can codify that slice of time.

Speaker 2:

You can say okay, here's my setup, here's where the player is, are they close to the enemy? Then the attack option should show up there. What gets really tricky and what gets much harder to test is real time games. So anything with physics in there becomes a little bit trickier. Because I've had situations with that ramp collision. I'm going to have nightmares about ramp collision for a very long time, but it feels great. Right, the player jumps, he runs up the map, he runs down dashes, all that stuff. But there's a situation where if I do a frame perfect input of pressing forward and then at the same time press jump, he would tunnel through the ramp and fall out the other end. And it's like, okay, I have to replicate a frame perfect input of hitting left, then right and jump at the exact same time on the same frame and then he drops down through the ramp. This is ridiculous. So as far as applying that. The cool thing is that and it goes to this idea of the status quo of game engines today they just accept that this is something that you have to deal with, though they know I'm putting a replay system into DragonRuby so you can actually say all right, I'm going to start a replay. It resets your game and then you fiddle around with it until you get the bug and it captures that input history. You can have the replay run every time you save code. So DragonRuby is all hot loaded, because Ruby is amazing like that. And so what I would do is I would say, okay, well, what if I set the gravity to zero before I execute the jump function? So I'll set the gravity to zero and it would automatically run the replay and then go through those steps and then see if the player drops down through the stage or not. That's kind of how you have to do some of these regression facets. It's almost like systems testing or end-to-end testing, but it's just a different mindset with respect to that.

Speaker 2:

And backfilling with a unit test. There's so much context that has to be communicated within that unit test that it's just hard to say let me do a frame, perfect jump and then the value of gravity should be zero at the next frame and you get a failure. And then you're like, okay, it's a failure, but I wrote this test three months ago and I have no idea why this is a failure or not. So that's one facet of it.

Speaker 2:

Another tricky facet of it is that, like I was building a racing game, and a racing game is called a car that turns my game names are ridiculous, so it's a car that turns and I'm playing around and you take that first corner, how can you like deterministically quantify or describe it? Doesn't feel right, right, right, it's a little stiff, or it doesn't float as nicely as I wanted to. And then you tweak some numbers and, okay, it feels good now, but what's the regression test for that? And then you're like, okay, well, it feels right for this turn, but the next turn doesn't feel right. And then you tweak the values again. You're like, okay, both turns feel good, but now your unit test fails because the values that you originally set up are not the same. And then you're like, well, test it assert that game is fun.

Speaker 2:

So those kinds of facets of it. And then one challenge I had with a car that turned the game was that I had a really good initial release and I was like, okay, this feels good and I made the controls a little bit more floaty and it felt really nice. But because I did that, there was a part of a track that is impossible to get around because the corner is too tight. That is impossible to get around because the corner is too tight. So now you've got this overarching issue of okay, with the values and how I've changed them, is it still possible to complete the 15 tracks that I have in this game? I don't know the answer to that.

Speaker 1:

That's why I came in and was like, please help me, please. Well, actually, speaking of help, there's actually a pretty cool. I got to shout out my podcast host, buzzsprout, which is a Rails app. So yay for using Ruby products in the wild. There is actually a link in the show notes. When you're viewing that, buzzsprout automatically adds it. You can text the show. So if you're hearing what's going on with Mir and like, oh, I know how to solve that, I don't know if anybody does Text when you're listening to this episode and I will relay it to him and we will use this super cool new feature from Buzzsprout. Maybe we can get you unblocked with a text message.

Speaker 2:

I love the idea of live streams, it's lots of fun. And so another facet of the testing thing is like, of course we're both apparently Zelda linked to the past or Zelda fans. And so the other facet of it is that when it comes to games, humans find games interesting for a specific problem domain. If it's a puzzle game where it just takes mental compute to try to figure out like move covers to try to figure out the answer, then it's apparently those games are more boring to play than games like Zelda, and there's like a really old write-up of Zelda. And the problem then it's apparently those games are more boring to play than games like Zelda and there's like a really old write-up of Zelda and the problem domain that it exists in and apparently it's an NP-hard problem.

Speaker 2:

Zelda, a Link to the Past, is NP-hard and that algorithmic problem space is something that computers just have a very difficult time solving. So how do you write a test to solve Legend of Zelda when it can't be solved? There's this facet of you can't even write an end-to-end or system level test that says beat Zelda for me and make sure that it can be done. And there's, of course, advancements that are happening there, but these are the kind of the challenges that games have. It's just that what we find interesting ends up being really difficult problems that computers have a hard time solving. So that's another challenge with this idea of like testing and regression parallel to app dev too.

Speaker 1:

But like, how do you come up with an idea for a game? I know you said you originally did a port and a car racing game is at least a solid enough concept that when you're like it's a car racing game, it's like okay, there might be a unique thing there, but it's probably a car racing game. Yeah, a metroid like platformer I can sort of visualize playing it in my head. But like, how do you come up with the idea for everything else other than it's a platformer? We're going to go from one end of the screen to the other and fight bad guys, everything else that goes into a game. Before you can even come up with writing the code, you have to have some idea of what's going on. How does that work?

Speaker 2:

And you're right, it's got a lot of correlations to app dev and the overarching theme is to fail fast. So fail fast and control scope is kind of my overarching tips. But what I end up doing is I think of games that I like. So an example would be, let's say, legend of Zelda, and I think about that game and I think about all the things that I appreciate about it and I take something away from Legend of Zelda. Maybe I take away a bunch of the items. Is it still a game that I would play?

Speaker 2:

And so you're trying to distill an experience down to the parts that you find that you connect most strongly with, and so that's kind of how I decided on an idea or a concept pull out from the feature set and think about the feel of the game. So what I tell people to do is think about your perfect five-star review. What does it say? It's not going to say I like this game because it had procedurally generated maps, and it's not going to say that right, it's going to have more facets of like. When I first picked up that sword and left and was able to charge it and throw out a fire beam, I felt like a powerful, godlike hero, and thinking of the five-star review is what helps you figure out that forest for the trees kind of idea. So you have your distillation to control scope, you've got the feel of the game to help guide your approach to the actual mechanics and stuff. And then the final thing is a 20-second demo where you communicate that hook within that 20-second period.

Speaker 2:

So the challenges though, especially within the game development. I'm not nintendo, so the player is not going to give me the benefit of the doubt and wait two to three hours before that big, nice facet of game mechanics comes in. And so, with respect to like live ops and what people and the industry and how they measure metrics, so from the point that they open the application, menu, screens, controls, splash screens, all that you have 20 seconds before the falloff rate ends up being more than 90%. So you have to say get them into the action, communicate why they should continue playing your game within that first 20 second period. So that's how my initial prototyping ends up happening, and then from there I expand on this.

Speaker 2:

Oh yeah, I've hooked them for the first 20 seconds. How can I keep them playing? I've communicated why they should or shouldn't play the game, and then it's about expanding on that longer game loop. But that's kind of how I approach ideas. I think about game. You know, draw inspiration from literature, like we Are Legion, we Are Bob games that I enjoyed playing, and then distill it down and focus in on those things that I found valuable and then the final thing is finding those niche audience that value the same things you do.

Speaker 1:

You were pretty successful with at least one of your games. A Dark Room was up there, but is there. I know why that got super successful it was because I have no idea why you have no idea. Okay, it was one of those viral phenomenons or just the right person tweeted about it, okay.

Speaker 2:

The interesting thing, though, is that, with respect to my subsequent games, the success is primarily long tail and hyper niche. So the idea there is that I'm not trying to compete with the big AAA companies there. What I'm trying to focus in on is there's an underserved niche community that loves XYZ and cannot provide a digital interactive experience for them that they end up appreciating. So the definition of success ends up being about not trying to put all your eggs in one basket and hope for that lottery ticket, but to focus in on those hyper niche experiences, create your wheelhouse, your identity from that perspective, and then service those air quotes smaller communities. So our dark room was out there, like whatever. So then the question was can I capture lightning in a bottle twice? And so I ended up making a pre-sequel, and that ended up in the top five of the app store, so it did really well. And then I was like okay, can I capture lightning a third time of the app store? So it did really well, and then I was like okay, can I capture lightning a third time?

Speaker 2:

And so what I ended up doing was I created a narrative, satirical, rhythm-based game based off of a book that was written in the 1800s called Flatland Romance of Many Dimensions and it's about this 2D world and it basically was a satire on Versailles and how royalty and the life of Versailles was like. You know what I'm going to take this idea of a 2D world and the concepts in there and then do a satirical commentary of the 20th century in the context of a game, and it ended up doing well too. So it made it into, I think it was like number nine overall and it's been in the top 100. So I would like to say that maybe this model can work, this idea of digitalization find your unique audience, find your voice and cater to those people.

Speaker 1:

But I have no idea what I'm doing basically, it sounds like a lot like app dev from the startup perspective of like keep your mvp very small and very tight and like focused. You're not going after google or you're not going after Amazon. The StoryGraph did not go after Amazon. It went after Goodreads, which is a lot smaller of a thing but it was a lot slimmer and it was a lot tighter and it kept its focus on its audience and that's why Naughty's been so successful with it. It solved a problem that people had. Yeah, goodreads is an amazon product, but she wasn't going after amazon.

Speaker 2:

You're not going to make the next witcher game the other challenge that you have is like, with an app idea, if you pitch it to someone say, hey, wouldn't it be cool if you had xyz? That made this part of your life easier. And you're like yes, please make this and take my money. And when it comes to games like what do you think about a satirical commentary of the 20th century as a top-down 2D rhythm-based game, they're like I guess I don't know, I guess it's sort of like pitching books to a degree.

Speaker 1:

Like I have this idea for the story, you don't write the whole novel before validating the idea, but you have to convey it.

Speaker 2:

There's a really good book called the Mom Test and it's this idea of idea generation and then vetting your ideas and taking it to market. I was like, okay, this is definitely going to help me. And then halfway through the book it says this is great and all, but it's not going to really work for games. I'm like, ah, shakes face. But yeah, that's one weird facet of it and that's why I say you build a 20-second experience and hook them and make sure that you have the idea of your perfect five-star review in your head, so you know what kind of emotions and feelings you're trying to convey, and then you need to communicate that very quickly and I think that helps mitigate the risk, but it's just difficult.

Speaker 1:

So the power of Dragon Ruby. Like we're talking 2D games, not 3D. So for anyone who's not like a super big gamer and doesn't quite understand what we're talking about is not like a super big gamer and doesn't quite understand what we're talking about, If you think of, like the new Final Fantasy 7 games that just were rebuilt, like that's very 3D animations versus a game like Stardew Valley is a 2D game. The big difference there, aside from like the computational stuff of like 3D math, Math Right Is the assets. The sprite is, I believe, what they're called in 2D math, Math Right Is the assets. The sprite is, I believe, what they're called in 2D games. Yes, or I might be aging myself back when, like we used to play games in the browser but sprites those little 2D guys versus that full-blown like Blender 3D animation model Yep.

Speaker 1:

How does that work inside of Dragon Ruby? Is it just like, hey, I've got these pictures, these PNGs or SVGs or whatever file format, and you upload them? And then you're like, okay, and you're going to move like this, and when you're doing this, it's this sprite, and if it's standing still it's this sprite and it's just to get it look the way that you want. You're just uploading assets, or does DragonRuby have something in it where it's like here's how we build a Sprite pixel by pixel.

Speaker 2:

So the tech behind it is really cool and so we have a core dependency on LiveSDL. So SDL stands for Simple Direct Media Layer and it's a C library that it's been around for 20, 25 years, like Valve. Steam Client is built with LoveSDL. So when it comes to like battle-hardened kind of thing, that's where the magic happens. So what SDL does is that it's a abstraction over all the operating systems out there mobile, android, web PC, mac, linux, console, et cetera.

Speaker 2:

And so you tell SDL render this air quotes sprite and it figures out how to render it on that specific operating system. And so the air quotes official term is that it's a texture and for 3D I think it's called material. But you're basically saying okay, when you say, render this PNG on the screen. Behind the scenes, what we're saying okay, get the PNG, load all the bytes from it, create a texture out of that PNG, cache it and then tell SDL to render this texture at this specific location with these specific dimensions. And so what SDL does behind the scenes is it takes that RGBA I forgot the explicit format but that byte array and that specific byte array and that texture it's a common construct for across gpus, so gpus understand this data structure of an array of bytes that represents rgb values, rgba values, on a screen. So what stl does behind the scenes is it says, okay, you have this texture and I'm going to give you another program which is called a shader, and I want, hey, gpu, I want you to take the shader program and this texture and do the work to present it onto the screen.

Speaker 2:

So what a shader is? It's kind of a C-based program, it's a C-based dialect. That is, I guess, highly parallel. So the value of a GPU and its power and what it brings to the table is that it can run a very small function extremely fast across all pixels on the screen. So what happens is that texture that has 8K worth of values gets sent to the GPU and the program gets run for each pixel on the screen. So, yeah, you think about that 8K texture. Yeah, yeah, yeah, it's saying for each pixel, give me the RGB, run this thing. And so for Windows, the shader language is Vulkan or Direct3D. For Linux it's OpenGL. For iOS and Mac it's Metal. And then your consoles have various ones. They're all kind of consolidating on Vulkan. But that's the GPU tech that happens behind the scenes. So the great thing in Dragon Ruby, is you just shuffle a hash into an array, that's my next question how much does Dragon Ruby help me with this Cause?

Speaker 1:

I'm lost already.

Speaker 2:

Yeah, you give it an X, so we have a logical canvas of 1280 by 720 and it's geometric.

Speaker 2:

So zero, zeros in the bottom left-hand corner.

Speaker 2:

So if I want to render a sprite in the bottom left-hand corner, we've got a argument called outputs and it's an array and you just do outputs and then you shovel a hash or an object that responds to X, y, width, height and path, which is your PNG path, and it'll render it to the screen and that's all you have to do.

Speaker 2:

So when it comes to animations and we talk about sprite sheets, it's frame by frame, so you can take the option of like okay, attack animation is across three PNGs. So then you've got your frame that the action happened, and you can say okay, I want to hold each one of these PNGs for four frames, and the duration of the entire thing is eight frames. And so you can tell DragonRuby eight frames, and so you can tell DragonRuby do the rendering across this collection of sprites on the screen. So when you do an attack, it cycles through those, do those specific animations? And it's a matter of providing objects that respond to that specific contract, which is the beauty of Ruby, right? It doesn't have to be a sprite class or whatever. It's just hey, if it responds to these functions, these properties, we're good.

Speaker 1:

That's so interesting, the thought of just like, yeah, I've got a bunch of static pictures and then I load them into this program and then you press a button on your keyboard or controller and then it moves and it's so cool. Yeah, it's such a cool concept.

Speaker 2:

What's really interesting is that and a difference that I saw with AppDev and GameDev is, with GameDev, a lot of it is kind of data-oriented. Like this it's like your game state is a function, what's rendered to the screen is a pure function that's derived based off of your game state, and so it feels data oriented and functional. It's an interesting paradigm shift that also existed when going from like app dev to game dev. So, yeah, a lot of the DragonRuby APIs are around this data oriented approach where you have referential transparency on what is actually going to be sent to the renderer and whatnot, and it's cool. It's really cool to kind of see all that in action. And then the simplicity of it of saying I can just have a value type that represents what's rendered to the screen and not have to think about immutability and a lot of the other complexities that exist out there.

Speaker 1:

So Ruby, if you ask a non-Rubyist, is notorious for being slow, so how is it that we can run a game at 60 frames per second in a slow language? Air quotes slow language.

Speaker 2:

Yeah, I've given up. So I was to a point where I was going to do like a white paper and we'll talk to that first and then I'll give you what I show them now. So the idea is that the initial response I run as fast as the NET Core CLR runtime that does a bitcode compilation in JIT. It's just not going to run that fast and so this idea of a language can't be fast or slow. It's a runtime implementation that makes it fast or slow With Ruby and this whole oh Ruby is slow. We're talking about MRI Ruby from.

Speaker 2:

Like the 1.8, 1.9 days 1.8, 1.9 days, which is like ancient Ruby at this point. And so the runtime implementation with like Ruby 3.3 is a different runtime. It's got a different execution profile. For DragonRuby we use mruby as our primary dependency. So we took mruby and then gutted the core lib and polyfilled it with a lot of the libSDL stuff so that it could do cross-platform stuff. So you've got your file class and you do filereadfile.

Speaker 2:

The mRuby, cruby, all those assume that you're working with an operating system that's PC, mac, linux that has a regular file system that isn't locked down the way that consoles or isolated storage or those other environments are. So we had to gut a lot of those things. And then those core libs are replaced with these across platform dependencies yeah, language can't be slow. And then with this, I guess, extraction and replacement process that's another facet of what makes the language fast is what is the implementation of your core lib? What is the speed of the C function that is being invoked through that foreign function interface? I went through all these details and it showed the employees like yeah, but Ruby's slow, and I'm like okay.

Speaker 1:

Okay, yeah.

Speaker 2:

So what I ended up doing was I was like, okay, I'm going to create a YouTube video and I'm going to have a scene where it renders as many sprites on the screen as I possibly can. And so the YouTube video yeah, if you do DragonRuby performance, it'll come up and what I show is rendering, I think, like 10 to 20,000. I give a profile, I say, okay, what's the speed of rendering? 5,000 sprites on the screen that are moving across and have some concept of collision, and they'll wrap around. And so I do 5,000 sprites. And then, okay, I'm going to bump it to 10,000 sprites, 20, 80, 40, like 80,000 sprites.

Speaker 2:

Dragon Ruby got around 20 to 30 frames per second, and I did the exact same thing with Unity and it got four frames per second. And so the conversation ended, All the white people, all the explanations, the details. I'm like watch this YouTube video. And they're like okay, there's still people like I don't believe that. So I did another one for many to many collisions. So it's like you don't believe that. So I did another one for many to many collisions. So it's like you've got collisions on your page and how do you construct something that visually shows that this object collided with these other objects and 1500 sprites with many, many collisions at 60 FPS. You need to get one frame a second. It's completely broken from that perspective.

Speaker 2:

It just goes back to that idea of like runtime implementation and your core lib implementation and the runtimes I'm picking on Unity because that's usually what people think of, yeah, sure, what people think of and the runtime implementation is, at this point, a 15-year-old fork of mono, of C-sharp mono, the C-sharp mono runtime.

Speaker 2:

And then the way they dealt with cross-platform compatibility was through a transpiler that takes the intermediate representation of C-sharp and emits C code. So you're taking C-sharp code which gets converted into this intermediate representation. It's kind of like your virtual machine, and that virtual machine those specific opcodes are then code-gen as C code and then that C code then gets compiled. So you've got the C sharp to IL transition, the IL to C transition, the C to intermediate representation transition, and then that gets translated into the compiler. And once you've done all those transpilations, you've lost any semblance of optimization at that point. And so their runtime implementation. It's a good and bad thing, right, you have BitRot and it's a longer running project, but they can't take advantage of all the advancements and compilers that we have today, and so that's why it's faster. It's just, our runtime is just that way.

Speaker 1:

Speaking of taking advantage of newer things, are you able to take advantage of the new stuff in Ruby 3.3 and what's coming out in 3.4, like the new parser, the new YJIT and things like that? Or is that not quite in your purview, because you're using mRuby and then sort of gutting it?

Speaker 2:

We're able to take advantage of those things as those changes make it over to the mRuby. Now, the biggest benefit of mRuby is that it's embedded. It's fairly trivial to put that into a C program and have it run everywhere. So there's no OS level dependencies from that perspective or assumptions that are made that you're running on like a server class machine. And so when you think about like YJIT and the native or the assembly code that it emits, yes, that will work on Windows and they've got it working on Emscripten, but the backend compilers that are used for consoles, it's not going to work there.

Speaker 1:

Or at least not yet.

Speaker 2:

Not yet.

Speaker 1:

And now we're getting into NDAs and all that crazy stuff.

Speaker 2:

So there's a facet of that. So those changes, if they make it into MRuby, then we can look at co-opting them. And for us we're kind of like in this parallel stream where there are some things that we can send back to upstream saying that, hey, this change makes XYZ better or faster. But it's difficult to say, oh yeah, your file IOs is actually not cross-platform. Take this dependency on 250,000 lines of C code which is libSDL. So that maintenance burden is why the product exists. Right, it's what makes this process sustainable on our end. That's why you pay for the engine. We can take advantage of some things.

Speaker 2:

I love Prism. I love the traversal of the specific recursive descent parser that's used in Prism. It's good. But mRuby was built later, which means that it has a nicer parser than what Ruby originally had, so it doesn't have as much as the other cruft that was there. So there's benefits that exist and it's just that balancing act of okay, how much are we going to invest in that parser facet? Can we collaborate with upstream to help that process? And someone's got to take the lead. If they're going to start with the prison port, I'm there, right, I want to make sure that that happens. But doing that work and then pushing it upstream. It's that question of whether MRuby is positioned to accept those kinds of changes. But it's really cool and our parity is with MRuby. So once the feature, that syntax, comes into MRuby, then we can leverage it.

Speaker 2:

One interesting thing and I'd love to hear your thoughts on this is that with DragonRuby and the ideas that I have around it, we can break Ruby from that perspective. Dragonruby is a Ruby, but it doesn't have the same onus of backwards compatibility or mission critical applications. So what are some experimental things that could be added to like DragonRuby? Maybe we do create a pipe forward operator or maybe we actually do introduce some experimental syntax that doesn't have the onus and the air quotes red tape that exists with CRuby or MRuby. So it's an environment for experimentation and it's a safe environment because you're not building medical software with it, right?

Speaker 1:

That's interesting. I didn't think about the fact that you're sort of isolated from what goes on in Ruby because you have your own. Would that be considered like having your own dialect in a way of like you know, sort of in the way that Americans speak English and the English speak. English and they are not the same language. There are similarities, but they're not the same. That's interesting.

Speaker 2:

It's a world for experimentation and potential innovation, and I think that's a big challenge for Ruby today is that we have the maturity and the ideas that have been set in place, but there's a trade-off, right. That maturity I won't say stifles, but it stifles innovation. Right, you're slower to innovate, no-transcript. You're slower to innovate because you don't want to break things. But DragonRuby has this unique environment where it's like okay, it's games, we don't have 25 years of code to think about.

Speaker 2:

We're building a new experience and the opportunities to innovate on what exists out there are, there, they're closer.

Speaker 1:

Have you done any experimenting yet, or is there a bit of it where you're like we actually added this syntax that if you're writing Dragon Ruby code, you can do this, but you can't do that in regular Ruby.

Speaker 2:

We've done an experimentation and it's actually went really well around the core lib.

Speaker 2:

So in Dragon Ruby, hash is quack-like attribute accessors.

Speaker 2:

So you can use the bracket symbol, whatever to access a key in a dictionary, or you can just do x and what it will do is it does the method missing the pre-cache and all those facets to where you'll actually get the x key value from, and it forwards to get key. Basically. And the interesting thing there is that with this approach you don't have to air quotes, pay the tax of creating a class to represent one of your game entities. You can say I'm just going to create a hash with XY armor that has this name and stuff and just create that dictionary structure, invoke it as if there were attributes and then later evolve to using a class. And the nice thing there is that because we've done those polyfills, you're not changing the call sites. You can continue to keep those specific properties that you decided these objects would have and just transition to a class. So those kind of things, same thing right. Like if I sent the pr that said hey, hashes, quack like classes with respect to attribute accessors, decline, right, they'll immediately.

Speaker 1:

Nope nope, you've got data classes. You've got structs, like there are ways to do it, but not hashes. Sorry, no dice, but dice.

Speaker 2:

But from our perspective we're like, yeah, we can do this, we can try this approach and see how it feels. And it's fun because we'll have Ruby devs that come in there and say, man, this is really nice, though I can just treat a hash like a full-blown class and you end up missing it. And I was like, yeah, I probably feel I opened up the hash and did the same thing and like more crime. Yeah, those are primarily the experimentations that we've taken is expanding the core lib from that perspective.

Speaker 1:

It's sort of like when someone goes from doing primarily Rails dev work to just raw Ruby and they're like I can't do any. It's like, yep, that's active support. Sorry, that's exactly Yep. I don't want to not do my favorite question, so we're going to do it now. Let's do it Before any more rabbit holes. What is something cool, new or interesting that you've recently learned or discovered or built Doesn't have to be coding related. What do you got?

Speaker 2:

It's really the shader tech, so how the GPUs work and everything. So there's shader language for OpenGL is different than the shader language for Direct3D, which is different than Metal. And then you're like okay, well, if I want to do this cool ripple effect or visual effect, I have to write five different versions of this program. That's not fun. But there's something called the Spear V toolchain, which is a cross compiler where you write I think it's Vulkan, you write your shader in Vulkankan and it will create the OpenGL, Metal, Direct3D variants of that specific shader language. So we're getting into a world where we've got fragmentation at the language to hardware level and each one of these companies is saying, no, our language is the best and we're not going to consolidate onto one. So of course someone said, no, we're going to do that and then provide that transpilation. But that's been some of the really interesting stuff that I've been exploring. We think about CPU and just languages that target CPU, but now we're getting into GPU languages and then their idioms and their highly parallel approach and paradigms are just, they're fascinating and they're different.

Speaker 2:

There's a website like, if you want some idea of like what that looks like. There's a website called Shader Toy and there's a scene of a tree with like leaves waving in the wind and like a grassy landscape and there's like a day-night cycle and clouds and everything Like how the hell did they do this? And you look at the program and you're like what is this? It's just all math. But all the way down, all the way down. But the fact that someone can take this highly parallel concept of every pixel is run in parallel with every other pixel, and how you form a program that can make a tree, it's just mind-blowing. But yeah, shader toy, you can lose hours just looking at all the cool little tech demos that exist out there. It changes your brain right. It exposes you to a domain that you haven't been exposed to and it'll make you a better developer across the board.

Speaker 1:

Yeah, I will include that in the show notes and then I will go waste hours staring at it here in a little bit. So if someone wanted to get started doing game dev, they have a little idea or they just want to tinker and they want to use everyone's favorite language, Ruby and Dragon Ruby. Like, how do you recommend getting started aside from? Like go buy Dragon Ruby so you have the Dragon Ruby engine and get started. But like how do you recommend going from I have nothing on the screen to hello world with Dragon Ruby?

Speaker 2:

So, just an aside, anyone that listens to the podcast, you send me an email saying that you heard about it. I'll hook you up with a free license, no big deal there. We also have income assistance if you're unemployed or in school under 18 or a parent that wants to teach a kid Any one of those like heartwarming, good feeling stuff. Just send me an email and I'll get you set up. So I'm not trying to put anyone out financially. But yeah, you download it, you double click to unzip and that's it. There's no dependency installation, it's all self-contained. And there's a book that one of our community members wrote that I recommend and it's in our docs. But you end up building like a side-scrolling shooter and like a Flappy Bird clone is also a facet of it and kind of work through that book. And if you're familiar with coding I think you'll get up to speed pretty quickly by working through that.

Speaker 2:

Aside from that, we've got I think like 150 plus sample applications that go in increasing difficulty. So it kind of teaches the basic. Then we dig into some of the advanced rendering concepts and then we have genre-specific reference implementations. If you want to do a platformer, here are some reference implementations of how to do a platformer, like a Mario Star or platformer, or if you're doing like a tactical RPG, we actually have a sample app where it's like a green sprite walking around the screen and it's the first area of Legend of Zelda from the NES. And then you enter a cave and it's like here, take the sword, take this. So we actually have that as like as a sample app and that's kind of like your springboard with respect to starting on a game.

Speaker 2:

I think that's like a big observation that I found is that with Rails applications, the scaffolding is extremely productive. I mean, we're building CRUD apps, we're taking data, sticking it into a database. It's formulaic, at least at that level. But when it comes to games, it's difficult to create that kind of scaffolding. So how we compensate for that is saying, okay, here's springboards to creating a top-down game or a platformer or a turn-based or ascii-based roguelike or a bullet hell shooter or twin stick shooter and all those variations and that ends up working pretty well. And our discord community is absolutely phenomenal. The idea of Minus is there and it's so great because there's so many people that it's Ruby is their first language, right? They're like I've never used Ruby before. That clicking happens. You see that magic that we felt and they're like this is so awesome. And so if you're ever stuck, you come to the Discord community. You're going to find a lot of help there, and I think a combination of those three things is the best way to get going Super cool.

Speaker 1:

This has been great. Thank you so much for coming on and reaching out and asking to come on, because this was so much fun getting to pick your brain on it and learn more about it and it's such a cool project and I love that. We can do literally anything with Ruby. It's not just web stuff, it's full blown applications and games. Just web stuff, it's full blown applications and games.

Speaker 2:

And commercial games. This is putting food on my table, right, right, right, yeah. So it's wonderful and the innovations I think that the language will bring to game dev is sorely needed and it's good and it's an investment in that future. I think the future like kids and students and things like that, and education, and I think that's where I feel the renaissance and that resurgence and what we discovered again.

Speaker 1:

Bringing developer happiness to game devs sounds pretty important. Cool, is there anything else you wanted to talk about before we do the wrap up? Take?

Speaker 2:

the time, feed your soul. I know people say like, oh, I got to learn the next new hot tech. And just step back and just remember that, why you decided to become a developer. Right, the love of the craft and the encoding, and I think game dev is a wonderful way to do that well.

Speaker 1:

Thank you so much for coming on. Where can people find you and dragon ruby on the internet?

Speaker 2:

yeah, we have our discord server, so dragonrubyorg has a link to that. I'm on the artist formerly known as twitter at amirazan. I on Mastodon, on rubysocial, on Mastodon. Shoot me an email, also DMs welcome. All those great things Excellent.

Speaker 1:

Yeah, I'll put all that stuff in the show notes so that people have access to it. And again, thanks for coming on. It was a blast having you on and hopefully I'll get an opportunity to do some tinkering of my own and then maybe even have you on again to pick apart how bad my game code is. Oh, my game code is terrible, don't worry. Great Well, audience members, don't forget to text in if you liked the show, if you have comments, questions, concerns, or if you'd like to be on the show, shoot me a text. I'd love to talk more to you. Otherwise, see you in the next episode. Bye, everyone.

People on this episode

Podcasts we love

Check out these other fine podcasts recommended by us, not an algorithm.

Remote Ruby Artwork

Remote Ruby

Jason Charnes, Chris Oliver, Andrew Mason
The Ruby on Rails Podcast Artwork

The Ruby on Rails Podcast

Elise Shaffer and Brian Mariani
Ruby for All Artwork

Ruby for All

Andrew Mason & Julie J
IndieRails Artwork

IndieRails

Jess Brown & Jeremy Smith
The Bike Shed Artwork

The Bike Shed

thoughtbot
Code with Jason Artwork

Code with Jason

Jason Swett