Bird Game

I've wanted to do a game jam for a while. The last time I did one was in person about 10 years ago with a group of friends from Uni. We made several small games over the course of a weekend. One of them was Gnome Patrol. It was basically Plants vs Zombies but the gnomes replaced the plants. It was also set in Alan Titchmarsh's garden because he hates games so he'd really hate this.

Another was Duck Nukem. Nothing was really playable - it was more the pun, and the Photoshops that came with it. I cannot remember the other games we spent hours making, but I do remember the 5 minutes I was on the train with a couple in their 40s going through a marital crisis. I hope Sharon and Tony sorted things out.

I've browsed itch.io a few times to see what game jams were ongoing, and picked a few I wanted to do. And then I never had the time to do them. A few weeks ago I saw one where the theme was birds and the challenge was 'always moving'. I came up with an idea pretty quickly, but then I read the rules and realised I would instantly be disqualified because 'keep it clean' means I can't submit a game about a bird pooping.

Warning: This is a bit of a long one.

Bird Game, as I called it, was quite simple - there would be a street with people constantly on the move and targeting them would drop some bird poo on them. You'd get a different amount of points if you hit their shoulder, or their head, and some would be carrying a cup of coffee. Not a lot going on, but perfect for a game jam.

But what if the bird was on the move? And it wasn't just about pooping, but you could swipe food to facilitate the poop? The bird would be on the move, and the little town below would be too. People going out to buy chips, coffee and ice cream during the day. And then I got really caught up with the idea of adding night time so the bird could poo on people outside a nightclub.

Then I didn't make it because I was busy for at least half the time I could have spent working on it. Except now, instead of a weekend, I had all the time I wanted, especially since I wasn't sure about whether the football game was going ahead. So I gave myself a week.

One week for core mechanics, art, sounds, testing, and then a little bit of polish. For the scope of the game, that seemed reasonable to me. The only thing I was a little bit concerned about was building the world. I wasn't going to use Unity. Instead I was going to use MonoGame, which still uses C# for the code, but does not provide anywhere near the amount of things that Unity does, because it's a framework instead of an engine. One of the things that MonoGame does not have is a level editor. So I'd have to figure out how to put everything together.

I came up with a plan on how to tackle the key parts of the game and stuck it on a whiteboard. Just like the plan for the football game, I'd completely forgotten AI. And despite worrying about how I was going to build the world, I also completely forgot about that.

The plan for Bird Game.

On the Sunday, I moved one of my monitors and an old PC into my living room. Once the Amazon delivery man handed me an ethernet cable, I connected the PC to the internet. And I'm pretty glad I did this on the Sunday and not the Monday because it turns out that not being connected to the internet in 3 years means that Windows will max disk usage up to 100% in order to download all of the updates, and bottleneck anything else you try and do. Updating started at around 4pm and, according to the logs, was ready to finish at 3am.

On Monday, I created the GitHub repo and then tried to clone it to my PC. Visual Studio complained about invalid credentials, which was fair since my password is not what it was 3 years ago. But it didn't point me in the direction to change them. How I managed to change them was - what became indicative of the next hour - not very intuitive. Instead of a button called Update Credentials, I had to go into the Git Changes window, click to create a new project and then click on an option that said GitHub. This opened GitHub in the browser, and jumping back into Visual Studio revealed this had somehow updated my credentials. No asking for my username or password. Just a button hidden in an option that made no sense for what I was trying to do.

I knew going in that it was not possible to create MonoGame projects in Visual Studio 2022, and instead you have to put a command in the command line. Except when I did, it told me that MonoGame didn't exist. I used a search command which revealed that it did know what it was, and then when I tried to install it, it told me I was making it up. As it turns out, NuGet had declared a folder on my machine as the foundation of its knowledge, except when using the search command when it was quite happy to browse the internet. Finding an option hidden away in a menu and forcing it to look at the internet for everything fixed it.

Once I had managed to create a project, it was complaining that it didn't know about the packages that it had literally just installed. Manually removing them and readding them fixed it, but it would do the exact same thing when closing and reopening Visual Studio. At this point I was an hour in and I'd written no code because I was faffing around with stupid command lines for things that used to be exposed with a UI that handled everything for you.

Then I wrote some code and hit the ground running. In the next hour, I'd smashed the first two parts of the plan for Monday, so I decided to test that input was working. MonoGame's Content builder wasn't building, which blocked building the entire project, so I had to faff around with more command lines to get the UI for that installed just so I could add a file to it to see if all it needed was a file to build with. But that still didn't work and, hidden away in some output log that it decides it isn't going to show you by default, it was because I didn't have an older version of .NET installed.

Once installed, I was off again. At the start of Monday I was worried that I would not force myself to finish at 4pm, but by 2pm I had got everything I had planned finished. With the remaining time, I added a score screen for the end of the game, and a title card. Not a title screen, as the the title is overlaid onto the world and disappears as the game starts. It makes it seem fancy.

On Tuesday, I decided I was going to try and tackle the AI. I had no intention of doing proper pathfinding with collision - this was going to be a simple list of nodes that characters can walk between. Although it scared me, so I went and worked on scoring, diving, pooping and implementing sound effects first.

A demonstration of how nodes work.

I'd popped on the soundtracks for all 3 High School Musical films so had to wait for those to finish before I could find some sound effects. I was tempted to skip the Gabriella ballads as they came on, but Gotta Go My Own Way hit differently than it usually does. That's not even me trying to do a joke about me going my own way to make games; I genuinely thought it was good. Unlike the song from the Lizzie McGuire movie. Hilary Duff's voice is all over the place. Yeah, I ended up falling down a Disney musical rabbit hole.

After checking a few sounds, I came across a bit of ambience that would fit in perfectly so I downloaded it, didn't even edit it because it was perfect the way it was, stuck it in the game and then the game wouldn't build. The bitrate on the audio file was twice the allowed size. After editing it and sticking it back in the game, I now had audio. But still no AI.

I continued ignoring the world building and AI for the rest of Tuesday to implement a camera and sort out the UI screens. The code for the options menu became wildly inconsistent with the rest of the code by creating inline methods to pass through to other classes, in part because that's how I've come to prefer doing menus, and also part of the wild panic of wanting to get it done by the end of the day.

I had also hoped to include an option to expose a file containing all the game's strings to allow players to create files for other languages and then have the game detect language files and allow them to be loaded from the menu. But I decided to drop it because I knew I'd end up putting more important things off to work on a feature that would almost never get used. A bit like cooking curries in Pokémon Sword and Shield. Never touched that, never will.

Towards the end of Tuesday, I had made the pooping animation so wanted a sound to go with it. Usually only the most disgusting fart noises get a reaction from me, but, despite not even searching for fart - squish, squelch, splash - almost every single one of the sounds that I came across was revolting.

At the start of Wednesday, I created the diving animation and decided to reduce the size of the sprite sheet from 512x512 to 256x256 because there was a lot of empty space. And that seemed to cause a disaster. The diving animation was working in game, as was the idle / flying animation. But the bird disappeared when it should have been pooping. This didn't make any sense - the animation was still there in exactly the same position on the sprite sheet, and why would reducing the size of the file have only broken that and nothing else?

I bumped the file back up to 512x512 but the bird was still disappearing. This was now even more confusing, because technically all I had done was colour in some more pixels on the image. There's no way that could be causing this. And then I had a bit of a panic. If I ended up spending hours trying to fix this weird bug, the game wouldn't get finished. I put breakpoints in the code - the sprite was using the right texture, and had the right number of frames. It was trying to draw the correct sprite when it should have done. And then, in the game, I saw the bird appear on the left side of the screen for a frame before it began flying in the middle again.

While adding the code to make sure the diving sprites were at the correct positions, I had accidentally deleted the code which did the same for the pooping sprite. The bird was pooping. It just wasn't doing it where it should have done.

After that, it was time to build the world. I had initially done a few basic tiles to denote what was grass, road, building, sand and ocean and was going to tell the code where to position them so it could draw them. But I needed a visual aid to lay the tiles out and then decided it would be easier to just have one image with a town in it and draw that once each frame, instead of creating a file with a list of positions and having the code make hundreds of draw calls each frame to put each tile at those positions.

The first version of the world.

I had to keep the bird inside the confines of the world, so forced it to turn around when it went outside the boundaries. And then it kept turning. I attempted a couple of fixes which improved things slightly, but it was still possible. It functioned sometimes though, so left it for Thursday as part of bug fixing.

With the map in place, I could setup some nodes to finally implement the AI. So I setup the nodes and then, in yet another effort to put off the AI, I decided I was going to change how the death state would trigger. Previously I'd planned for it to happen when diving down and getting hit by a car. But the player might never dive down, and, even if they did, they could time it to avoid getting hit. So I decided that the people in town would get fed up and send drones after the bird.

That meant creating a new sprite, sourcing sound effects, implementing them, wondering where the drone was even though its sounds were playing (they only play when it is on screen), realising I wasn't setting the drone's position, and then getting the drone to follow the bird.

Then it was Thursday. According to my original plan, testing and polish. Sure I could polish the animations up a little bit, and make the town look nicer (although that was supposed to be Wednesday's task), but I also still had to implement the AI, make the drone kill the bird and trigger the score screen, and actually spawn the poop.

I'd largely let myself roam free with what I did - writing a list of things I wanted to get done at the start of the day, and working through them in any order. But now I had to micromanage myself, writing what needs to be done in each hour and trying to make sure that got done. First up was getting the drone to kill the bird and triggering the score screen. I got that done with a little time to spare.

Second on my list was the AI. So I did what I'd been doing all week and just moved on to task 3 which was spawning the poop. Then the poop spawned and I was left with no choice but to do the AI. By lunchtime the best I had achieved was getting characters to spawn at random positions and have them move to another node. But they always moved to the same node, instead of picking between the two that were available to them - since I'd set it up so it was a circuit.

At lunchtime I went shopping and was thinking what to do if the game wasn't done. I could easily lose another few hours to this, and I still had to sort out changing the resolution since it didn't scale properly, and wanted to go back over the art to improve it. My new plan - give myself a couple of extra days to show how important polish and bug fixing time is. Except this wasn't either of those - it was implementing stuff that wasn't finished.

Then 20 minutes after getting back, I had characters moving around. About an hour later, all the core mechanics were done. There were bugs - characters were acutally moving backwards but the resolution was so small it took me a while to notice, if there was more than one drone then it was possible that they would end up occupying the same position by slowly merging into the same flight path. And then I was out of time.

While I had planned to do some bits on Friday, this went against my Monday-Thursday rule. I'd been good at sticking to the 7 hours, and I still can't believe I willingly walked away from a computer to get on a treadmill several times, so I didn't want to break any rules.

I couldn't do the full day on Friday anyway - I would only have been able to do the morning. But as I turned the PC off on Thursday, it decided to do Windows updates which could potentially mean it would take forever to load on the Friday morning as I created the build. I put the code on my other machine on Thursday night to play with it and see what I wasn't happy with and whether it would be an easy thing to fix. And that's where I noticed that I'd somehow broken drones as they were no longer spawning.

I spent a couple of hours on Thursday night fixing a few bugs and making some improvements to the art. It wasn't perfect, but I never aimed for it to be. It was playable from start to finish, and that's what mattered. Although I still needed to boot up the main development PC on Friday to create a build, since my other PC was missing a font.

Finally, I needed a proper name. I wanted some kind of pun, since the game has a few of those in - Mini Pooper for hitting a car and Crapuccino for adding some extra flavour to coffee. But I couldn't think of anything, and I'd grown to like Bird Game, presumably because it reminded me of an older project I started called Space Game where that was the actual title.

Then it was done. After getting some screenshots, pumping out a release build and uploading them both to the internet, Bird Game was finished. Or as finished as it was going to be in the time I had. I could easily spend another couple of days fixing bugs and improving the art. And the idea of picking up food in order to poo was dropped, so that could be added. As well as the nightclub thing.

And then on Saturday morning a friend played it and found a bug that prevented the game from being replayed after you get killed. It was going to have to wait until Monday, but I then spent Saturday commenting all the code anyway because that was much more enjoyable than trying to catch the weather genies in Pokémon Legends Arceus. And I wanted to start something new on Monday, so I might as well get Bird Game out of the way before then. With the code commented and now public, and a new build with the replay bug fixed, I was done. It wasn't perfect. Not even anywhere close. But I'd set out to finish a game and I had.

So what have I learned?

If I'm going to stick music on via YouTube while I work, make sure it's a lyric video otherwise I will get captivated by how incredible Little Mix are during their live performance of Secret Love Song.

Setting up a project when you have things missing from the machine is awful. And there isn't really any way I'd have known they were missing until Visual Studio gave me an obscure error in one box and hid the useful one elsewhere.

Don't download external assets and assume they are ready for use. Even if they don't seem like they need editing, give them a once over before adding them to the project.

Adding the ability to change the resolution needs to be done earlier. I always knew it was going to be in there, but when it went in, so many things broke because the maths was calculating based on the resolution it was designed around, instead of the one that was being displayed.

Something I already knew was that game development never goes to plan, and considering I was still implementing mechanics the day after I was supposed to be refining them, this definitely didn't go to plan.

And that's Bird Game. Or as I later realised I should have called it, Crappy Bird.

While having a bit of a think, I've got a plan for what to do next. But that's for next week, because I did not intend to write this much.

The source code is on GitHub and the game is downloadable on itch.

Popular posts from this blog

Getting Started with the FireRed Decompilation

Phoning It In

Tonight Matthew, I'm Going to Make...