What I Learned While Making a Game With React Native

I used React Native to build a cross-platform game for iOS, Android, Windows, and the web. SudoBlock is a cross between Sudoku, jigsaw puzzles, and Tetris.

You can find SudoBlock on the web, App Store, Google Play, and the Microsoft Store.

React Native only supports iOS and Android, but I used react-native-web for the browser, and react-native-windows for Windows desktop and phone. The UWP app can also run on Xbox One and HoloLens. I also experimented with react-native-macos and react-native-appletv, but they’re not being maintained.

Here’s some of the things I learned while building SudoBlock:

You should probably use a game engine

I’ve heard good things about Godot and Unity. These game engines support iOS, Android, Windows, and Linux. Unity supports many other platforms.

Making a simple game was a great way to learn React Native, but it’s not the best tool for the job. However, people have started working on some game libraries for React Native, such as react-game-kit and react-native-game-engine.

It’s not the easiest way to make a game, but it’s also not impossible. The built-in Animated library is great, and I also used react-native-animatable. I used a library to play sounds. I wrote native code to integrate with iOS Game Center and Google Play Game Services. I used libraries to integrate with InApp Billing on Android, and in-app purchases on iOS. I also wrote native code for ads and in-app purchases on Windows. There’s a RN library for particle effects (although you’d have to add support for Android), and react-game-kit provides a way to manage sprites and animations.

I want to make some more simple 2D games, and I’m going to stick with React Native for now. I can fork SudoBlock and reuse a lot of the code that I’ve already written.

If your goal is to quickly build a cross-platform mobile game, then I’d recommend learning Godot or Unity.

Don’t worry about supporting Windows

This is a no-brainer. No one uses Windows Phone and Microsoft have abandoned it. I wanted to explore and learn new things, so I decided to do it anyway. I enjoyed the process of installing Windows, working with Visual Studio, and writing some C#. I also figured out how to write cross-platform npm scripts using scripty.

react-native-windows gives you a UWP app that can run on Windows Phone, tablets, desktop, Xbox One, HoloLens, and other Windows platforms. But:

  • Nobody uses Windows Phone.
  • Mobile games don’t usually make sense on an Xbox.
  • If your game runs in a browser, then you probably don’t need a desktop app.

React Native might be better than Electron for desktop applications

When I was running SudoBlock as a Windows desktop application, I realized that React Native could be a better choice than Electron. Electron apps are notorious for being huge and using a lot of memory (e.g. Slack and Spotify.) They have to package and load an entire WebKit browser. React Native apps are much smaller and use far less memory, because they only need a JavaScript engine. You can also use responsive design, so that a single codebase works on desktop, mobile, and the web. The only problem is that react-native-macos is unmaintained and out of date, so it would be great if a company sponsored development.

You’ll probably write some native code

Some people are attracted to React Native because they’ve heard that you can write a mobile app with only JavaScript. In practice, this is only true for extremely simple applications. Most of your code will be written in JavaScript, but you’ll probably have to write some native code. At the very least, you must be prepared to fix some bugs in third-party libraries.

I started contributing to react-native-admob, and sent a pull request to allow multiple test devices. That was my introduction to native code in React Native, and I had to work with JavaScript, Objective-C, and Java.

I also did a lot of work on react-native-blur. When I first tried to use it, it was completely broken on Android, and there were lots of problems on iOS. It took a lot of work to get everything running. I could have just skipped the blur and used a darkened overlay, but I enjoyed the work and learned a lot.

I also had to write native code to integrate with iOS Game Center and Google Play Game Services, and for ads and in-app purchases on Windows. I also wrote a small library to manage vibrations and haptic feedback across iOS, Android, Windows, and the web (using the Vibration API.)

There will be bugs

React Native is pretty stable, but there’s a lot of unmaintained libraries, and most libraries don’t have any tests. React Native is a bit like jQuery, in that it smooths over a lot of quirks and inconsistencies and provides a consistent API. But there’s some tricky edge cases, and I often had to read the React Native source code to figure out why something was happening.

Some examples:

Android was particularly unstable. Not just React Native, but Android itself. I didn’t have too many problems with iOS.

React Native vs. iOS / Swift

I wrote an iOS app with Swift a few years ago, and I’ve actually had a much better experience with React Native. When I was working with UIKit, I remember constantly fighting with things like layout, contraints, and font rendering. I uncovered some actual bugs, and found long threads on the Apple forums that were being ignored. It was really nice to let React Native handle all of the rendering. I had no rendering issues on iOS or Android, and just a few problems that I fixed on Windows.

Swift was also very unstable at the time, and Xcode upgrades took a lot of effort. My Obj-C code still compiles a year later on the latest version of Xcode. If I was using Swift, I think it would take at least a day to upgrade to Swift 4.1 and update all of the third-party libraries. I believe Swift is more stable now, and I love the language, so I might start using it again on future projects.

I had a lot of headaches with React Native, but it wasn’t as bad as Swift v1 and UIKit.

Marketing is really hard

  • I tested Facebook ads with $50. I reached about ~7,000 people and got ~50 clicks. One person ended up buying the game for $2.99, so I made $2. You can’t spend $50 to make $2.

  • I posted on Reddit a few times:

  • A German website published an article about SudoBlock.

  • I tried to capitalize on #covfefe, which didn’t work at all. But I repurposed that new code into an Emojidoku mode.

  • I found a game publisher who was going to handle all the marketing and split the revenue. They even promised to get the game featured on the App Store. We signed the contract and I took the apps down for a while, but the publisher fell off the radar and stopped replying to my emails.

  • I finally got around to writing this blog post.

Other Notes

  • I switched from Sublime Text to VS Code near the beginning of the project. VS Code is awesome. It’s super fast and very customizable.

  • I set up Flow and started using Immutable.js. I love having static type checking for JavaScript.

  • I used Airbnb’s eslint config, and spent about a day fixing all the issues. Every time I saw a rule that I didn’t understand, I looked it up to understand their reasoning. I read through a lot of great discussions on Github. This was a great way to learn more about JavaScript, and especially some of the new ES6 features.

  • I starting doing some functional programming with lodash/fp and ramda. I had fun refactoring some code in a more functional style.

  • I really enjoyed working with redux-saga, which helped me clean up a lot of messy code.

  • I learned a lot about Reactive programming. This post is amazing: The introduction to Reactive Programming you’ve been missing. I started playing with RxJS and redux-observable.

  • I set up CodePush, so that I could push JS changes without releasing a new version to the App Store. The setup guide is very helpful.

  • I had to debug some memory issues on Android, and this article was really helpful: React Native Android App Memory Investigation

  • I learned about the webpack DLL plugin, which made development a lot faster. You can compile everything in node_modules as a separate bundle. You only need to do that once, so it saves a lot of time.

  • I released a boilerplate project with my webpack config for react-native-web.

  • I learned about the Babel AST while working on an issue in a Babel plugin, related to react-native-web.

  • I wrote a script that stripped unused glyphs from icon fonts, to reduce the app size.

  • I tested the app while simulating a slow network connection in Chrome. This revealed a bug where the counter started ticking before everything had finished loading.

  • I discovered that it takes a huge amount of effort to actually launch a game. Once I had a playable game, it was another 2 months before everything else was finished. Things like in-app purchases, ads, analytics, high scores, achievements, tutorials, app store listings, screenshots, icons, social media accounts, etc.

This was about 3 months of work, and I was in a state of flow most of the time. I learned a lot of new things, and I really enjoyed the whole process. The game has only made about $50 so far, but I have some more ideas for grid-based games, and I can reuse a lot of the SudoBlock code. I’m also a freelancer, so this is the only way I can pick up new skills.

Thanks for reading! If you have any questions, please leave a comment on Hacker News.

  • I’m currently working on DocSpring, which is an API for filling out PDFs.
comments powered by Disqus