Abstract
Problem: How do C, C++, and C# compare for game development, and which should developers choose?
Approach: Tim Cain draws on 40+ years of professional game development β from Atari 800 BASIC through Fallout (C), Vampire: Bloodlines (C++), and Pillars of Eternity (C#/Unity) β to compare the three languages in practice.
Findings: C offered the best optimization and closest-to-metal control through the 1990s; C++ eventually caught up and now dominates with powerful (but easily abused) features; C# is the easiest to learn but suffered from poor performance and encouraged bad patterns in Unity.
Key insight: C++ is Tim's top pick today for its mature optimization and power, but disciplined use is critical β operator overloading and deep inheritance are the most common sources of unmaintainable code.
Tim's Programming Journey
Tim started with BASIC on the Atari 800, moved to assembly to understand how games worked, then learned Pascal in high school β his first compiled language. The jump from interpreted BASIC to compiled Pascal was eye-opening: dramatically faster execution and real debugging with breakpoints. At the University of Virginia he studied many languages (Snowball, Lisp, Ada) but C became his professional workhorse starting in 1983 with Grand Slam Bridge at Cybron.
The C Era: Grand Slam Bridge Through Arcanum
C powered all of Tim's games from Grand Slam Bridge through Bard's Tale Construction Set, Rags to Riches, Fallout, Arcanum, and Temple of Elemental Evil. He valued C for several reasons:
- Optimization worked better on C than C++ throughout the 1990s β smaller executables, faster code
- Close to the metal β direct memory manipulation, data layout control
- One-to-one mapping to assembly β you could inspect the compiler output and confirm it matched what you'd write by hand
When shopping Arcanum to publishers, one potential publisher called him "an idiot" for not using C++. Tim's response: he'd benchmarked both, and C consistently produced smaller, faster executables with fewer optimization bugs.
The C++ Transition: Bloodlines and Beyond
Vampire: The Masquerade β Bloodlines forced the switch to C++ because Valve's Source engine required it. Tim was "pleasantly surprised" that C++ optimization had improved, though compiler bugs persisted even into the 2000s β optimization flags would produce incorrect code (unrolled loops, bad jumps).
A Shocking Discovery
Tim was stunned to find professional programmers in the 2010s who didn't know how to diagnose optimization bugs. Instead of inspecting the generated assembly, they'd either toggle optimization flags one by one or use #pragma directives to disable optimization in problem areas β never understanding the root cause.
The Pitfalls of C++ Features
Tim sees C++ as "C with classes" at its best, but two features cause the most damage when abused:
- Operator overloading β redefining
+or other operators for custom classes makes code look like it does one thing while actually doing another - Deep inheritance β method calls appear straightforward but may invoke completely different behavior in subclasses, making debugging a nightmare
Six months after writing "clever" C++ code, even the original authors couldn't explain what their own code did.
The STL Debate at Carbine
During WildStar development at Carbine Studios, two programmers Tim respected argued over the Standard Template Library (STL). One argued they were wasting time reimplementing data structures; the other pointed out that many STL implementations shipped without source code, making debugging nearly impossible. The compromise: they found a plain-vanilla STL with source code and made it available.
The C# Detour: Unity and Its Problems
For Pillars of Eternity and Tyranny, Obsidian used Unity, which meant C#. Tim found it:
- Easiest to learn of the three languages
- Convenient for tools and UI β he experimented with C# tooling during WildStar
- An order of magnitude slower β in benchmarks around 2005β2006, identical image-processing code (convolution matrices for sharpen, blur, edge detect) took 30 seconds in C# versus 1 second in C or C++
Unity's event-driven architecture was also widely misused. Developers crammed logic into Update() instead of listening for events β keeping lists of old status effects and checking for changes every tick instead of subscribing to event callbacks. This compounded C#'s already poor performance.
Tim's Rankings Today
- C++ β "super powerful," mature compilers, great optimization. Easy to abuse, but disciplined use produces excellent results
- C β very close second. Familiar, close to the metal, reliable compilers (though possibly plateauing in improvement)
- C# β third, but "by far the easiest to learn." Recommended as a starting point with Unity, with the advice to eventually move to C++
His recommendation for new developers: start with C# and Unity to learn the fundamentals, then transition to C++ β which matches both his experience and current industry practice.
References
- Tim Cain. YouTube video. https://www.youtube.com/watch?v=wTjm-e0eZ8E