Starting with state management in the first post is a different approach I wouldn't normally expect.
That being said I don't know what it is but I prefer writing games in C. I experiment with higher level languages and use them for rapid prototyping. However, and maybe its simply nostalgia, I always come back to C.
And it's not even my favorite language by a long shot. For practically everything else, save for systems programming, I prefer languages like Common Lisp and (more recently) Haskell. Imperative programs are notoriously difficult to comprehend and maintain but there is something about game programming specifically that C leverages which makes it a good fit for game engine development; the mix of pointers and machine-sized types perhaps? I'm not sure. But it works really well.
I remember writing a blog post years ago about how I enjoyed C and Clojure, apparently two extremes, equally.
My current conclusion is that we just enjoy problem solving within mental frameworks, and each language family gives unique mental frameworks that come with different challenges.
Now that I've slowed down life and am planning in years instead of weeks, I think I would absolutely enjoy (and I think my kids would too) making a new video game from scratch with SDL in C.
The only difficulty is, every time I try this, I keep running into weird issues that only I seem to be having and can't find a solution to online. For example, the last time I tried making a lemmings style game in C with SDL, I ran into weird framerate issues where for apparently no reason or pattern, it would go incredibly slow sometimes.
C gives you all control over your machine, there are no obscure libraries, grabage collector or unexpected stuff, if something doesn't work as expected you know you have fcked it up.
I'm using C here cause 1st, i like it a lot, and 2nd, i think it's the clearest language out there, you can follow the code execution from start to end and "almost" know what's happening, it doesn't have function overloading, obscure scopes, garbage collectors or automatic weird typing.
HN users tend to parrot the safety line a lot because most people are working on web applications that store somewhat important user data, so gaining access to a remote machine due to a buffer overrun issue is catastrophic, but in games, especially in single player games, safety is less of an issue or even a non-issue. With a multiplayer networked game, cheating, attacks on servers and attacks on other players clients are a concern, but in a game that is entirely or mostly single player the worst outcome of unsafe code is that it crashes to desktop.
Ignoring the almost barbaric lack of abstraction in C, you could avoid a whole load of these bugs and make your customers not want your head on a spike at next to no cost by using a different language.
Nobody's complaining about the barbaric OS and network stack written in C. The safety nazis' bleating means little if they can't produce a viable alternative. Where are the high performance OSs written in Ada or whatever next big thing is?
What? Operating systems are big projects and the tools to write them safely (and open source) haven't existed for very long, so it's a question of manpower and effort not technology. C has almost no performance benefits these days, either, due to advances in compiler optimization; if anything it can be less as other languages can provide more static guarantees to the compiler to use when optimising.
That network stack written in C gave us heartbleed for example. If C arrays were bounds checked by default (e.g. they carry around their size), this could've been easily avoided at no runtime cost.
How can you honestly complain about people wanting more safety in software? If it's speed ("high performance") then you're probably implementing yourself in C (e.g. Bounds checking) something that is built in either at runtime or even statically as can be done in some cases.
What do you propose? Replacing the system stack with Ada?
Modern successors to C, such as Zig, and modern successors to C++, such as Rust, are still too young to be used for serious re-implementations of the lower layers.
true, i'd never do a C89 game from scratch as a profesional project, but this is not a profesional project, it's more like a hobby-academic approach to the lower level of game engine design :D
Indirection, pointer casting, and the C standard library actually make things quite opaque in practice. Do you sbrk your own memory or use malloc? Malloc may not be as mysterious as GC, but it’s still a runtime-managed resource.
You can replace malloc with your own implementation. Just have a big static array to dole out bits of memory. The loader or startup code will prep it for you.
I have some recent experience with doing game programming in C and while I think the experience was overall positive, I'm not sure that I would do it again unless my aim was portability.
I found that when my project grew to a certain size, I started running into many cases where I needed many implementations of some base type, the kind of pattern that lends itself well to classes and simple inheritance. This pattern is totally 100% possible to roll yourself in C, but requires a bunch of boilerplate each time and I found that every time the implementation came out slightly differently, or that I had to go back and rewrite a bunch of code because I needed one more layer of flexibility than I anticipated.
I also really wish templates were in the language. Maybe not to the C++ level of flexibility, but at some point, you're going to need a dynamically allocating array or hashmap of a specific type, and your choices are either going to be *void or some macro thing that makes your eyes cross.
Also, build tools in 2019 are still kind of bad. I use CMake and try to do things "the right way", and I still run into trouble occasionally, mostly surrounding external dependencies and generation of files outside the scope of the C compiler. It's a shavable yak, but it's still a yak.
Still, the lack of mental overhead and the much faster compilation times compare favorably to C++. But if portability wasn't a goal, I'd seriously consider an alternative like D, Zig, or Nim next time.
>I needed many implementations of some base type, the kind of pattern that lends itself well to classes and simple inheritance.
Inheritance is an anti-pattern, you can accomplish the same with composition.
>you're going to need a dynamically allocating array or hashmap of a specific type, and your choices are either going to be void or some macro thing that makes your eyes cross.
I don't understand, why would you need a *void for a specific type? If you meant heterogeneous types, you can use a typedef union.
In all my gamedev I've found that the best structure was how Lua does meta-tables.
You can then use that simple mechanism to implement inheritance, component based design, message passing or whatever structure makes the most sense for your game design. I'm personally tend to lean towards component based for reusability and performance but that's by no means a hard-and-fast rule.
interesting, i'd suggest you to follow the blog, iv'e already implemented something like a dynamic array in the first post and will have to implement some other "modern" things in the near future, it's awesome what you can do in C89
I'm not really a fan of C for games just due to exploding complexity the moment game logic enters the picture. While the language is fairly clean, I find that it gets messy really quickly once the number of structs and functions starts to take off, and then I end up flipping things over to a reduced set of C++ features.
That being said I don't know what it is but I prefer writing games in C. I experiment with higher level languages and use them for rapid prototyping. However, and maybe its simply nostalgia, I always come back to C.
And it's not even my favorite language by a long shot. For practically everything else, save for systems programming, I prefer languages like Common Lisp and (more recently) Haskell. Imperative programs are notoriously difficult to comprehend and maintain but there is something about game programming specifically that C leverages which makes it a good fit for game engine development; the mix of pointers and machine-sized types perhaps? I'm not sure. But it works really well.