Picking a Programming Language - Part 3: Common Languages

Now that we’ve talked about the big features of languages that can impact your game, we can look at specific languages and what they have to offer a game engine. This is not a complete list of the only languages you can write games in, just some of the more common ones (and the ones I know well enough to speak to). Chances are, you can find game development tools and libraries for pretty much any programming language.

C

Type: Compiled
Memory: Manual

C is a (relatively) low-level programming language and the language of choice for the Linux kernel. C’s low-level status and manual memory management means it runs very lean, using a minimum of system resources for non-program related activities. For games, this means being able to make better use of system resources for a game that runs better or offers more features on a lower-end system. However, C also has a steep learning curve. You’ll need to learn about how C’s manual memory management works, as well as pointers, and ensure both are properly managed to avoid memory leaks. C isn’t object-oriented so if you’re coming from an object-oriented background, the change can be a bit of an adjustment. The lack of object-oriented-ness is likely the biggest reason C isn’t one of the bigger languages used in game development, but it’s still perfectly possible to make games in C.

There are plenty of great libraries available for game development in C, with two of the biggest being SFML and SDL2.

C++

Type: Compiled
Memory: Manual

C++ is an extended version of C, adding some big features such as support for object-oriented programming and a huge host of commonly-used data types, containers, and algorithms through the Standard Template Library (STL). The object-oriented design does add some overhead compared to C, but it’s still a very lean language that makes good used of its resources. These features make C++ extremely common for console game development because it allows developers to squeeze as much performance out a console’s fixed hardware as possible. That means bigger, better-looking, more complex games on more limited hardware. C++ does have a steep learning curve as well for most of the same reasons as C.

Because C++ is an extended version of C, everything in C is available in C++ (the reverse isn’t true though) including libraries. It’s very common to use libraries designed for C in C++, so SFML and SDL2 both work in C++ as well. C++ is also the language of choice for the Unreal game engine so if you plan to use it, it’s worth learning C++.

Java

Type: Compiled/Interpreted
Memory: Automatic

Java’s biggest selling point is portability. It sits between a compiled and interpreted language. Java code is compiled to a file that can be executed by a Java Virtual Machine (JVM). The nice thing is that unlike C or C++, this compiled file is completely portable because any system that has a JVM can run it. This feature makes Java a little quicker than purely interpreted languages, but still slower than purely compiled languages. Another issue with Java is it’s memory management.

More knowledgeable people have written entire articles on just the subject of how Java manages memory, so I won’t go into extreme detail here. The important thing to know about Java’s memory management for game development is that it’s automatic and that the minimum and maximum heap size is set for Java programs. They can either be specified when running a java program using the -Xms and -Xmx flags, or if they are omitted then some default values will be used based on your system configuration. If your game needs more memory than the minimum, but less than the maximum, your game may stall as the JVM allocates more memory. If your game asks for more memory than the maximum, there’s a good chance it will simply crash when it runs out of memory.

Despite this, Java is a perfectly respectable language for game development (just look at Minecraft). Java is also the language of Android, so if you plan to develop mobile games, Java is a good language to know. The Lightweight Java Game Library (LWJGL) is a popular choice for game development in Java and as long as you aren’t trying to manage tons of data or do a lot of heavy processing, then Java will meet your needs.

C#

Type: Compiled/Interpreted
Memory: Automatic

C# actually shares a lot in common with Java, but was developed by Microsoft for its .NET platform. Like Java, it compiles to a executable that can be executed by the .NET framework. This executable is fully portable between any system that has the correct version of the .NET framework. However, the .NET framework handles this executable very differently than the JVM in Java. Instead of the virtual machine processing these instructions, the .NET framework compiles them into machine code and loads them into memory. This means we actually get the benefits of fully compiled code in terms of performance. C# also uses a slightly different version of memory management that avoids the memory limits present in Java, so the memory limits will only be those that exist for the system in general. Automatic memory management does still add some overhead to your game, but games written in C# will generally run quicker than in Java.

Although C++ dominated the console market for a long time, cheaper hardware has allowed for consoles with better specs. This gives developers more room to develop their games without worrying quite so much about optimization and helped make C# a more viable language despite its automatic memory management. C# has become a major player in the world of game development for both consoles and PC, and popular engines such as Monogame and Unity use C# for their scripting.

Python

Type: Interpreted
Memory: Automatic

Python was developed as a language to be easy to learn, but being an interpreted language with automatic memory management means it won’t handle complex games with a lot of heavy processing very well. You won’t be writing the next Borderlands in it, but it’ll handle simpler games like platformers or graphic novels perfectly fine. It makes for a great way to get into game development and learn programming at the same time. For people who want to start making games with “real code” instead of an engine, Python can be a good first step before moving on to other languages.

The Pygame library is a pretty popular choice for game development in Python.

JavaScript

Type: Interpreted
Memory: Automatic

JavaScript is the language of game development on the web. Thanks to enhancements to the language over the years, and the addition of the canvas element in the HTML5 spec, JavaScript has dethroned Adobe Flash for browser games. If you’re new to the world of programming languages, I should point out the Java and JavaScript are two completely different languages. JavaScript is an interesting one because the virtual machine that runs it is a web browser instead of your typical virtual machine that’s hidden away as a process. It suffers from many of the same problems as Python, but its availability online makes it a very popular choice overall. It can even do 3D thanks to WebGL.

One consideration worth mentioning for JavaScript is the fact that it runs through a browser, which means its code must be downloaded to your user’s computer to run. JavaScript is sent as plain text, so anyone who plays your game will have access to its source code. There are a couple of ways to get around this if you’re concerned.

The first is to run the code through an obfustigator. This is usually done to shrink the size of JavaScript program to make it easier to send to the client, but also has the side effect of making the code understandable to a machine, but virtually unreadable to a human. The code is still there though, and it can be reverse engineered if someone is determined enough. It’s more of a deterrent than a solution.

The second is to split your game into a client and server. The client’s job would be to handle the rendering and input while the server would contain the actual logic for your game. Only the client would be downloaded and visible to the user while the game itself would exist on a server. The server source code would be protected. However, this requires you to have a server up and running for people to play your game and the code for the client would still be visible. It would protect part of your code, but not all of it.

A quick search will yield plenty of libraries for game development through JavaScript. GDevelop and MelonJS are two of the bigger ones I’ve heard about personally, but there are plenty of others as well.

Hopefully this helps highlight some of the features of programming languages that can affect the development of a game engine. The issues I’ve highlighted here will generally only crop up when you try to push a game to its limits by having either a lot of data or heavy processing, and even then some clever algorithms can circumvent some of this. If you read this article because you’re agonizing over what language to learn, then I hope the information here helped you make the choice. Remember: you’re not locked into a programming language forever. You can start learning another at any time and each language you learn makes the next one even easier.

Picking a Programming Language - Part 2: Memory Management

Last time, we took at a look at how whether a language is considered “interpreted” or “compiled” can impact the performance of your game project. Although this can have an impact on your game, it’s not the only aspect of a language that can. The other big feature of a language that can impact your game’s performance is how that language manages its memory. There are several different ways to manage memory and entire books have been written on the subject. In trying to keep this blog accessible, I won’t be going over every approach to memory management. Instead, we’ll take a look at the two major categories that memory management generally fall into: manual and automatic.

Memory Management: Manual vs. Automatic Memory Management

Manual memory management came first and requires that a programmer specifically request memory from the operating system for storage. Whenever a variable is declared in code, the instruction is effectively asking the OS for enough space in memory to hold the variable’s data type. Because all the variables are in the code when it’s compiled, they’re known at the time of compilation. This means we know how much space needs to be set aside for all the variables when the program is loaded into memory. But sometimes we don’t know how much memory we’re going to need. Maybe our program needs to open an external document and load it into memory so it can be displayed and manipulated. We could try to guess at the biggest possible file we’d ever need to load, but then we’d be setting aside all that space in memory on the off chance the document is even that big. Any unused space is effectively wasted. To keep executables small while still supporting the ability to be flexible, we have access to a second type of memory: the heap. The heap is a term referring to memory that’s allocated at run-time, also called dynamically allocated memory. Lower-level languages such as C and C++ have specific commands to request memory from the heap. When the command is run, that amount of memory is allocated to the program from outside the program and a handle to that memory is returned. That handle can be used to read and write to the memory on the heap. However, returning that memory when we’re done with it is the responsibility of the programmer. That’s where things can get tricky.

Because the programmer is responsible for dynamically allocated memory, mismanaging that handle can cause problems. The most common one is the memory leak. Remember: the heap effectively exists separately from the rest of our program memory. If we don’t tell the OS that we’re done with it, it will continue to leave it allocated to the program even if the program terminates or the variable holding the handle is reassigned. If the programmer isn’t careful about ensuring all the heap memory they requested is freed, the system will start to accumulate memory that has been allocated but not freed. If the program runs for long enough or is run often enough, the RAM in a system is gradually used up until there’s none left. The system will try to compensate, but will eventually run out of memory for basic operations and crash.

Alternatively, some languages are designed to manage memory automatically. Most languages still allow us to request memory from the heap, but doing so is a basic part of the language instead of something separate. That memory will also be tracked and released for us during execution. This frees up the programmer to just focus on writing code that works, rather than dealing with memory. In general, this is great but it does come at a cost (sound familiar?). Automatic memory management requires that some system is monitoring and managing the memory. This system requires resources to run, resulting in increased overhead in terms of both memory and processing time. The automatic memory management algorithms are also only so effective. As programmers, we know exactly when we’re done with memory, but an automated system doesn’t. They’re designed to be more general, which means memory isn’t always freed up as soon as a program is done with it. We have to wait for the memory management algorithm to determine that the memory should be freed. If your game is creating and deleting a lot of objects, you’ll find a portion of the memory used will linger for a little bit, resulting in a bigger memory footprint than your program strictly needs. In the worst case, the memory management system may actually halt execution of your game while it searches through the program’s current memory space for any memory that can be freed. If your game isn’t using a lot of memory, you may not even notice when this happens. If it is, you may see your game stall until the memory management is done. In console game development, this generally isn’t considered a great option. Languages with manual memory management such as C++ tend to be more popular for console game development because developers can utilize more of the available processor time and RAM for the game itself instead of managing memory. That means more objects and better framerates.

Now that we’ve covered two of the biggest language features that can impact game performance, next week we’ll take a look at some of the more common languages available to write games in and how they factor into the world of game development. See you then!

Picking a Programming Language - Part 1: Language Types

One of the most common questions I see in various forums from people new to game and simulation programming is which language they should choose. If you already know a programming language but are just getting started in game development, my general suggestion is to just use the language you know best. If you don’t know a language yet or you do but you’re thinking of picking up a new one for an upcoming project, then read on because I’ll be going into some of the features of languages that can impact your project. Programming languages are a complex topic, but I’ll try to avoid going too deeply into the nittygritty so if you’re new to programming, hopefully you’ll walk away with a better understanding of the factors involved in picking a programming language without being completely lost. Because there’s so much to discuss (and the first draft was massive), I’ve broken it down into a 3-part series.

I should point out that these suggestions are all based on writing a game completely from scratch. In other words, these features will affect the game engine you write. If you plan to use a pre-made game engine such as Unity, Unreal, Stencyl, etc. then the language choice is pretty much out of your hands. This is actually one of the reasons using an existing game engine isn’t always the best choice for some projects, but that’s a conversation for another post. If you plan to pick up a game engine, then you’ll be using whatever language that game engine uses.

There is No Best Language

Let’s start with the question I’ve seen a thousand times online: “What’s the best language for game dev?”
Answer: “There isn’t one.”

Like any software, different languages have different features that could help or hinder your game development project. It depends heavily on the type of game you have in mind and where you plan to run it. Game development resources have exploded over the years, so no matter what language you choose there’s probably at least one game development library available to make your life easier. If you’re just looking to learn about game and simulation development, don’t let picking a language stand in the way of learning the craft. Once you have the basics, you can always move on to a new language that better fits your dream game. The algorithms and concepts behind game development are rarely language-dependent, and learning them in any particular language won’t bar you from using them elsewhere. They just might need to be translated a little.

Of course, this wouldn’t be a very interesting post if we stopped there. Even though most algorithms can be written in any language, they can still differ in how they run your game. As game developers, it’s worth knowing the benefits and limitations of languages and how they could potentially impact your game. Minecraft is a prime example of a game that has bumped up against the limitations of its language over the years, especially with the growth of the Minecraft modding community.

Language Type: Compiled vs. Interpreted Languages

Programming languages are designed to be read and understood by both humans and computers, but doing so takes a little compromise on both sides. We need something that can be analyzed and written by a human, but also understood and executed by a computer. Code might look like a foreign language to people new to programming, but they’re really just a series of instructions for a computer to follow. In a compiled language, we take the code we’ve written and translate it into instructions a computer can follow. This process is called “compiling.” The result is a file called an “executable” that contains a set of instructions for a computer that can be loaded into memory and run by the operating system on a processor. The problem with this is that any executable that’s created will only work for the operating system it’s compiled for. In game development, this means compiling your game on Windows will result in an executable that will only run on Windows systems. This is made worse by the fact that one often can’t just compile the same code for a different operating system. Different operating systems may use different instructions to accomplish similar things. For example, while Windows uses the Winsock library for network communication, MacOS and Linux use BSD sockets. Both libraries provide instructions for network communications, but the instructions and methods differ slightly. This means having to write two different versions of your networking code in order to compile it on both Windows and Linux. It’s possible (and even common), but it’s also more work.

Interpreted languages are a more recent invention (relatively) and work differently. In these systems, the code isn’t compiled into machine instructions. Instead of loading an executable into memory, the code is translated by an interpreter which feeds the resulting instructions to the operating system through a virtual machine. This makes interpreted languages extremely portable. You can write the code and move it to any operating system that has an interpreter & virtual machine (the two usually come together) for the language without worrying about OS-specific instructions. This portability does come at a cost though. Because interpreted languages don’t generate instructions that can be executed directly by the operating system, we have to use a different way to tell the processor what to do. This is done through a virtual machine. The process looks something like this:

  1. An interpreter compiles the code into a series of instructions that the virtual machine can understand.
  2. The resulting instructions are loaded into the virtual machine.
  3. The virtual machine executes the loaded instructions using its allocated resources.

The virtual machine acts as, well, a virtual computer. It maintains its own set of resources and processes instructions much like a computer would process an executable but it exists in a computer system’s memory and uses its resources to operate. It adds an extra step between the code and the processor because the virtual virtual machine effectively translates the virtual machine instructions into instructions executable on the processor while the program is running. The virtual machine also requires resources to run in addition to any resources required by the program its running, leading to increased overhead. As a result, interpreted languages tend to run a little slower and use a little more memory than compiled languages.

From a game development perspective, one of the other roadblocks to game development with interpreted languages is the virtual machine itself. Because interpreted languages require a virtual machine to run, your users must also have the virtual machine installed to play your game. This means requiring your user to download and install the appropriate virtual machine. It might seem minor, but in the competitive world of game development, even small obstacles to your user’s experience can have a big impact on the number of people who play your game.

I should point out that the reality of compiled vs. interpreted languages is actually much more complex and nuanced than I’ve presented here. If you look online, you’ll find plenty of discussions about wehther or not any particular language actually counts as interpreted or not. This is just meant as a general introduction to the topic to help inform your language choice. Join us next week when we look at the second major feature of a language: memory management.

Welcome to FrogBytes!

Over the years I’ve worked with a lot of aspiring game developers, both in-person and online. It’s been amazing seeing so many people take an interest in making their own video games, but I’ve also started to notice a more recent trend in the people seeking help. The internet is so rife with tutorials about how to do specific things in any game engine imaginable that beginner game developers can find exact code snippets to do virtually anything they want to…until they can’t. Eventually, it seems they reach a point where they need to do something specific to their game that no one has done before. They can’t find a tutorial and code snippet to copy, so they turn to the internet and start asking how to do it. This isn’t bad in itself. There are hundreds of game developers who are all too happy to help someone make their game a reality by sharing their knowledge, but it can also be frustrating to try to explain to someone the workings behind a solution when they lack the foundation needed to understand it. The result seems to be either more copy-paste code that results in a mess of code that feels like it’s held together by sheer willpower and luck, or a beginner that gets frustrated that no one will give the exact code needed to make their idea work which results in both the helper and helped being frustrated.

I’ve started this blog to share the algorithms, design patterns, and approaches I’ve seen over the years in game and simulation programming and to answer some of the more common questions I see online. I will try to present the algorithms in a language-agnostic way so people can understand how they work and implement them in whatever engine or framework they want. If you’re looking for how to make a health bar in Unity, this probably won’t be the place for you. If you want to learn how health bars work so you can write your own in any position, colour, and engine you want, then stick around because that’s what we’re here for!

My goal is to post every friday, but being a substitute teacher in the middle of a global pandemic has kept me insanely busy. I hope you’ll bear with me if the occasional Friday gets missed. I’ll try to keep them as infrequent as possible.