Much ado about Customize

Battlefield means soldier customization. Battlefield 4 specifically allows you to customize your loadout (or kit), your weapon accessories, and your vehicle. For reasons best called historical, the whole system was and still is extremely complex and filled with technical debt. Which is where I come in.

A large part of my work on Battlefield 4 ended up being that system, because it needed a quasi-full rewrite of the UI layer. The initial goal was to reduce technical debt and make it more data-driven, it ended up allowing us to convert it to the in-house C++ UI framework rather than using Scaleform. But this is not what we'll talk about today. No, we'll talk about funny bugs.

Quite early on, one day, we fire up the game for a quick review. And we're greeted by the soldier having a glowing light orb over his head. After a good ten minutes laughing out loud and catching a quality video capture, we start looking for an explanation. It eventually turned out to be a temporary underwater indicator. "Wait", you say, "this still makes no sense". It actually does! And the same root cause led to the screen being blurry and filled with fishes another time, but tragically I do not have a screenshot of that particular hilarious bug.

See, the Customize backdrop is a standard 3D set, built in the level editor. But it needs to exist on the level to be loaded at the same time, while being out of sight from the main events, of course. Can you see where this is going? Yes, the Customize backdrop is under the level! Which technically means it's under the water level, which was triggering underwater effects like the blinker and the fishes. The fix was to add an exclusion volume, which was luckily supported in the engine.

Another time, during a regular playtest, angry emails start coming in. "How am I supposed to fly my plane with a tank floating in front of me??!" Laughs, video capture, and search for an explanation. Luckily I had just been poking at the 3D vehicle display in Customize, so that ridiculous tank sure looked familiar. It wasn't a case of broken physics, as has happened before in Battlefield, because the tank was always in a set position in front of the player's camera. Which is exactly how the Customize vehicle was positioned.

So what was going on? The Customize vehicle is a normal game entity, spawned through the same code as anything else in the game. Which is why the flying tank had physics and could be shot down. It just needs to... not... be replicated on the server. Woops.

It turns out that two lines of code had been inverted. The first line spawned the vehicle into the world. The second line told the vehicle to stay on the client, and not be sent to the server for replication. The correct order was the opposite one, since the spawning also caused replication if the option hadn't been set. And that is how stateful code will get you every time.

A fun side effect of the bug was that you could stack Customize vehicles from several clients. And so the tankcopter was born!

Those were hands-down my best bugs during Battlefield 4's development. Not the hardest to fix or the most epic hunt for a culprit, but definitely the most amusing ones. The Battlefield 4 UX team was a pleasure to be a part of, and I'm proud of what we delivered. I couldn't have wished for a better first game job.

Ludum Dare 34 Post-Mortem

(Cross-posted from the Ludum Dare blog)

Hi! @LiaSae here. For background’s sake, I’m a AAA game coder currently taking a break to fix her brain. LD34 was the perfect chance to make something, feel good about it and fall in love with game-making again.

My game’s called Thunder On, and was made in 48h (~16h of work) even though it’s a Jam entry. I initially wanted to call it Thunder Down, but… Well, you google that and tell me what you find. Possibly not at work.

Thunder On: gameplay view

Gameplay view. It’s THAT kind of game.

The idea had been bouncing through my head for a good while now: “being” a lightning bolt, going down, losing energy as you go and having to create new branches, to see the final result once you touch ground. The LD themes gave me the constraints I needed to make a workable implementation.

WARNING: Coder lingo ahead. Artists beware, though I’ll try to have some snippets for you as well.

What went wrong

1: “WTF is going on?”

This was the general reaction from the bulk of the players (thanks all for your feedback, it’s very valuable!). I purposefully left the initial instructions vague, because I was going for whimsy / eerie. But combined with the lack of altitude indication of any sort, this means that what is obvious to me – “well of course the camera’s looking down and you’re going down, it’s like that in the Scene view!” – is cryptic to players.

2: Check the compo rules beforehand next time

I was aiming for a compo entry, but had forgotten even sounds had to be made from scratch. As I checked when getting ready to upload my entry, I facepalmed hard and ticked the Jam box instead. On the bright side, that means it sounds decent instead of terrible.

3: Unity 5.3

I don’t know what on earth was going on with viewport rendering, but a quarter of it routinely turned black for no apparent reason. Getting my alpha blended shader for the cloud layer to work was a matter of one hour of copy-pasting and tweaking the built-in shader to get a version that didn’t break. I can’t say I’m not used to randomly breaking tools, but generally that has been because I’m on a dev branch! I should have stayed on 5.2 for the jam and upgraded afterwards.

4: Responsiveness

I went with a coroutine-based easing animation for the movement, but that also meant blocking inputs until the easing is done. Unfortunately the end of it is virtually infinite, so I added a cutoff. But it was not tweaked well enough, and the game feels frustrating as a result, because you expect to be able to provide new input earlier that you’re allowed to.

5: Too easy

No time means little tweaking, randomness means impredictability, and as a result it’s way too easy to reach the ground. It would not be hard to add a system that analyses possible paths to decide how far up you should go for the best difficulty, but it would take time!

What went right

1: Hell yeah, I made a thing

It’s finished. It works. It feels and sounds and looks better (suppress banding rant) than anything I’ve ever made by myself. It’s complete, people like it overall, they get the point, and that makes it an excellent proof of concept for that idea. I’m happy and proud, and this does wonders for Broken Brain.

2: No crunch!

I live in Sweden, and that meant waiting until 3AM for the themes to be announced. Then to bed, let my brain work it, takes notes, sleep. The next day we had to go borrow the car, buy moving boxes for my partner’s family, drive to IKEA, survive IKEA, come back (this is all very Swedish). Then I had to go buy yarn Because Reasons, head off to an exhibit, go back home, head off again to dump some stuff, then drop off the car. THEN I was able to start on the game, at 5PM past. Between breaks and meals, I put in about 8h that day. The next day I had to go have lunch with a friend leaving the country, run an errand halfway across town, come back, which once again meant starting work at 5PM. Again I put in about 8h total, completing the last tweak to the feel of it all at 2:58AM and doing the submission afterwards. All of this to say: the week-end was packed, which forced me to put in normal work hours instead of Jam Crunch Hours, and I still made it. If life gets in the way, just slash scope massively.

3: Procedural techniques

The bolt is a binary tree (made simple by the two button controls). From there, I generate a mesh that represents the final bolt. The clouds are based on Simplex Value noise from an excellent tutorial at CatLikeCoding. This all adds up to something that feels more complicated and rich than it really is, and was fun to code.

4: Infrastructure

I typically use Assembla for projects like this. The repos have a size limit IIRC, but otherwise they’re free and you can create tons of them. So I created a SVN repo and off I went. Then I made sure to commit quite often, keep things running at all times, and added debug draw as early as I could. It helped immensely, because I didn’t have to guess whether things worked: I could just test, at all times.

Thunder On: scene view

The scene view with the debug tree.

5: Coroutines

I had never used coroutines. On related news, I positively hated gameplay and procedural animation programming for its heavy reliance on a crapton of flags. I don’t know how well coroutines-based systems will scale to bigger projects, but for this it was an absolute delight to chain per-frame callbacks instead of keeping track of all that state. It taught me a new way to think and that makes me immensely happy.

Conclusion

I’m happy with it, as I’ve mentioned. It’s far from perfect, but it was never going to be, and I had to finish, package and ship it off. It looks good because I went with something simple and cheap with glow. I learned stuff. I’m getting excellent feedback, and pondering whether to bring this further eventually. I’m taking the time to play and rate some games this time around too, and discovering a lot of fun things. So long live the Ludum Dare, and congratulations to everyone who made a thing, or tried to make a thing. It’s worth it.

Thunder On: final view

Making lightning bolts is fun!

C++ GUI (or how to lose precious hours)

As stated previously, I'm working on a terrain generator with the SFML (more details on that later). But now that the core thingie is running, I'd like to add a GUI to tweak the parameters.

Foolish me. I had no idea what I was getting into.

So. I know we're going to delve into Qt later this year, so I wanted to use Qt. But building under VC2010 sounded like a pain in the - er - back, so I looked elsewhere.

wxWidgets looked rather nice. Bummer, no VC2010 version. But wait, wxPack is a compiled version, with VC2010 compatibility! Well, uh, not quite. It doesn't integrate so linking is really painful, specifying every library by hand with no data on the required ones (and trial and error is really annoying beyond 20 libs). Integration works with the 2008 version though. Which is (completely objectively) less pretty and comfortable, and doesn't highlight matching braces on reading. Using wxWidgets also involves really ugly-looking macros absolutely everywhere. And I dislike having 400 warnings coming from the libs during linking.

Back to Qt then, using QtCreator? I guess. Except no. The installer seems to have messed up and not installed project files. And the package manager refuses to find some component's metadata. So on I go to download the offline version.

Meanwhile (1.4GB takes quite a while to download), I look around for alternatives. I had heard about GTK+ but forgot to investigate. Saw a C++ wrapper called gtkmm. Download. Install. Add properties sheets for VC2010, included in installer. Write some example code. Build. Run. One small warning. Running smoothly. And one small but lovely detail: a "Side Effects" section in the installer, stating the modified environment variables. That's too rare.

Qt wasn't even done downloading.

So I guess I'll stick with gtkmm. No ugly macros, easy install, multiplatform. What more to ask for?

(Edit / Spoiler: easy GL context creation? One cannot have it all... We'll see how it ends.)