What to Consider When Developing a Video Game
To make a video game of your own, you'll need a fun idea for a game, which is a big hurdle to overcome to start making a game. Let's assume you have an idea for a game and want to bring it to life. To do this, you'll need to write code to make everything work, art and sound design to make everything appealing, and you'll need to do anything you can to ensure your game runs smoothly and the experience is enjoyable for your user.
The last piece of the puzzle of making the game run smoothly is the priority for many game developers, and choosing the correct language to code your game typically ties back to this issue. C++ is "renowned for its speed and flexibility, and [its] ability to communicate directly with hardware." [1] Before jumping into the details of why C++ works so efficiently, let's explore a few other languages used for game development and where they may have an edge over C++.
Comparing C++ With Other Game Development Languages
Before discussing C#(Sharp) and Java, I want to highlight a few other languages used in game development for different reasons.
JavaScript, Python, and Lua
JavaScript can be found on web pages, servers, and even on Raspberry Pis, which has become a popular way to make portable game systems. A few game engines support JavaScript code, including "Impact.js, LÖVE, and Crafty.js." [2] Python and Lua can be easier to pick up when learning a new programming language, and both come with support from many open-source game engines. These three languages have been mainly used for 2D games. They can also be used with 3D games, but it is recommended to use Python for 3D over the other two since JavaScript has limited support and Lua has no support. In a future article, I plan to spend more time researching these languages in the gaming space.
C#(Sharp)
C# has support from many game engines, which include Unity and MonoGame. C# is similar to C++, and it is reported to be "less complicated and easier to set up with Visual Studio and VS Code as your Integrated Development Environment." [2] There are many differences between C++ and C# as well, and they should be considered when deciding on the language you'll use. We're going to highlight a couple differences [3]:
Memory Management
In C++, the programmer manually manages memory, while C# has an automatic garbage collector. C# is more convenient for this task, but C++ gives the programmer more control over how the memory is used, which can lead to optimizing code to run more quickly for smoother performance. Depending on the size of the project, this amount of control over memory may not be necessary if the project is small.
Pointers
Pointers are a way of referencing an address in memory, and I will go into more detail later in the article. In C++, pointers can be used anywhere in the program, while C# can only use pointers in unsafe mode. "Unsafe code can create issues with stability and security due to its inherent complex syntax and potential for memory-related errors, such as stack overflow, accessing and overwriting system memory." [4] This means that extra special care needs to used with the unsafe mode in C#, which means that pointers may need to be avoided when writing code for your project.
Java
Java is an object-oriented programming language similar to C++, and "the Java Virtual Machine (JVM) is used to run the bytecode, which makes it compatible with almost any platform." [2] The differences between Java and C++ are similar to C# and let's explore why [5]:
Memory Management
In Java, memory management is controlled by the Java Virtual Machine (JVM), while C++ is manually controlled.
Platform Dependency
Both languages work on any platform. For Java, it uses the Java Virtual Machine (JVM) to accomplish this. For C++, it needs the correct compiler to compile the code for the correct platform.
Pointers
Java can use pointers, but there is limited support for them. C++ fully embraces pointers to the point that values can also be called by reference, and Java only calls by value for the pointers.
Choosing C++ For Video Game Development
When developing a video game, resuing assets will happen naturally. Introducing obstacles for your player to overcome and returning to the same or similar obstacle later creates a sense of progression for your player to show them how they have grown throughout the experience or how they can look at an obstacle in different ways to overcome it. This structure sounds like a class in programming, a way to reuse code multiple times throughout an application. Picking an object-oriented programming language will be paramount for a smoother development period. Luckily, the languages I've mentioned all support class-based programming techniques. Let's look into why C++ is often chosen for game projects.
Regarding performance, video games designed with C++ run more quickly and smoothly than other languages when creating games that can scale well. C++ accomplishes this by giving the programmer direct control over memory management. Other languages handle these tasks automatically with garbage collectors. "Understanding pointers, memory allocation, and memory leaks can help your game run smoothly without wasting valuable resources." [1] We're going to break down these three things with a few coding examples.
Pointers
A pointer is a variable that stores the memory address as its value. Since a pointer stores an address, we can make a call-by-reference. Pointers can "create and manipulate dynamic data structures" [6] and can be used to iterate over these data structures.
To use a pointer, you need to define a pointer variable that matches the data type you will be referencing. The data type must be associated with a pointer so it "knows how many bytes the data is stored in." [6] Use the unary operator & on the variable address you want to store on the previously created pointer. To access the value stored at an address, use the unary operator * on the pointer.
#include <bits/stdc++.h>
using namespace std;
void pointers() {
int var = 20;
// Declare pointer variable
// Note that the data type of ptr and var must be the same
int* ptr;
// Declare pointer of a pointer variable
int** ptr2;
// Assign the address of a variable to a pointer
ptr = &var;
// Assign the address of a pointer to another pointer
ptr2 = &ptr;
// ptr holds the address of var
cout << "Value at ptr = " << ptr << endl;
// var holds the value of 20
cout << "Value at var = " << var << endl;
// * dereferences ptr to give the value of 20
// located at the address assigned to ptr
cout << "Value at *ptr = " << *ptr << endl;
// ptr2 holds the address of ptr
// Even pointers have addresses of their own
cout << "Value at ptr2 = " << ptr2 << endl;
// Dereferencing ptr2 once reveals that
// ptr2 references the same address as ptr
cout << "Value at *ptr2 = " << *ptr2 << endl;
// Dereferencing ptr2 twice reveals 20,
// the value you receive when dereferencing ptr once
cout << "Value at **ptr2 = " << **ptr2 << endl;
}
int main() {
pointers();
/*
* Value at ptr = 0x6caebffc54
* Value at var = 20
* Value at *ptr = 20
* Value at ptr2 = 0x6caebffc48
* Value at *ptr2 = 0x6caebffc54
* Value at **ptr2 = 20
*/
return 0;
}
Since we store the address to other data types, we simulate calling by reference. We can modify any data type within a function and reuse that updated data later in our code.
Dynamic Memory Allocation
If we expect a certain maximum-sized input, we could prepare our program to have enough memory set aside to match the worst-case scenario. This could pose a problem as a project continues to scale larger and larger. What if we could pick how much memory we need only once we know how much is needed? This would prevent unneeded memory usage and allow our code to run more efficiently. This is the key principle behind dynamic memory allocation: only set aside enough memory space to accomplish the task at hand and then free up the space immediately after.
Check out the following code [7] with the addition of comments to help you see how we accomplish dynamic memory allocation:
#include <iostream>
#include <new>
using namespace std;
int main() {
// i => Used for looping
int i;
// n => Used for capturing the input for the first question
int n;
// ptr => Pointer used to reference memory that is allocated
int* ptr;
// n is assigned the input from the user
cout << "How many numbers would you like to type? ";
cin >> n;
// new => Allocates space match the input for n
ptr = new (nothrow) int[n];
// Check to make sure ptr points to a valid object
if (ptr == nullptr) {
cout << "Memory allocation error!" << endl;
}
else {
for (i=0; i<n; i++) {
// Ask for a number n times
cout << "Enter number: ";
// Store the number entered in memory
cin >> ptr[i];
}
// Reveal to the user the choices they made
cout << "You have entered: ";
for (i=0; i<n; i++) {
// Pull each number from the allocated memory
cout << ptr[i] << ", ";
}
// After we finish with the task,
// we free up the space taken using delete[]
delete[] ptr;
}
return 0;
}
The use of the delete keyword is essential when coding in C++. Since programmers need to clear out their memory manually, developing good habits to clear out memory once it's finished being used will lead to less frustration and fewer bugs, and it avoids the dreaded Memory Leak.
Memory Leak
In C++, there is no automatic garbage collection, which means that any memory that a programmer dynamically allocates throughout the lifetime of a program needs to be freed manually after its usage by the programmer once it is no longer needed. If a programmer forgets to free this memory after its usage, it will occupy the space while the program lives and will be unavailable to other processes. Often, a function may need to be called several times, and if each call allocates more memory without removing it, a lot of unused memory will take up space. This accumulation of unwanted memory usage is referred to as a memory leak. These can drastically slow down a program, but they are the avoidable price for faster running code. [8]
Final Thoughts on C++ For Game Development
Having complete control over memory usage is a huge plus, or some might call it a "plus-plus." We create pointers to store the addresses of newly created data structures. After the stored memory has been used to completion, we remove the data from memory to free up space later in the program to prevent memory leaks. The object-oriented programming language aspect of C++ also shows the usefulness of reusing code.
C++ isn't the only choice for a game development language. Java is portable and can be used across multiple platforms, but it is limited in making 3D games. C#(Sharp) is less complicated than C++, but it has little to no support for pointers unless you use unsafe mode, which is not recommended unless you take extreme care while programming in that mode.
Due to the programmer's direct control of memory in C++, fast speeds can be achieved with pointers and dynamic memory allocation. Speed is an important consideration when designing a large-scale video game because an unresponsive or slow-to-respond gaming experience can leave your user unsatisfied.
Happy Coding,
Tyler Meyer
Sources
Sources:
[1] https://www.geeksforgeeks.org/cpp-for-game-development/
[2] https://www.orientsoftware.com/blog/gaming-programming-language/
[3] https://www.geeksforgeeks.org/c-vs-c-sharp/
[4] https://www.c-sharpcorner.com/UploadFile/f0b2ed/understanding-unsafe-code-in-C-Sharp/
[5] https://www.geeksforgeeks.org/cpp-vs-java/
[6] https://www.geeksforgeeks.org/cpp-pointers/
[7] https://cplusplus.com/doc/tutorial/dynamic/
[8] https://www.geeksforgeeks.org/memory-leak-in-c-and-how-to-avoid-it/
Top comments (36)
One thing, C# is not specific to Windows... I've been coding games in C# with Unity since 2011, and I've not had a Windows computer in all that time!
This indeed is true. It is not hard to make C# projects that are built entirely on Linux, that even cross-compile to different linux targets, and build with forward compile (native) code. The nuget infrastructure works the same on Linux. And one can even produce stand-alone binaries that work well with docker, too, that target alpine musl libc, and are often no worse in size than say golang binaries.
Linux choices for cross-platform front-end ui's may be more limited, but most games are scene renders on a window anyway. C# has peculiarities, but both C++ and C# are peculiarity by design ;). I do not talk much about C# simply because nobody asks me to produce things with C#. One could talk about F#, too, as it is a great example of what a properly expressed general purpose functional language can look like.
I must have read some inaccurate information about C#. I'll update my post. Thank you for your insight!
I noticed that a lot of people make this a assumption.
C# started off as a Microsoft's attempt to replace Java on Windows, so the assumption has a bit of truth in it. But indeed, C# is a perfectly multi-platform language nowadays, has been for more than a decade.
It's also a VM-based language, just like Java. It has less focus on the "compile once, run everywhere" idea, though - understandable as that idea didn't quite work for Java either. But if you feel like it, you can even spin up a .NET VM inside a browser and write a web app in C#.
Yeah, Unity even compiles IL back into C++ for a bunch of platforms.
C++ is not cross-platform very much. Different compilers frequently generate binaries that work differently. And, you have to recompile your code for different platforms, while Java has cross-platform binaries by default.
Also, manual memory control is always a negative trait of C++, not a positive one. Manual memory control fails everywhere, comparing with garbage collector.
Interesting! This space has been very opinionated online. I kept reading how memory management in C++ helps with speed and performance. I have a background in JavaScript and am beginning my learning in C++. I also plan to learn C# and Java. From what I've read about Java, the cross-platform capabilities sound so convenient. Are you familiar with Java? Do you use it regularly? If so, what do you like about it?
Java memory allocation in fact is faster than C or C++ ones. I made benchmarks recently, and I am going to write an article about that. I used Java for two years in my personal projects, but last 6 months I use Clojure (Lisp on JVM), making my game.
If you know how to benchmark properly, you can find yourself, that modern Java is faster than C and C++, or equal. JIT compiler has much more freedom and information, than traditional static compilers.
Though, good luck using C++ for making games. Having competitors struggling with C++ is a very good thing for everyone else
I see more studios struggling to adopt Rust than to code with C++.
Yes, Rust hysteria is a real thing.
When I say that C++ is bad, I don't say Rust is better.
I used to use C++ decades ago and came back to it 2 years back with Unreal, tbf Unreal has a big ecosystem, but it does make C++ work better for me. Given how successful Unreal games are, I don't think you can dismiss C++ like it's a joke, though; a lot of significant games have a combination of blueprints and C++ developed for them.
Bare metal allocations in C++ can improve performance; they just take a lot more thinking about. I'm good with game developers not caring and using something else that deals with it for you - I do most games in Unity GameObjects so I definitely fall in that camp for many projects. Unity has introduced DOTS to combat the performance of lower-level languages and the kind of designs that work well in them.
Bare metal allocations don't improve performance. Check it for yourself, compare with garbage collected languages, such as Java. Allocations there work faster for a reason. I am going to write an article about that (with benchmarks, of course), so you are welcome to read it in future.
In reality, C++ and C are not only slower (or same) with Java, Go, Lisp, but significantly less safe, less readable and less effective (we are talking here not about system programming, but about games)
Yes I've checked it for myself, garbage collection sweeps and allocation frequencies have big impacts in hard to fathom ways. There's a reason why most game engines are written in C++ - Unity and Unreal etc.
Mister, do you have exact benchmarks? Because I do.
github.com/Taqmuraz/alloc-table
And they show, that C and C++ are slower in memory allocation, than Java 17.
Yes, there are reasons, why most game engines written on C++, yes. But speed is not a reason.
Sure, list your benchmarks and their code and I'll figure out where you got it wrong :)
You have a link. I am open for any critics. More than that, I WANT you to show me if I am wrong. Please, e-mail me, if you find something. My e-mail you may find in my profile.
Checked your c++ code and I'm confused on why you would create a pointer on one line only to delete it two lines after.
You would never see anyone do this in real code because that's no what pointers are meant for. Pointers are for resources that need to be held for long periods through different scopes and gives you the control of when to delete it.
A garbage collector which Java uses on the other hand do not give you this freedom. Instead they choose specific times to collect and delete unused resources all at once which can create visible performance degradation for demanding applications and would be a nightmare for a game.
Rather than allocating and deleting a pointer on every loop iteration, you should either allocate it all at once as a pointer to an array or just use a plain old variable, keep in mind the default c++ allocator is slow compared to other allocation methods
Edit: Additionally java requires a virtual machine which basically makes it an interpreted language. For very demanding tasks, an interpreted language will never match the speed of a compiled language like c++.
I added that
delete
call only because without that C++ test cannot complete (out of memory). Table has results without thatdelete
call.Also, benchmark is a benchmark. It is not a program that does something useful. So, I would expect critics of measuring methods and results, not style.
UPDATE:
Actually, releasing memory exactly after you used it is a good thing in C and C++, it makes next allocation faster (benchmarked as well, though it is explained in specs).
If you're going to use a resource for 3 lines of code then don't use memory on the heap, use a normal variable. It's not about coding style it's about what the feature was designed for. There's limited value in the testing scenario itself
Also you should use std::Chrono for timing because sys/time has been known to be inconsistent on different platforms
First. I am testing heap memory allocation, so I allocate memory from the heap. Period.
Second. How much inconsistent sys/time is? Do you think that use of std::chrono would change results by at least 5%?
UPDATE
I really don't get it. Test clearly show, that C malloc is slower than java new[].
All point of the C test is to measure how much time does take malloc itself.
And you are saying something about malloc use cases. Did I say anything about use cases?
lol, first of all, benchmarking memory allocation does not equal to benchmarking manual or automatic memory management, it only benchmark a part of it, so your test result does not mean manual memory management is slower than managed ones.
secondly, I wonder what would be the reason for game engines mostly written in C++ when you claim that its slower, unreadable, unsafe, and inefficient
Starting conversation from "lol" does not make you look smart.
Memory management includes allocating, accessing and releasing memory. I proved that allocating and releasing memory is slower in C and C++, than in Java. So, you want to say, accessing memory in C or C++ is somehow faster or what?
Well, I also wonder, why people choose C++ in game industry. Though, appealing for its popularity is a dubious argument. Job market state, traditions, history, people's fallacies, many factors, and you must prove that speed is one of them.
Show me that speed you are talking about in actual benchmarks.
I agree the main idea, which C++ give a better control on computer resources and hardware.
But I find Javascript option analysis very (very) short!
The given libraries are totally out of date, whereas there are powerfull alternatives today for 3D games like Babylon.js (just by Microsoft) or Three.js!
On other hand, even if C++ has still granularity advantages, new versions of theses above libraries bring now native GPU api control through WebGL, so I think we have to consider them more a little bit.
While Babylon and Three.js are great, they are not the best for intense graphical games. One is better off using WASM for massive multiplayer and intense graphical games. When speed and memory is not a concern, Babylon and Three.js are great
I am considering JavaScript more since I have a background in that language. I am learning C++ and used this article as an opportunity to learn more about it. Due to time constraints, I had to cut my research short on JavaScript, Python, and Lua. Perhaps in a future article, I'll dive deeper into JavaScript's use in the gaming world.
I did a bunch in PlayCanvas; it was fun and performant enough for a whole slew of games. Choosing probably depends on whether you want to learn C++ or you want to make games. If the latter, I'd recommend PlayCanvas or Babylon.js - if the former then as others have said, choose your engine and the language is chosen for you.
I think the title is wrong. People do not choose C++ for game development; engine creators choose the programming language people should use with their engines.
Exactly. Games using Unreal will be largely written in C++, games in Unity will be in C#, Godot games will be in Go, and RPGMaker in JS. Most studios aren't going to be creating a game engine from scratch.
I need to change that title for sure. It was an early inspiration for writing this article, and my opinion changed while researching, but I forgot to revise the title. Thank you for giving it a read! I am new to the space, and I've been writing articles to learn more and give me a reason to research areas I wouldn't normally spend a lot of time in.
2024 and people still think C# and .NET are specific to Windows when .NET Core was released in 2016.
Lol what about .NET MAUI?
Because c++ have the opp
Things I've found to be true with Java:
Yes, you can write once and have code run on Windows, iOS and Linux operating systems (and some others as well) but the user has have Java installed.
An alternative is to compile the Java code with a built-in, customized JVM. In this case, one needs a JVM for each OS, and it can be a bit of a task setting this up for each.
I found that there are some differences in the ratio between font sizes and pixels, for Windows vs iOS/Linux systems. For this, I've resorted to creating alternate sets of constants to be used with a given OS that pertain to the size of fields.
There are a couple Game Engines that primarily use Java: JMonkeyEngine and libjdx.
Personally, I dislike pointers. I find their use makes code more difficult to read and more prone to bugs. You may not have any problem with them.
For the most part, Java is very close C++ in terms of performance speed, and to me, easier to code with Java, and it is better adapted to multithreading and functional coding. But it's been a number of years since I checked out how these aspects are handled in C++. I assume there have been improvements.
I think it's a shame that the Java game engines didn't get the level of support similar to Unity or Unreal. IDK why, but it does seem that on a number of occasions Oracle decided to ignore requests by the Java gaming community to open up some aspects of the GPU and graphics in a way that would have allowed faster rendering. There are folks that have a better understanding of the history than I do.
This interesting
Some comments may only be visible to logged-in visitors. Sign in to view all comments.