Friday, September 6, 2019

Snake Games: Visual- vs. Text-Based Programming

Whenever I begin diving into a new programming language, API, or game engine, one of the first mini-projects I undertake to familiarize myself with the system is creating a snake game. It's simple-enough to implement quite quickly without much hassle while also providing adequate opportunity to explore some basic architecture properties I'm bound to encounter later on in the future. In particular, I've made three such games over the last few months - two using C++ (one rendered using ASCIIs on the console, and another via OpenGL), and one with Unreal Game Engine's Blueprints - and have made (somewhat) clear to me the differences between visual- and text-based programming, the details of which I will elucidate later on. Before jumping into that, however, I would like to briefly showcase the games themselves.

The Snake Games


The screenshots, from left to right, are the ASCII version, OpenGL game, and Unreal game. While there are some differences, mostly aesthetic, between each game, they all share the same base features, which include:

  • Randomly-spawning food.
  • Snake length increasing every time a piece of food is consumed.
  • Boundary and self-overlap conditions that end the game if true.
  • Score count based on how much food is eaten.
  • Increasing snake speed as more food is ingested.
While I won't explain the code behind each one in detail (it's pretty simple and stays relatively consistent between each version), I will include the source code for each for those that are curious. I would instead like to talk a bit about some of the realizations I had while making these games regarding the differences between conventional and visual programming.

Visual- vs. Text-Based Programming

The Unreal Engine snake game presented here is my first real exposure to the game engine and its native Blueprints schematics, and the differences between it and the conventional coding I've been doing thus far were, in my humble opinion, quite stark, and the bottom line is this: while visual programming makes coding much more accessible to a general developer audience and allows one to rapidly append new (albeit usually simpler) functionality to existing logic, scalability and organization can quickly become crippling issues, thus requiring more micromanagement than text-based programming to keep everything intact.

When I first began using Blueprints to work on the snake game, I was pleasantly surprised by how the system helped lower the entry bar a bit for people, including me, eager to learn how to use Unreal (and code in general). The procedural, step-by-step code-block outline (and connected via nodes) gave the program a simple structure for users to follow, ensuring that they wouldn't get lost from the get-go. 

The explicitness of Unreal's Blueprints later grew to become a bit of a curse, however, since it both quickly became very messy and forced me to complicate many game features in an effort to get them to work. For example, both C++ versions of the snake games each have 200 or less lines of code, and the code itself is quite simple and easy to read (even without comments). Just compare that, visually, to this monstrosity of a blueprint:
And that's not including the other blueprints which are responsible for drawing the score/speed on-screen, managing the HUD, end-game screen, etc. Here, unlike the previous versions, I needed to be much more careful with how the code was arranged, adding relevant annotations for different sections of the program, etc. In short, simply keeping everything neat was a much more time-consuming process than I originally thought. In addition to this, certain game functionalities became more complicated in Blueprints than the mirror coded versions, another aspect of visual programming I did not expect. 

For example, every snake component needs to trail the one in front of it so that its current position is the previous position of the snake body piece it's currently following. This can be achieved via text-code like so:

for (int i = snakeLength - 1; i > 0; --i)
 {
  posX[i] = posX[i - 1];
  posY[i] = posY[i - 1];
 }
A simple for-loop does the trick. In Unreal, however, things get a little more involved:
Basically, we first have to create the snake body by instancing a number of mesh objects equal to however many pieces of fruit we've eaten (plus the snake's initial size). These newly-instanced objects will then be assigned a position equal to the previous object's location, which in turn is determined by running through a for loop similar to the one shown above (which in itself wasn't entirely trivial to create since Unreal's native for loop code block only runs from smallest to largest index) that finds the previous object's ID. While the actual steps are quite simple, and basically the same as for the text-based snake games, the actual implementation can become much messier as one has to keep track of a web of nodes, interconnections, etc., and as soon as a project takes on a scale much larger than an elementary snake game, it seems to me that Blueprints will not provide the functionality and organization necessary to successfully develop such a product without wrangling extensively with the visual programming system.

Conclusion and Games

Both types of programming have their uses and merits when it comes to development: Blueprints makes coding much more accessible to the general public and allows for rapid prototyping/simple functionality handling, while text-based programming offers larger flexibility in structuring one's code, manipulating data, etc.

Finally, here are the files to the actual games, in case anyone is interested in checking them out. Note that the OpenGL version does use deprecated functionality (i.e. not using vertex buffer objects, shaders, etc.) which, while not great, does keep the code shorter. No need to over-complicate a snake game, right?

Version 1 - C++/ASCII
Version 2 - C++/OpenGL
Version 3 - Unreal Engine 4.x

No comments:

Post a Comment