Programming

"Square pixels in 4:3 ratio really triggers me"
- Anon

What should I use?

There's many ways to make a project. You could just pick a game engine and start dicking around with it, you could download game frameworks and libraries and use their capabilities to piece together a project, or if you're mega autist you could write literally everything yourself from scratch.

The programming side of game development could be thought of as many layers; first you make the tool, then you use the tool to gather resources, then you make something with those resources. You can jump into a specific layer depending on your preference, but that means you have less control of the layers below it. So if you don't make the tool yourself, you'll have to work within the limitations of the tool you chose and deal with the quirks it comes with.

Layer 1: languages
A programming language can come in many shapes and sizes, but ultimately it is a human-readable way to tell the computer what to do. Well-known compiled languages include C, C++, C#, and Java, while Ruby, Python, Lua, and JavaScript are more popular choices for scripting.

Layer 2: libraries
A library is essentially a bunch of code that someone else wrote and that you can use for your own project. It usually contains a number of useful helper functions, performs one specific task very well, or implements a complicated system that would be difficult to do yourself. Many languages come bundled with several libraries, for example most languages have some kind of math and timing libraries to help you do simple operations. Perhaps the most well-known example is OpenGL, one of the most widely-used graphics and rendering libraries, which comes bundled with most operating systems. Libraries can come in compiled or uncompiled form, open source libraries will give you access to the full source code.

Layer 2.5: frameworks
Frameworks can be thought of as collections of libraries. SFML and SDL are both frameworks that help you interact with your operating system and hardware for audio, graphics, input devices (e.g. mouse and keyboard), and more.

Layer 3: game engines
A game engine is the heart of your game, it's a large collection of functions and features geared towards building a game. Game engines also come in many shapes and sizes, at the most minimal level a game engine may be just a very large and specific framework. However, many large game engines such as Game Maker, Godot, Unreal, and Unity have a highly sophisticated visual interface and tools that help you organize and build the game and move things around and drag and drop files and more, which makes it much easier to manage your project. Game engines also usually include systems for physics and textures and models and the game world and many other parts of the game code, making it effectively an editor for a videogame that has nothing in it.

Game engines also come with a rich set of debugging tools so you know exactly what went wrong and why, as well as the ability to immediately run changes to your code and experiment with logic and adding content. While it is possible to get advanced debugging tools without an engine, they're more hassle to work with and are sometimes limited to a partiuclar IDE, while an engine does it all straight out of the box in the same interface.

Some engines are only suited for very specific purpose, for example RPG Maker is a game engine that makes it very easy to create RPG games, but it's very difficult or impossible to use it for other types of games. Engines usually support one or two specific languages (usually scripting and markup languages), and it is very difficult (if not impossible) to use another language with it. It is usually possible to use libraries or even frameworks with an engine.

Because engines are usually a commercial product, some have terms and conditions to release a game on their platform, such as licensing fees or restricted controversial content.

Layer 4: modding
Modding is the act of modifying aspects of a certain game. This can be simple as adding new content, fixing bugs, translating the game to another language, or creating whole new games using the modded game's engine and logic usually called "total conversion" mods. How this is done varies. Some games can be modded by changing the games assets while some are modded by altering the binary directly. Many popular games have official tools for creating mods (usually level, script, and sprite/model editors) but unofficial tools exist for popular games without official modding support.

Keep in mind that usually there is still programming involved when it comes to making mods. Usually it's done through scripting languages either common ones like Lua or Python, custom languages made specifically for that game or engine like CaveStory's TSC language or UnrealScript, or Assembly or the language the original game was programmed in if you are modifying the binary directly. Also keep in mind that many games (especially commercial games) have terms and conditions when it comes to mods such as only allowing distribution on a certain site/forum/platform, restricting controversial content, or out right banning mods entirely. Freeware and FLOSS games usually don't have this problem and may even allow you to distribute your mods with the binaries so you can release them as standalone games.

ROM hacking is basically modding for console games (usually ones that can be emulated). Unlike modding, ROM hacking is usually done by changing the binary directly since all of the game's code and assets are usually compressed into a single file. Many popular retro console games have ROM hacking tools created by fans so you don't have to worry about reverse engineering everything yourself. To avoid copyright infringement, many ROM hacks are distributed as software patches, requiring the original ROM or ISO to be played.

Layer 5: money
Just pay Pajeet to do it.

…so what DO I use?

Which tools and methods you should use mostly depends on your intentions and personal preferences. If you just want to make a game and don't care about the specifics, consider learning a game engine. If you want to improve your programming skills or get good at using a particular language, making your own engine from scratch with basic libraries is a great way to do just that. If you're comfortable with programming but primarily want to get a game done, look into game related frameworks and libraries or experiment with engines.

  • If you're not going to use an engine, it is more or less a requirement that you genuinely enjoy programming, otherwise you're not going to have a good time. Furthermore if you're not experienced with programming, it will take you a long time before you can expect to have a game.
  • If you've never programmed before, it's not recommended to start out with a low level language like C or C++, or an obscure/new language like Go or Haskell. Low level languages require a lot of preparation and padding before you can get anything done, which will easily lead to demotivation and frustration. Obscure and unpopular languages on the other hand have small communities, so if you get stuck or confused, it will be harder to find help. This also applies to libraries, frameworks, and engines. Learn one of the more popular high level scripting languages (like Python, Lua, or JavaScript) instead, and then see if you want to go into deeper or more obscure languages after you've got your bearings. Everyone has a different level of interest towards programming, and not everyone wants to go into meticulous detail with low level languages like C. Knowing one language makes it much easier to move into another, so even if you learn a scripting language it won't be a waste of time.
  • For text-based games such as text adventures, you typically don't need any other tools than the language. Even shell scripting languages like Batch and Unix shell can be used. Text can be very easily displayed on the operating system's console, which also accepts text input from the user. It cannot display any images or play sounds however, and if you want to use color or ANSI text, you are going to need a TUI library (such as curses) on most operating systems.
  • 2D games can be made by most game engines, including seemingly 3D engines like Unity, but ideally you should use an engine that's specially designed for 2D such as Gamemaker, RPG maker, or Godot. Do not underestimate game makers, as many successful games have been made using them. Alternatively it is not too difficult to roll your own engine using libraries such as OpenGL (cross-platform), DirectX (Windows) or frameworks like SDL and SFML.
  • If you want to make a 3D game, it is highly recommended that you use an engine or mod an existing 3D game, since implementing 3D graphics and physics and texture/model formats yourself can quickly get very overwhelming. It isn't undoable or unheard of however, and even several people from our own /agdg/ have done it before.
  • For HTML5 games, Javascript is more or less required, as it is the only language that reliably works on all major web browsers. Note that HTML5 is not actually a programming language and you cannot make games with it, a "HTML5 game" simply refers to the <canvas> element on the page which is used to display graphics, the actual programming is most likely done in Javascript. However, a new option called Webassembly is quickly approaching. Webassembly is a "language", but to better understand it it's better to think of it as a special program that can run on the browser. You do not actually write Webassembly, you compile into it from another language such as C++. It is currently very new and unfinished however and is not properly supported in all browsers, but in the future it will likely become highly preferable to Javascript as it will allow for much greater performance.

Which language to use?

The debate of the languages is a never ending one. You will never get an unanimous answer because everyone has their own preferences. In the end the best thing to do is to look into many languages and make a decision for yourself, as you will never get a proper answer from other people. Even the best and most popular languages aren't objectively the best options for everyone. If you're using a game engine however, the choices are probably narrowed down to one or two choices as it is very difficult to use any language that the engine does not support. In that case look into what language(s) your engine of choice supports and learn that.

Note that a "powerful language" does not make your program powerful. It simply gives you power, but it is up to you to use that power responsibly. An incompetent programmer may make a slower program in C++ than they will make in Java, because it is your job to use C++'s power correctly while Java hides the fine details out of your sight. Conversely, a competent programmer's C++ program will leave the same programmer's Java program in the dust, because Java does not provide the same level of control that C++ does.

Common/popular/relevant languages

  • Assembly is the lowest level programming language that is human readable. Every computer architecture has it's own version of assembly, thus it's not portable. It is also very difficult to learn and understand and definitely not beginner friendly. The benefit to writing in Assembly however is that you have minimal CPU overhead and you can take full advantage of the hardware. Unless you're autistic and/or writing for much older platforms like the Atari 2600 or Apple ][, there is no need to write games completely in assembly these days. Assembly is sometimes used alongside another language when you need something to have very high performance, so assembly knowledge is still useful for advanced gamedev. Some languages and compilers allow you to write "inline assembly", i.e. write assembly code in the middle of other code.
  • C++ is the industry standard and probably the safest choice at the current time, although it is a very old abomination covered in duct tape and swiss army knives. Many love it, but just as many hate it, but unfortunately there's currently nothing that can quite replace it. Use it with care and you can consider it an upgrade from C. However, while C++ is technically "C with more stuff", it has had so much bloat added to it over years that it is very difficult to fully learn, and the compile times can get slow especially if you use certain features like templates. You can ignore those features for yourself, but as soon as you start reading a tutorial or someone else's code in general or using a library, you'll run into it again.
  • C is the older brother and a much simpler version of C++, it is a very capable language although quite lacking in convenience features like classes and garbage collection. Many people still prefer it over C++, it does exactly what it needs to and nothing more and is much cleaner than C++ as a result. If you want to use C, you MUST get comfortable with the idea of pointers and memory management. C is one of the fastest languages and is often used as a benchmark language to test speed against.
  • C# is a higher level cousin of C++ created for Microsoft's .NET framework. It is somewhat simpler than C++, but doesn't give you as much power, but is a good and popular choice for game development either way. It is commonly used as a user/scripting language in big game engines such as Unity.
  • Java is both one of the most popular languages but also one of the most hated ones. While it is not in reality the worst of languages, it is used by the worst of programmers. It doesn't exactly give you anything that you can't do better with another language, but it's quite easy to make programs with and has a huge amount of support online. Think of it as the Unity3D of programming languages; tempting because it's easy to work with, but everyone including you yourself know deep inside that there's objectively better choices out there. C# is sometimes considered to be a better version of Java.
  • Javascript is a terrible piece of shit, if you use it for anything other than HTML5 games then you need to swiftly remove yourself from this earth. That said, it is one of the most easy and forgiving languages out there, and excellent to get started with for someone with 0 experience. A bonus note: Javascript has absolutely nothing in common with Java other than the name.
  • Python is one of the most popular scripting languages. It is very high level and probably difficult to make games with in itself, but there's engines and tools such as Pygame that let you make games with it.
  • Lua is currently the fastest (LuaJIT) scripting language and it's the most common scripting language for game development. Like Python, there are many engines and frameworks like Love2d that allow you to make games. It is also a common language used for mods.

Niche/unpopular/new/obsolete languages

  • BASIC is a family of programming languages made specifically for beginners. It was extremely popular for beginning programmers back in the 70s, 80s, and early 90s, but has been slowly replaced by scripting languages like Python and JavaScript. The most recent dialects of BASIC are object-oriented and are usually designed for gamedev. Examples of modern dialects of BASIC include Visual Basic, FreeBASIC, and Gambas.
  • Lisp is an ancient family of languages made for AI programmers and emacs users. Using it will give you a new perspective on programming. It's rarely used for games these days but wrappers for frameworks like SDL and SFML exist.
  • D is a newer language in the C family. It attempts to be a modernized alternative to C++, but isn't actually too similar. It's more similar to C# and Java.
  • Go is a language developed by Google with the aim of bringing back procedural programming in the tradition of C but with modern conveniences such as garbage collection, memory management, and structural typing. It may become a viable replacement to C and C++, but the community is still relatively small. It's more commonly used for server code.
  • Haskell is a functional programming language like Lisp, but with a syntax similar to more common languages like C. There are wrappers for common frameworks like SDL, and there have been games programmed in it, but the gamedev community is small.
  • F# is the functional programming version of C#. It is supposedly on par with C# and compatible with most C# libraries but is not as popular.
  • Swift is a new language created by Apple to replace their Objective-C language. It is intended to teach normalfags how to program to the point where you can use emojis to name variables, classes, and functions. There are game development libraries and frameworks, but this language is not recommended unless you somehow want to make mobage.
  • Perl is a scripting language most commonly used for web servers and as an alternative to shell scripting. Though there are wrappers for multimedia libraries, it's lack of certain features and slow nature makes it unsuitable and unpopular for gamedev.
  • Ruby is a scripting language that aims to be a more powerful version of Perl and a more object-oriented version of Python. It is often used as a server-side language for websites and not common for game development, but frameworks for it exist like Gosu and Rubygame. It's also notable for being one of the few FLOSS projects to be based in Japan.
  • Rust is a new and upcoming language from deep within the headquarters of starbucks, created by the hippest of beards and thickest rimmed glasses. It is controversial due to it's obsession with safety, and can be thought of as a powerful but naggy language that goes fast but doesn't want you to press the "fuck you fags I'm going turbo" button because you might hurt yourself.
  • Jai is a language in development by the creator of The Witness, with the goal of replacing C and C++ in most cases. Some say it might end up doing just that in the future, but some say "fuck that guy". It's intended to make programming fun again, and let competent programmers do good programs even if it means beginners and pajeets are left crying.
  • Zig aims to be a competitor to C, with compatibility to C libraries. It has many advantages, especially in regards to error handling, but has incomplete documentation which makes it hard to get into.

Also note that it is possible to use multiple languages for one program. For example, many C++ programs will use libraries programmed in C and assembly due to the better optimization those languages have, and many games use scripting languages like Lua and Python to script enemy AI and in-game events.

Explanation of terms and concepts

Crash course to programming terms, variables, statements, and data types

  • Variable - some data that you can refer to by name and modify. For example "shekels = 500" will set the value of the shekels variable to 500.
  • Index - index is a word that describes some position in a list. For example the third item in a list may be at index 2 or 3 depending on the index method. Lists are often 0 indexed, which means the first item is 0, second item is 1, and so on.
  • Bit - the smallest amount of data possible, it can be either 0 or 1.
  • Byte - 8 bits. Memory is usually grouped into bytes, rather than being interacted with 1 bit at a time.
  • Binary - data of bits and bytes, all data is technically binary, but the word is usually used to refer to data that isn't in a specific or commonly readable format such as text.

Data types

  • int / integer / short / long - a number value without decimals. The different names refer to how many bytes it has (and thus how high the number can go).
  • char / character - an integer that's 1 byte in size. It can also be used as an ASCII text character, for example "A" or "7" or "/".
  • float / double - a number value WITH decimals (e.g. 1.35). Floats are kind of imprecise, and double has a higher precision than float ("double precision") but is larger in size.
  • boolean / bool - a value that can be either true or false. The actual data and size of a bool varies by language, but usually true is 1 and false is 0.
  • String - a sequence of characters in the form of an array, used to store text in a variable.
  • Array / list - a contiguous list of variables. To access the items, you would do for example "myarray[5]" to access the 6th item.
  • Associative array / dictionary / map - an array of sorts where you can access the items by name rather than index. For example "mydictionary["faggot"]" might access an item that has "faggot" as it's name.
  • class / struct / object - a collection of variables that can be referred to through the object. For example in order to access the "hitpoints" value of the "slimegirl" object, you use "slimegirl.hitpoints". Class and struct are effectively the same thing, though some languages define them as separate and have some minor differences. Usually struct is more plain data while class is a more complicated system.
  • Vector / Vec2 / Vec3… - a vector is essentially a struct or an array that contains coordinates of some point. Vec2 contains X and Y, Vec3 also contains Z, and there are some others. C++ has a data type that some retard named "Vector", but it has nothing to do with actual vectors. C++'s vector type is just an array that expands automatically as you put items into it, also known as a dynamic array.
  • signed / unsigned - Integers can be signed or unsigned. Signed means the value can go to negatives, but it can only go half as high (e.g. -127 to 127 for signed vs 0 to 255 for unsigned).
  • constant / const - a constant is a variable that cannot be modified. When you create it, it will keep it's value forever, and you will get an error if you try to change it.
  • static - a variable that keeps it's value between function calls. When you call a function for the first time, the variable will get initialized. However every call to the function from then on will skip the initialization, and the variable will have whatever value it had when you last called the function.
  • u8, s8, i32, f32, uint_8… - these are just alternate names for integers and floats that some languages have, or they may be defined in the program code. For example instead of having to type "unsigned char", you could just type "u8", and then i8 or s8 for a signed char. The number refers to the size of the variable in bits, char having 1 byte which is 8 bits.
  • Pointer - a variable that has a memory address as it's value. In other words, it points to some data in another location in memory rather than having any data of it's own. Pointers are usually interacted with by adding & or * next to the variable.
  • dereferencing - dereferencing is when you go to where a pointer points to, and interact with the data that's there, instead of interacting with the pointer itself.
  • void - a special data type that refers to the lack of type; it's nothing. Void is usually used to either refer to data of unknown type, or used as a way to indicate that a function doesn't return anything.
  • null / none - means that the variable currently has no value.
  • NaN - means that a variable is "Not a Number". In some languages, number variables can become NaN if you set a non-number value into it.
  • casting / cast - a value can be converted, or "cast", to another type. For example you can cast a float into an integer. In some cases you don't need to do it and in some cases it's automatic. You can also cast void into some type.
  • global variable - a variable that is not tied to a function, struct, or object and can be accessed anywhere in the program.
  • local variable - a variable that is tied to a function, struct, or object and can only be used there.

Common statements

  • print/printf/echo - a statement or function that outputs text to the console. In most object-oriented languages this is usually a method like Console.Write() or Console.Writeln().
  • input - a statement or function that prompts input from the console. Once the input is given it is assigned to a variable.
  • if/else/else if - a conditional statement. Basically the computer will run a block of code if the statement is true. If the condition is false, an else if or else statement can be used to run a different block of code.
  • switch - a short hand version of an if/else statement but can only be used for one variable.
  • for loop - a loop with a variable (usually labeled as i) that increments until a certain maximum value is reached. Often used for reading/writing values in an array or list.
  • foreach loop - a variant of the for loop that loops through the items in an array.
  • while loop - a loop that runs while a condition is true. Once/if the condition becomes false, the loop will stop.
  • do while loop - a while loop that will run once regardless if the condition is true and will repeat as long as the condition is true.
  • break - you can "break" out of a loop even if the loop is still going by using the break statement.
  • continue - similar to break, it will exit the current iteration of a loop early, but unlike break, it does not exit the loop itself.
  • return - similar to break, it will break out of all loops in the function, and exits the function. It is also used to return values from the function to the caller.
  • goto - a statement that allows the computer to goto a certain line or block of code. This is more used in older languages like C or BASIC.
  • eval - a statement/function that allows you to execute a string as code. Be warned that this is a very dangerous statement if not used properly.
  • assert - a common function/macro that checks if the condition is true, then exits the program or function if not and possibly writes/displays some kind of error information. In other words it is used for debugging purposes.

Misc

  • function / procedure / subroutine - a bunch of code that you can call up from anywhere without having to re-type it. You can also give some values to it. For example "dosomeshit(20, 500)" will call the function whose name is "dosomeshit", and gives the values 20 and 500 to it. Functions can also return some values back to whoever called it, for example the dosomeshit function could multiply those two values together and then return the result.
  • method - a function that is tied to an object. Used to modify data of said object or even other objects. Usually called by typing object.method().
  • constructor / deconstructor - a method that is called immediately when an object is created or destroyed.
  • label - A block of code that can be accessed with a goto statement so it can be accessed without referring to its line number. This is more used in older, unstructured languages but still used in shell scripting languages like Batch.
  • exception - when an error happens during runtime (e.g the program is accessing a file that doesn't exist), the program will throw an exception and will go to a block of code to handle the exception if it exists otherwise, the program will crash.
  • Bitwise operations - usually you handle data in bytes, but bitwise operations let you modify then bits within bytes more precisely. For example "«" will shift the bits to the left.
  • enumerator / enum - a list of named values called elements or members that behave as constants. Each element has a different number value, you can add elements to the enum and they will automatically gain an unique number unless you define it separately.
  • scoping / block - a block is an area in the code where variables and everything live. For example each function has their own scope, and variables created inside of it are not available outside of it. Blocks are usually indicated by curly brackets {}. Blocks can also contain functions and structures, making them unusable outside of that block.
  • comment - comments are a part of your source code, but they do nothing. The compiler/interpreter will just cut them out as if they were never there. You should always add comments to clarify what certain parts of your code do, and where different parts of it begin. They are also useful for debugging since you can "comment out" parts of your code and uncomment them for later use.
  • namespace - a place to store objects, structs, and functions making it easier to organize them.
  • using - (note: usage of this mechanic may vary by language) it is possible to "use" a namespace, allowing you to access variables and functions from that namespace without using it's name. For example, "nodev.games = 0" changes 'games' from the nodev's namespace. To use a namespace, you use the keyword 'using', for example "using nodev", now you can modify nodev.games with just "games = 0".
  • union - a way of grouping different datatypes so the same memory can repres.
  • debugging - The act of testing a program for potential bugs and exploits.
  • Refactoring - Refactoring is when you change the way some of your existing code works. Usually it's done to optimize the performance, expand it so it can support new features, or just cleaning it up so it's less shit.
  • Spaghetti code - Spaghetti code refers to source code that it is so messy and disorganize that it is virtually unreadable. Usually caused by poor planning, little to no comment usage, or writing more code than necessary.
  • Psuedocode - refers to a mix between computer code and English. Usually used to help plan out an algorithm.
  • Standard library - A library that is bundled with a language's compiler/interpreter and is usually considered part of the language. Usually contains functions and objects for commonly used algorithms like printing text to the console, mathematical functions, file handling, networking, and in some cases, basic graphic and audio functions.
  • runtime - refers to a time when the program is running, i.e. not before or during compilation.

Dynamic vs. static typing

Dynamic and static typing refers to the way you create and refer to variables. Basically static typing means you need to tell your computer exactly what kind of variable to use, and dynamic typing means the computer figures it our for you depending on what you do with it.

Dynamic typing:

var myvariable;
myvariable = 10; //valid
myvariable = 1.52; //valid
myvariable = "Anon"; //valid

Static typing:

int myvariable; //myvariable is an integer value
myvariable = 123; //valid, 123 is an integer
myvariable = 1.52; //invalid, 1.52 is a float
myvariable = "test"; //invalid, "test" is a string

Why not use dynamic typing all the time? Runtime safety. With a static-typed language, you can guarantee that certain functions, variables, and objects all take up a predictable amount of memory, the right values are being passed to functions, etc. Static typed language will not compile if you try to do an invalid operation, but dynamic typed language will, and your program might crash due to invalid operation unless you check for the proper types.

Compiler, Linker, and libraries

The code you write is just a plain-text document, but the computer can't actually use it in that form. When you run that document through a compiler, the text is converted into data that the operating system and hardware can understand, and it takes the form of a compiled program (usually an .exe when on Windows). Alternately, instead of an executable file, you can generate other things such as a library file (.a and .dll being examples) or a sort of halfway-file that's used to link with other files (.o being an example).

Linking is the second part of the compilation process, and is often implied to be done when someone talks about "compiling". The compiler only compiles your project files halfway into an executable, but the linker is actually the one that ties them together into an executable file that the user can run. The linker is usually part of your compiler or operating system, and may even link your project automatically unless you tell it not to.

Library files contain functions and code that you can use for multiple projects or share with other people, for example a pathfinding library could provide path finding functionality, and it does not need to be re-written for every project. If you're using third party libraries, it often comes in aforementioned pre-compiled library file format so you do not need to compile it yourself. In order to use them, you need to tell your compiler to do the compiling and linking in 2 separate steps. First to compile your own code without linking it (which creates the "halfway" file), and then to use the linker to link it with the library files.

Additionally, dynamic library files (e.g. .dll files) are linked every time the program runs rather than when the program is compiled. Long story short; when you compile your program for dynamic libraries, the program looks for the .dll file whenever it's run instead of integrating the code into itself. If you delete the dll file, the program probably won't run anymore.

Cross-compiler

When you compile source code for a program, it usually compiles for the platform it is compiled on. For example, a program compiled on a Windows computer will effectively be a Windows program. So usually, it is required to have multiple computers/VMs for each platform your targeting. A cross compiler allows you to compile for a different platform than the one that you are currently using.

Transcompiler

A transcompilier or source-to-source compiler converts source code from one language to another. This is useful if you somehow want/need to switch languages for your project without rewriting the code from scratch or if you just want to see how your program would perform if it was written in another language. Some languages are made just to be transcompiled since it is easier to transcompile to another language than to write a compiler or just to make writing a certain language easier. Examples of transcompiled languages include Nim and CoffeeScript which compile to C and JavaScript respectively.

Decompiler and disassembler

A decompiler is a program that takes an already compiled executable and attempts to create source files of the program. A disassembler is basically the same thing but creates assembly files instead hence its name.

Note that a decompiler and a disassembler don't give you the actual source code. It's just a guess on how it is made and the result isn't that human readable. They're useful for reverse engineering programs however.

Debugger

A debugger is a program that is used to test another program for bugs. They can help detect runtime errors, track and change variables, pause the program at anytime, and jump to any point of the programs execution. While debuggers are useful, you can replicate the functions of them by creating debug output in your programs.

Parser

A parser is a program or a library that reads information from one format (usually plain text), and converts it to another format. For example browsers have a JSON parser which turns JSON text into JavaScript objects that can be used by the JavaScript code. All compilers also use a parser system to read the plain text code.
It can also be used to convert information backwards, e.g. from code into text, which can then be saved in a text file.

Interpreted languages

Some code is not compiled, but instead is run through another program called an interpreter which reads the code and either runs it in real time or does something called "just in time compilation", or JIT, i.e. compiling it during runtime before using it. Examples of such languages are Python, Lua, Ruby, and JavaScript. The advantage of this is that the code is much simpler and can run on many different platforms with little to no modifications. The disadvantages are that the program will run slower, the user will need to download and install the interpreter and the code's libraries, and the code can be easily modified.

High/low level languages, scripting languages, and visual scripting

Programming languages come in various levels of abstraction. High level languages simplify programming for you and makes it easier to write programs. Low level languages are typically more faithful to how the computer and data actually works, thus you usually need to be more meticulous and specific with what you do and your code is more prone to errors. Basically; high level languages are easier to use, while low level languages give you more control over the program and data.

Scripting languages are some of the highest level of languages, although it doesn't necessarily differ from a "real" programming language in their function. If a language is classified as a "scripting" language, it can be expected to be among the easiest languages to use. The actual definition of a scripting language is kind of murky though, sometimes the term means "a high level language", but sometimes a language can be referred to as a scripting language due to the context in which the language is used or how it works. For example C# isn't a scripting language, but can be used for "scripting" in some engines and systems.

Games are usually never written entirely from scripting languages but are instead used with compiled code, the main exception to this are HTML5 games made with Javascript. Many game engines like Godot, Unity, and GameMaker have built in scripting languages to make programming easier.

Visual scripting is essentially the highest level of programming languages. Instead of writing code, a visual scripting language allows you to create programs with a graphical user interface, for example by adding boxes and connecting them together and tweaking numbers. These languages are often used by artists and sound designers and other people in the development team whose job does not involve programming. Visual scripting languages are unusual in that sometimes due to their inflexibility they can be better optimized than normal scripting languages, and may offer better performance as a result as long as you don't abuse them. An example of a visual scripting language is Unreal Engine's Blueprints. Multimedia Fusion and Construct are examples of game engines based on visual scripting.

What makes low level languages complicated, and why use them?

High level languages try to make programming simpler for you by hiding all kinds of details behind a curtain so you wouldn't need to concern yourself with them, but that doesn't mean the computer doesn't need to do those things in the end. Having the language secretly do them and try to make things work conveniently comes at a performance cost and may even make certain kinds of optimizations difficult to do since you don't know exactly what's happening behind the scenes nor have control over them. A low level language doesn't do that, and it's up to you to use your data according to your desires, and there's rarely any secret magic that's happening without you knowing.

  • Number types and "casting" - different kinds of numbers need different kinds of data to represent them. For example a "character" is a small number that only ranges from 0 to 255 but is very small in memory size. The biggest common number variable (usually called "long long") can reach up to around 18,400,000,000,000,000,000, but is 8 times bigger than a character, so usually using it is very wasteful. In order to represent negative numbers, you need what is called a "signed" integer. It halves the maximum value of the variable, but in exchange allows it to become negative, for example a signed character ranges from -128 to 127. Representing decimal numbers in data is kind of finicky, so for them you will need a special variable called a "float". In order to convert one type of number to another, you need to do what is called "casting" (although it's often automatic even in low level languages). High level languages often do various tricks to hide these facts from you and pretend than there's only one kind of "number" type, so it's either difficult or impossible to optimize.
  • Dynamic arrays - array is just a straight sequence of values, they can only contain a fixed number of items because the computer needs to reserve memory for all the space when it's created. If you try to add more items after the last item, some other data may be in that position and you will override it. In order to expand the array, you need to either re-allocate memory which may cause all kinds of complications if not handled properly, or use a special system that creates new segments and travels along them. High level languages often treat all arrays as dynamic arrays to avoid these complications, but there's no solution that's as fast as using a fixed array when you can.
  • Strings - a string is an array of characters, but high level languages may act like "string" is a single object that you can modify. A "low level" string may not support characters besides the 127 or so ASCII characters, and you cannot make it longer than you originally defined without reallocating the memory. High level languages often make all strings dynamic arrays and support UTF-8 character encoding (as opposed to ASCII).
  • Memory management - many high level languages have automatic memory management, but low level languages require you to manually reserve space in memory for data and free it when you don't need it anymore. Automatic memory management has a certain performance cost and makes some optimizations impossible, which is why you can't just add it to all languages.
  • Pointers - pointer is a variable that points to some other place in memory. They're required for a lot of different things such as arrays and data of unknown/various types, but high level languages usually avoid pointers or may not even support them at all, and makes things work for you without them. For example in C, a variable cannot contain an array in it, instead you get a pointer to memory where the first item in the array resides, and then access the other items by moving from the pointer's position. Another complication with pointers is when you want to expand memory, for example if you want to make an array larger, you may break any pointers that point into that data since the array now resides in a different location in memory. There's various solutions to that but high level languages may not even let you know that any of it happens.

Markup languages (HTML, XML, etc)

Markup languages are languages designed for organizing documents and information so that a program (e.g. a videogame or a web browser) can read it easier. The document itself is plain text, you can create and edit these files with any text editor including Notepad. The information is usually stored in some kind of associative array after being parsed, and can then be queried by the program at any time.

In game development, markup languages are usually used for storing game data such as level data, in-game text, game options, game saves, etc. The most common markup languages used in games are XML, JSON, and S-expressions. HTML is usually used with JavaScript or WebAssembly for <canvas> games and as an alternative to plain text in documentation and README files.

Although static HTML documents could in theory be used to make a simple text adventure game (by adding links from one document to others), markup languages do not allow for programming per se, thus you cannot make videogames with them alone.

Alternatives to markup languages include binary files, config files, and SQL databases.

JSON

JSON (JavaScript Object Notation) is one of the most popular languages for storing data such as text and numbers and arrays, it is similar to markup languages but technically not considered one, and is often seen as an alternative to XML. Libraries for parsing it exist for most languages and many engines support it by default. It is essentially a JavaScript-style object written as a string. JSON files, like XML files, are plain text, thus you can create one with Notepad if you want to. BSON is JSON but in a binary file instead of a text file.

Formats with similar purpose include YAML and S-expressions.

Binary file

A binary file is a non-executable file that is in binary format rather than in plain text, making it harder for the end-user to modify them externally. This is useful for files that you don't want the end user to easily modify (i.e save files and high scores). Also, reading and writing binary files is much faster than text files. However, binary files are much harder to parse than plain text and you need to keep track of which byte holds which data and you need to learn how to read/write in hexadecimal. A hex editor is a program that allows you to modify binary files externally.

Config file

A config file (or configuration file) is a text file used to store settings for a computer program. Unlike markup languages, config files are solely designed for storing configuration data and are usually only read once during start up. However, markup languages can be used in place of configuration files, and are usually a better option since they can handle more complex data structures like objects, arrays, and dictionaries. Examples of config file formats include Windows INI files, property lists, and Java's .properties format.

Virtual Machine

Some strongly-typed languages such as C# and Java, and most dynamic-typed languages, run on a virtual machine. Rather than rely on your physical hardware, the program runtime creates a memory state that acts as if it were a simple computer, with dedicated sections for memory, processing, etc. The advantage to this is that you only need to write your code once, and if the hardware and OS is compatible with Java, for example, every single Java program can run without an issue. The disadvantage is that your program can take up a lot of memory and will run slower than if it was a native application but not as slow as if it was interpreted. Also, programs that run on virtual machines can be decompiled easier than native applications, but depending on your point of view, this isn't really a problem.

Historically, languages like C and C++ had (and still have) many implementations to guarantee cross-compatibility between platforms. This is why some games can have differences between Windows, Mac, and Linux distributions, because it literally needs to generate a specialized program for each. With modern engines and technologies like virtual machines and HTML5, you don't have to worry about such details; but the advantage of older languages lets you cut away needless features and gives you the most control over how things work.

IDE

An IDE (Integrated Development Environment) is a single tool that contains various functionality to help you write software. It is usually a combination of a text editor, hex editor, file manager, some compilers/interpreters, project templates, versioning control management system, and debugging features. Examples of an IDE are Visual Studio, MonoDevelop, Xcode, and Code::Blocks.

Despite what Microsoft and many other companies want you to think, you almost never need an IDE, they're mostly for convenience. You can pick whatever compiler you want with whatever text editor you want with whatever other tools you want, you could write all your games using nothing but Notepad and your language's compiler/interpreter if you wanted to. Though note that some IDEs have unique tools that you cannot get out of it, for example, Visual Studio has some of the best debugging tools period, so if you want to use them you need to deal with Visual Studio.

Open source and Free software

Main article: FOSS

Programs which make their source code available are open source and are usually freely shared and/or modified. However, depending on the project/library, some licensing terms can restrict what you can do for it (eg, some may give you source code for personal or education purposes, while others allow you to make modifications for commercial purposes, as long as you reserve the right for others to make the same use of your code).

For large projects, the source code is common stored in a git repository (eg, GitHub), which is a kind of versioning control management system. These let you publish and branch codebases, and rollback changes. Most people here probably won't need to worry about this, but they can make for a good backup of your project.

Note that "open source" is not the same as "free/libre software". While open source software may have it's source code available, you may or may not have certain freedoms that the definition of "free/libre software" entails. Open source is often used interchangeably with free software however.

Memory management / garbage collection

Every time you create a variable or load an asset, your computer has to reserve memory for it, and when it's no longer needed it needs to be "freed" so it stops reserving memory. Some languages such as C# and Java do this for you, these are called "garbage collected" languages. Other languages like C and C++ have manual memory management, which means it is up to you to allocate memory for your data and free it when you're done with it.

There are two places where data (variables) are stored in; the stack, and the heap. When you create a variable, it usually goes into the stack automatically, and gets deleted when the function runs to the end. This process is automatic and you do not need to manage it yourself even in most low-level languages like C. However any data that you want to access throughout the game, such as game state, map tiles, player data, etc. must be stored manually in the heap. The heap is controlled by you, and if you keep allocating more data into it without deleting old unused information, it'll keep growing and growing with useless data, this is called a memory leak. Memory leaks are very easy mistakes to make and sometimes hard to track, if you allocate memory and then overwrite or delete the pointer that points to it, the data becomes inaccessible and the memory will be stuck in the void until the program is closed.

The advantage of garbage collection is that it is easier to develop software since you do not need to think about keeping track of your data, but the downside is that it has a "significant" performance penalty. This performance penalty is not meaningful or even noticeable in most cases due to the speed of modern hardware, but it is something to consider if you need very high performance, are making something mechanically complex, or are targeting older/weaker hardware.

Programming paradigms

Programming paradigms are used to categorize languages based on their features and programming style. Some programming languages only allow one paradigm (like C), while other allow multiple paradigms (like Python). Here is a list of commonly used paradigms and their description:

Unstructured programming is the earliest programming paradigm. As the name suggests, the code isn't structured into functions, structs, or objects but is instead one continuous block of code. Jumping to certain parts of code has to be done manually via GOTO statements. The advantage of unstructured programming is that you have a lot more control over your program, but complex projects end up as "spaghetti code". Examples of unstructured languages include Assembly, Fortran, Batch, and many earlier dialects of BASIC.
Procedural programming groups individual code into functions and subroutines which can be accessed at any time during execution. These functions can be reused in other programs through code libraries and modules. Before the rise of object-oriented programming in the late 90s and early 2000s this was the most common programming paradigm for game development. Examples of procedural languages include C, Fortran, Pascal, and Go.
Object-oriented programming groups code and data into self contained objects. These objects can have built in functions called methods which can modify the data of said object or other objects. Objects are grouped into classes which determine the type of object and what properties and methods the object has. This is currently the most popular paradigm for game development because it makes it easier to organize your game's code. However, objects take up more memory and resources. Examples of object-oriented languages include C++, C#, Java, Python, and more recent dialects of BASIC.
Functional programming is similar to procedural programming in that you write your code into functions but the functions in functional programming always return the same value for a given input. Much like traditional mathematical functions. Currently, this paradigm is not commonly seen in games, but many functional programming languages have bindings for frameworks like SDL. Examples of functional languages include Haskell, F#, and many dialects of LISP.

Data-oriented design/programming

Data-oriented design is a programming style where you care and pay attention to the actual data and memory that you're interacting with, and try to design the program according to that. You have some data, and you operate on it to get a desired result. The opposite is to think of your data as abstract objects and things, such as "enemy" and "sprite" that have various methods and functionalities to them, with little regard for what kind of data they consist of and how they're organized or accessed in memory.

Computer processors are insanely fast, but memory is not, which is why it is highly beneficial to organize your data in such a way that the program can access and operate on it easily. The primary methods are to separate data that's accessed often from data that isn't, and laying data into contiguous lists (as opposed to using pointers to point to random parts of the memory). Memory is a huge bottleneck whose speed is limited by actual real world physics and the physical distance from RAM to the CPU. The CPU has it's own small memory and can load chunks of data into itself (e.g. multiple variables from an array at once), but it cannot do that properly if the data is spread all over the RAM.

Errors

Compilation errors occur when you try to change your written code into machine code. This could be as simple as a syntax error (eg, you wrote "conts" instead of "const"), or something more complex that the compiler detected as wrong (such as using an undeclared variable).

Run-time errors happen when the program is executing. The most common ones are "index out of bounds" errors when working with arrays, and "null reference" exceptions, when you try to access a value that belongs to a null object, which is an impossible state. Like compilation errors, almost every language will tell you when something is wrong.

Logical errors are the most devious, and cannot be detected by the computer. These occur when your game behaves in unexpected ways, and can be difficult to track down since the game has no idea of knowing what you actually wanted to happen - but as far as its concerned, the game is in a correct state. These occur less often with experience, but a common occurrence among new programmers is to mess up conditional logic, perhaps putting ">=" instead of ">" or getting the sign backwards, and spending several hours tracking down the error. It happens!

Tips

Help! I'm worried about performance!

The Indian approach to performance

If you are just starting to build an engine or are in a very early stage of your game, chances are that you are being paranoid and suffering from ye old premature optimization. The purpose of programming is to provide the developer with the tools and interface to achieve a written piece of software in a human-to-computer-comprehensive manner. If you worry about performance without even measuring the gains, you would not only be prolonging your development time, but also be misusing the interface and tools on code that does need to be profiled. In some cases, you may even cause worse performance refactoring code on a whim. As a result, a good game programmer should strive to develop an application as neatly and swiftly as his/her skill allows. Some tips include writing, planning, and designing beforehand and making use of the engine's prototyping tools. Remember: Do not give in to your optimization itch.

B-but I like doing it the slow way!

Good for you. You will be a great programmer. But your game will age faster than the code it runs on.

Random 2D Vectors:

gamedev%20random%20vector2.jpg

See also

Articles

Related articles

Helpful links

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License