Ruby
Game Development + Ruby = Happiness
Summarized using AI

Game Development + Ruby = Happiness

by Amir Rajan

The video "Game Development + Ruby = Happiness" features Amir Rajan, an indie game developer renowned for his hit iOS game "A Dark Room." In this presentation at RubyKaigi 2016, Amir shares his journey into game development using Ruby and highlights the intrinsic connection between elegant code and engaging game aesthetics.

Key points discussed in the video include:

- Background and Success: Amir recounts his transition from a .NET developer to an indie game developer, detailing how his minimalist RPG "A Dark Room" achieved viral success and garnered over 2.5 million downloads.

- Game Development Process: He outlines how he follows up that success with subsequent titles, drawing on influences such as "Dark Souls" for challenge design.

- Collaboration and Art: Amir emphasizes the importance of collaboration in his projects, specifically highlighting his partnership with a composer for his rhythm-based game "Noble Circle," inspired by Edwin Abbott's "Flatland."

- Development Journey with Ruby: He describes how building automation with Rake led him to appreciate Ruby's elegance, which he finds contrasts with the rigidity of C#. He shares insights gained from transitioning his mindset from static to dynamic typing, allowing more fluid development.

- Incremental Development: Amir touches upon the benefits of incremental development in JavaScript, where he created a hackathon game called "Node Kick," thus enhancing his understanding of game lifecycles and gameplay mechanics.

- Challenges in Game Development: He elaborates on various challenges in game development, such as complex collision detection and the limitations of game engines, and shares learning experiences from creating titles like "Noble Circle," "Spirits of Akina Drift," and "Beautiful Go."

- Artistry in Game Design: Amir expresses concern that while modern games excel mechanically and graphically, they may lack artistry—a sentiment underscored by his push for balance in storytelling, production value, and engaging gameplay mechanics.
- Contribution to Ruby Motion: The presentation concludes with Amir encouraging ongoing involvement in the Ruby community and contributing to open-source projects like Ruby Motion, allowing greater accessibility for Ruby developers in mobile game development.

00:00:00.060 Can you hear me? Okay, good! Excellent. So, I'm from Dallas, Texas, which means my Japanese is pretty much non-existent. Gomen nasai, sumimasen. This talk will be in English. Thank you for having me at RubyKaigi. This is pretty much a dream come true for me. I've come alive. You're going to get a bit of my history.
00:00:21.590 My name is Amir, and that's my Twitter handle. I'm an indie game developer, and I've been doing it for about three years, on and off. I'm a storyteller who built a minimalist text-based RPG called 'A Dark Room' out of sheer luck. This game somehow went viral and reached the number one spot in the App Store. To date, it has about 2.5 million downloads, close to 25,000 five-star reviews, and it stayed at the number one spot for 18 days. Quite an accomplishment, and completely lucky from that perspective.
00:01:02.460 So, how do you follow up that kind of success? I built a prequel and a sequel, and I made it very challenging. For those of you who have played Dark Souls, you now have some idea of what I'm talking about. I imagine some smiles and perhaps even tears of joy appeared concerning the answer for Dark Souls. I created a game called 'The Ensign,' which was also well received, so I was pretty happy about that.
00:01:43.920 I took things to the next level and built a game about a bouncing circle. This rhythm-based game is inspired by Edwin Abbott's satirical novel, "Flatland." It is part of the Gutenberg Project and was written in the 1800s during the Versailles era. Edwin Abbott was a highly learned mathematician. The book describes a two-dimensional world and the various shapes that exist within it, along with the society they have built.
00:02:09.750 I'd like to play a trailer for the game. I actually partnered with a composer who created the music because I can't do music. He handled all the composition for the game while I managed the gameplay and artwork. Here is the trailer.
00:03:06.930 Man, I love this stuff! These games are my heart and soul, painted on a digital canvas of ones and zeros. I truly can't imagine doing anything else right now, or at least for the foreseeable future. I feel very fortunate that Ruby has put me in a position to build games for mobile environments.
00:03:31.290 To give you a little background on how I got here, I was actually a .NET developer—don't kill me! I did C# development for seven years before 2010. When 2010 came around, I was tasked with building automation using Rake. This is a simple build test that employs a gem called Albacore.
00:03:56.640 It turns out that batch files are terrible for build automation. The same goes for XML; you never want to do any kind of build automation in XML. So we used Albacore and Rake for our build automation. An unfortunate aspect of working on Windows was that you had to deploy your website to the default directory, which is the "www" root, effectively overwriting it.
00:04:08.640 I started with Ruby, and it was through build automation that I transitioned to being a Ruby developer. It took me a while to see the beauty that Ruby brought to the table, and it all began with one single variable: the output path, which was the process working directory. The most elegant thing I noticed was that I could create a function for the output path and then delete the variable reference, while the call site didn’t change, as I didn’t use any parentheses in my method calls.
00:04:46.200 This subtlety was not something I experienced in C#. Eventually, I took this function and transformed it into a module—a next evolutionary step: from local variable to function, and then function to module. When I included my module, the call path didn’t need to change. This was when I really started to see the power of the ability to evolve your code slowly and defer the need to create something you may not need at the moment.
00:05:38.760 In C#, it would have started off as a class—there was no way I could just create a bare function or a simple variable. The ability to do this in Ruby was very enlightening to me. Eventually, I took the approach of making it into a class, as you can see from the differences that arose from there.
00:06:20.190 Instead of 'include build deploy,' I had our instance of the build and deploy class managing my state. This was a turning point in how I thought as a developer. I spent a lot of time in the .NET community trying to influence this kind of change, encouraging my fellow developers to appreciate the aspects of dynamic typing and this evolutionary aspect of building software.
00:06:41.800 I even created a dynamic library in C#. C# has something called a Dynamic Language Runtime, and here I created a dynamic class called Gemini. If your function definition uses dynamic return types and accepts dynamic parameters, I could treat this as a public function that can be redefined.
00:07:07.430 You could initialize an instance of the class by creating a person type or by passing an arbitrary named parameter, like a hash. Although it was a bit ugly, it worked. I took it a step further and got modules and method missing functioning in C#, which is a statically typed language. I know I’m crazy, but I got it to work!
00:07:40.710 This should have probably been called 'include' instead of 'extend'—but basically, I could take any instance of person and redefine all instances of person to return something casually, as opposed to the original definition, based on this idea of the dynamic language runtime.
00:08:04.680 By defining a method called method missing, I could create a method that allows me to define the attributes dynamically. This led to the ability to create instances of all attributes at the end, throw in HTML to URL encode that property, and then simply throw a ‘member doesn’t exist’ exception if the method was called improperly.
00:08:57.400 In 2010, I decided to dive into Ruby and started learning Rake. I spent three years trying to influence this philosophy of incremental design and evolution in a community that generally wasn’t receptive to it. I learned a lot during this process, particularly around how to create dynamic runtimes and how to bend a language to your will.
00:09:43.640 Specifically with C#, one interesting element you have is progressive typing. You can start with a dynamic type and then use an explicit cast operator to generate a static type from that dynamic type, giving you a full spectrum to work with.
00:10:16.480 Unfortunately, this wasn’t something the community as a whole loved, so I eventually gave up. It got so bad that I quit my job and sold everything I pretty much owned. I discussed with my wife that I needed to take some time off and do my own thing.
00:10:50.130 We moved from a two-bedroom apartment to a one-bedroom apartment, and the picture you see is everything I owned. I got rid of my PS2, PS3, GameCube, my PC with its beautiful 30-inch monitor and 27-inch vertical one. It was very difficult. My wife kept all her stuff while I kept a car, clothes, and generic furniture. My worldly possessions fit into the same backpack I have now.
00:11:36.370 During this time, I focused on doing what I wanted to do, which was build games. And that is exactly what I did! Before diving into the actual games I built and the lessons I learned, I’d like to show you how I perceive development.
00:12:05.470 I see it as drawing. This is a drawing that I created. I'm not the best artist, but after you watch part one and if I haven’t been booed off the stage yet, I’ll play part two, and then we can continue the talk. This is an analogy I feel aligns with development, showing that you don’t start with dark lines and fixed structures. Instead, they evolve over time as you learn and refine what you're building.
00:12:59.470 You can see errors I made and how I erase them before solidifying the structure of what I’m trying to create. You need that initial structure to fade away as you work into the finer details of what you're looking to develop, similar to how I create variables, modules, and classes to encapsulate my ideas.
00:14:02.580 So, you want to see part two? Yeah, there we go! In part two, you’ll see more details. Shading is akin to the initial sketching phase where you gain the overall shape before refining the elements. I enjoy using the iPad Pro with a pencil, especially for doing sprites and similar creations.
00:14:47.300 Going back to my game development journey, the first thing I did was build a game in JavaScript, despite talking about Ruby. The game is called 'Node Kick.' I developed this as part of a hackathon with some friends. Has anyone played 'Divekick'? If so, you'll enjoy 'Node Kick.' I press up to spawn a player and use the jump key to jump, while left and right will attack.
00:15:23.490 [Game sounds] I also did the voice acting for various sound effects in the game; I recorded my voice using Audacity, adding reverb and echo to create that classic video game feel. It was a joyful experience developing a game like this and you can actually play it here; I’ve deployed it to a Heroku instance, and the source code is available for you to run and explore.
00:16:09.000 One beautiful aspect of JavaScript I appreciated was the idea of incremental development, starting with one function and evolving from there. I gained a clear understanding of first-class functions. In game development, a lifecycle is generally built around a tick—executing every certain frame rate.
00:17:08.180 In this case, we executed the tick roughly 60 times a second. During each tick, you handle control input, perform computations, and render the screen. In handling control input, I iterate through live players, apply gravity, and manage kicking in the game.
00:17:47.720 Unfortunately, when you attempt to force complex functions into classes, it can become cumbersome and frustrating. This is why many times during the conference people have asked what I've been working on, and I've been explaining my frustrations with front-end JavaScript, especially through React.
00:18:48.870 Afterward, I found a game called 'A Dark Room,' which is a web-based game by Michael Townsend that I ported to iOS. This game effectively changed my life—it was built with Ruby Motion, and thanks to the guidance of Lawrence and Zanetti. Without Ruby, I wouldn't be standing here today talking about how I created a game using Ruby Motion.
00:19:29.410 Here's a battle sequence you'll find within the game. You can see the old-school attack mechanism. It’s thrilling and engaging, capturing that traditional JRPG feel. And you've got loot at the end—so cool! This represents a culmination of my work utilizing Ruby Motion. Many of the elements, like defining battle sequences or loot drops, are quite elegant in Ruby.
00:20:53.050 For instance, the structure allows elegant class methods, where you define the title and text elements leading to sophisticated battle mechanics. The class itself is simple yet elegant—nothing less than what I expect from Ruby.
00:21:38.720 It stands in stark contrast to Objective-C, which can be difficult and cumbersome. Objective-C requires such extensive typing for what should be straightforward processes. This expressiveness of Ruby has enabled me to finish the game and launch it in the App Store.
00:22:23.680 That comes back to the beauty of Ruby versus Objective-C. The message-passing concept present in Objective-C is useful and is compatible across various programming languages. However, my experience in game development has taught me that there are distinct challenges.
00:23:39.490 Building games introduces complexities like non-terminal polynomial time and random number generators. I noticed that many strategies for traversing random maps end up becoming NP-complete problems. It’s surprising how many game challenges stem from such intricate computational issues.
00:24:50.100 When it came to the testing practices I built while working on CRUD applications, they did not apply seamlessly to gaming. So, my testing methods ended up being vastly different, often leading to difficulties that were impossible to navigate outside of manual playtesting.
00:26:05.910 With 'Noble Circle,' I had to hone my mathematical skills in trigonometry and geometry. As a developer, I found good collision detection can be tricky, especially when dealing with complex shapes. Initially, I explored simple closed intersection methods, beyond just basic shapes.
00:27:07.740 With this in mind, I had to devise ways to handle complex collision detection—often modeling the game’s physics to ensure smooth gameplay. This involved substantial calculations for detecting intersections within various shapes.
00:28:29.240 I came across methods, like Heron’s formula, which allowed for easy area calculations without needing arbitrary bases or vertex designs. However, it was frustrating to realize that the game engines didn't allow for a fluid evolutionary approach.
00:29:09.780 The engines embedded logic directly into nodes and physics bodies rather than presenting functions that could be called independently. This introduced an inconsistency in gameplay mechanics that was hard to navigate, but I had to concede and adapt.
00:30:16.690 One of my next projects was 'Spirits of Akina Drift.' Building this project was a massive learning experience, especially when it came to implementing physics and how to convey realistic car mechanics. It allowed me to extend my knowledge further into the functionalities of gaming physics.
00:31:07.480 These concepts helped me develop an appreciation for how different factors, such as drag coefficients, influence cars in games. It involved an understanding beyond surface-level gaming design into deeper physics principles.
00:31:57.640 Even though I explored intricate realism through physics, I learned that breaking reality could enhance fun gameplay experiences. Simplification is critical during game design.
00:32:38.230 My final game, 'Beautiful Go,' was inspired by the anime 'Hikaru no Go.' My aim was to learn the game of Go through app development. The initial build aimed to capture the digital essence of Go without the traditional crosshairs that players use to count liberties.
00:33:58.730 However, I found that it wasn't appreciated as an actual Go game by customers. The feedback I received pushed me to incorporate elements that would make it easier to count—and the finalized version of the game was reasonably well-received.
00:35:12.390 I challenged myself with understanding my user base and designed based on their feedback. It was a fascinating process that helped me think about how to adapt my designs while remaining true to my artistic vision.
00:36:25.530 As I wrapped up, I wanted to highlight that there’s a balance in game development between production value, game mechanics, and narrative. While we’ve genuinely achieved remarkable graphics and mechanics in modern games, I worry we've lost some artistry in the craft.
00:38:02.160 It feels as though we’re hitting a local maximum in these areas. The evolutionary approach I’ve explored in Ruby and JavaScript doesn’t seamlessly translate into C#, Unity, or C++ frameworks.
00:39:17.530 There is hope, however! Ruby Motion is an open-source project I contribute to that allows Ruby developers to utilize its capabilities for mobile games more easily. I believe in continuously influencing my community through the lessons I've learned but also in remaining engaged with the narrative aspects that matter in the realm of gaming. Thank you for your time and for listening.
Explore all talks recorded at RubyKaigi 2016
+26