Ludum Dare 53 took place the weekend before final exams. This is a great time for a professor to step away and do some creative exploration, but it's not a good time for my students. Truly, it's hard to find a good time for students to jam since it's not like the rest of their classes hold off for a bit so they can spend 48 hours making something, despite the fact that this might be the single best way to get better at making things.
The theme for Ludum Dare was "Delivery," and at first I was a little disappointed. It felt a little like people were voting on the worst part of RPG quest grinding. After some discussions, I realized there are a few different interpretations, and I look forward to exploring more of the games during the scoring period. For my own game, though, one of my first ideas is what really stuck: a delivery person who manhandles packages. The result is Mr. Delivery Man.
I read the theme Friday night but could not set to work until Saturday morning. It did not take me long to get a minimally playable proof-of-concept implemented: drop a package and kick it as far as you can. I sketched some character ideas on paper, and then I pulled out my Wacom Bamboo to draw them up in Gimp. I feel much more comfortable sketching in pencil than I do doodling with my digital tablet. Every time I do something like this for a jam, I feel like I should invest some more time in getting fluent with the tools. Then I think about how long that would take and deprioritize it. Still, I wish I had more confidence. I watch my art majors with their tablets, and they fluidly add layers, sketch ideas, and move on. All my ideation is on paper, which makes the digital production feel weighty, leading to a lot of reworking. It's not like you'd know it from the results, either. They are only good enough.
A digitally-enhanced photograph of a goofy pencil sketch of some character ideas
I tinkered with trying to add a knee joint to get something with a QWOP feel, but I ended up preferring the straight-leg kick. I also spent a little time trying to animate the character as if he was holding the package before dropping it, but this proved tiresome and didn't significantly add to the gameplay. The result is that he's got a bit of Homestar Runner magic in how he holds that box in the air.
Recording the sound effects was some of the most fun I had on the project. I did a little quick research on how to Foley the sound of glass breaking. I took a break from that to make an afternoon coffee. Opening the cupboard, I was inspired to clink some mugs together. Perfect. I recorded myself clinking mugs together for the glass sound, and then I punched a spare board game box for the impact sounds. Conveniently, the box had some bits in it, which gave it a nice depth of sound. It's subtle, but it's quite nice. Whenever the box is struck, one of four random glass sounds and one of four random impact sounds are mixed together, so even though it's a small set of sounds, it still feels audibly satisfying.
The music also brought be great joy. Tritones play on tremolo strings before dropping the box, and this adds lovely tension to the very silly experience. There is a moment of silence as it falls. I experimented with playing audio through the fall and the kick, but this was much less fun than just bringing in the music after the box came to a rest. I think the polka is just right for a successful kick, and the sad trombones came out as I desired. I had to look into LMMS' controller tracks and pitch variation for the trombones. This feature didn't work quite like I wanted, since I wanted to mix square and interpolated forms; there may be a way to do this, but I couldn't find it. I was able to get a satisfactory sound by adding enough control points to a curved wave.
By the end of Saturday, I wanted to get a Web build up to make sure everything was working as intended. Here is where the headaches began. My usual continuous integration configuration makes use of the godot-ci action, but it does not currently support Godot 4.0. There is an open issue about this that actually had some discussion contemporaneously with Ludum Dare 53. The latest post points to an alternative approach. I looked into that, and after a lot of frustration and back-and-forth with GitHub Actions (push, wait, check, fix, repeat), I ran into a more troubling issue: Godot 4.0 Web build requires SharedArrayBuffers. I had just encountered SharedArrayBuffers on Friday when working with my game studio team: a subset of them were trying to fix an audio stuttering problem, and we had discovered that we could address it by enabling the "Threads" option on the HTML5 export. This worked fine on our test machine but then failed in integration. This is because SharedArrayBuffers require custom http headers, and GitHub Pages does not allow such a thing. All of this came after I had just added on-screen buttons for all the controls, assuming the Web build would work when deployed, but now I had to consider the real possibility that this would be strictly a native game. The biggest problem with this is that it's much harder to integrate with the Ludum Dare review community if you don't have a Web build. Indeed, one of the threads I just saw on the LD site was asking for a filtering feature since the author did not want to run any non-Web games.
Somewhere on my journey through many search results, I saw someone mention that itch.io had recently added custom header support. Whether this was specifically to support Godot 4.0 games or a beneficial coincidence, I do not know. A quick test showed that, indeed, this worked just fine. While I prefer just having all my jam projects in one place, and that place being GitHub, it was very easy to get the version on itch.io playable. I set up a Makefile to automate the generation of the Web build and its zipped contents, but I have not yet gone so far as to automate uploading to itch.io using butler. If I have to continue using itch.io as a platform for jam games or side projects, I will have to look into it.
It was midday on Sunday before I had the deployment issues sorted out, and I still had the energy to do a little bit more with the game. Something that had inspired me early on in the project is that just kicking the boxes around is a fun toy, and I figured I could use achievements to reward players for trying different things. Mr. Delivery Man then became my first game with achievements. I think that they serve the design purpose very well, and this sentiment is echoed by the early comments on the game during the Ludum Dare rating period. The software system behind the achievements it not terribly clever: each achievement is an object with a function that can tell whether the achievement has been met based on a game record, and after each play, the list is checked to see if there's any new ones met. I had hoped that after implementing my first achievement system, I would have a better idea about how I would want to do it next time. The truth is that it was just sort of pieced together, and I'm not sure I gained any great insight into implementation patterns.
That's the story of Mr. Delivery Man. He was almost named Delivery Dan in an homage to great characters in both Red Meat comics and Firesign Theatre, but leaving him anonymous ended up feeling right. Once again, here is the Ludum Dare page for the project; while you are there, consider checking out Delivery Destroyer and Messenger, which were created by two of my sons.
Ludum Dare 52 was the weekend before the start of the semester. I was able to get all my necessary work done the previous week and so participated in the compo. My game is Ol' Limberlegs, and this blog post will share a few details of how it came about.
I got out of my last meeting for the week just before 3pm on Friday, and so I was able to check the theme announcement on the walk back to my office. I wrapped up a bit of work before heading home, mulling over the theme: "Harvest." I find game jams to be a good opportunity to explore different genres. For a while, I've wanted to make a Cookie-Clicker-style game, and this seemed like a good opportunity. It also felt a bit too easy, though, sort of like making a game about planting and harvesting plants. Yes, it matches the theme, but it seemed like there must be a hundred of those being made.
One of the genres I've never explored is fighting games, and I have a few bad sketches here of a giant corn man fighting an android tractor. This is where my meager drawing skills are a real limiting factor to Ludum Dare. I turned my mind to other aspects of the harvest, and this got me to thinking about the harvest festival—the party at the end of the harvest. Here there would be music and dancing, so why not make a rhythm game?
I wanted to get the core mechanisms in place, so I started just figuring out how to track the amount of time an audio stream had been playing and synchronizing keyboard input to that. With the audio side of the proof-of-concept out of the way, I turned to making a dancing character. A stick figure seemed the right way to go, and I got that working pretty quickly, but not before spending some time exploring the idea of spline-based rendering. In my imagination, I can imagine a wobbly-limbed stick figure, something like noodle arms. Turns out that my memory of how splines actually work, and my experience with Godot's Curve2D class, were both not up to the task. A simple stick figure it was.
The dancing character was always meant to be a form of fun visual feedback, not something intrinsic to the gameplay. However, as I was working on it, I recognized that he just wasn't dancing enough. My plan was to do a kind of traditional rhythm game, pressing keys to make the guy dance, but this meant he was really just moving one limb at a time. This gave me the insight that I could do something a little different: why not have the player one limb in position, and release it on the beat, and then earn bonus points for jangling the other limbs around? It didn't take too long to prototype this, and right away, I knew I was on the right track. Now, the character had a kind of herky jerky personality instead of just doing the white man twist. This was about the time that I started to really think of the guy as Ol' Limberlegs, named after a folksy wooden dancer in "Mr. Show with Bob and David."
Here is where I lost a bunch of time. I set up my old Bamboo and tried drawing a pudgy hillbilly character with the intention of replacing my stick figure with a cutout animation. I thought I could just whip up something and drop in place, but I'm pretty slow at "whipping up" a drawing. I hadn't used these particular tools in a while and had forgotten all the shortcuts. I didn't know exactly what I wanted, artistically. Also, my code assumed that vertices moved rather than being rotated. What a mess. I finally gave myself a hard deadline, missed that deadline, and then realized I had to go with Plan B. Next task: come up with Plan B. I decided to try doubling down on the Limberlegs idea and see if I could make a wooden man. One Gimp tutorial later, I had a simple wood grain texture, which I could slap onto resizable TextureRects in-engine. This meant I didn't have to know exactly how big each piece would be, which allowed me to tweak settings until I got what I wanted instead of having to redraw upon mistakes. I still had the Bamboo out and used that to make the charming face.
One feature I really wanted, but that took a back seat to some other critical issues, was to have the face animate based on the player's performance. I have some sketches of closed eyes, "O"-mouths, and some expressions that would have been fun to put in. However, as some of my players have pointed out, there's already too much happening in the game to fully enjoy the dancing.
The last feature I added was the little rhythmic wobble of the torso and the head. I think these add an awful lot to the personality of the wooden guy.
That's all I have to share about Ol' Limberlegs. I hope you enjoy it. The next Ludum Dare is right at the end of the semester, and I hope I can participate in that as well, even though it will likely be very difficult for any of my students to join in.
Ludum Dare 47 ran from 6PM on Friday, October 2, to 6PM on Sunday, October 4. This is the latest instantiation of one of my favorite game-making events. The traditional Ludum Dare is a 48-hour game development competition in which participants are given a theme and then must make a game from scratch—code, art, music, sound, story—within the time constraints. "From scratch" is a bit ambiguous, since one is able to use programming libraries, game engines, and fonts, but the spirit of the event is clear. There's also a "Jam" category, which allows for teams, third-party assets, and an extra 24 hours, but to me that feels like a different, concurrent event. There's nothing wrong with it of course, but Ludum Dare to me means the traditional competition (or "compo").
The theme for LD47 was "Stuck in a Loop," and my eldest son and I both created entries for the compo. Because of family obligations, we only had a little more than 24 hours to work on them. The other boys worked on related projects in Kodu and Construct while we worked on ours.
The rest of this post is about my LD47 project, Orbital Blast. Follow that link to the LD47 page, or you can also jump right to the HTML5 build (which was built, of course, through continuous integration).
The moment I read the theme announcement, I heard Devo's "Stuck in a Loop" playing in my mind. This put me in a retro mindset that got me thinking immediately about cyan and magenta. This combined with the "loop" idea of Gyruss. In fact, in 2012 for Ludum Dare 25, I made a quick entry called Reverse Gyruss, in which you play the aliens instead of the hero in a game of similar topology. I have fond memories of playing Gyruss on the C64, although it was one of many games I enjoyed; I suspect part of my reverence for the design comes from Raph Koster's including it as a notable evolution of shmup topology in Theory of Fun.
My family went on an after-dinner walk before I could sit down and start working, and we discussed some different interpretations of the theme. I think it was part of this conversation in which my wife asked me if there was something specific I wanted to learn from this jam. My first thought was that there wasn't, but on further reflection, I really did have two goals: one was to explore how object-oriented architecture manifests within Godot Engine, and the other was to implement examples of juice.
Controls
Developing the control of the games was challenging. I tested primarily with keyboard input, which I intend to be the primary input scheme. For most of the game's brief development life, I had a system where left moves the ship clockwise and right moves it counterclockwise. This works well for the ship's starting position at the bottom of the screen, but it gets awkward when maneuvering from the top. Upon further reflection, I could imagine holding a C64 joystick and pushing the stick in the direction where I wanted the ship to be, rather than the relative direction I wanted it to move. I redesigned my input handling logic to use this same approach with keyboard input. I could not puzzle out the geometric problem of determining which way around the circle to move the ship. For example, if the ship is at 9 o'clock, and you give input for 12 o'clock, how do you know which way around the circle to move? This was a case where I had to look up the formula and insert it into my solution.
Supporting touch input cost me quite a bit of attention. I started with keyboard input but, knowing how it easy it was to post an HTML5 build, I also knew that supporting touch would be convenient for players. My first approach—when the input system was based on left and right input—I tried just putting simple, handcrafted buttons on each side of the screen. Unfortunately, Godot does not make it easy to allow more than one button to be pressed at a time. Adding further complication is the problem that testing multitouch input requires me to deploy to the Web and load the game on my phone, so the cycle time is very long. After an hour or so, I decided this was not worth the effort and abandoned touch input... until later, when it had been scratching at the back of my mind and I decided to add it again. This time, I had the Gyruss-style input working for the keyboard, and it seemed natural to allow the player to touch the screen to move toward that point. Indeed, the math here was basically the same as what I already had in place, so it was just input processing. Unfortunately, this still raised the problem of not having an easy way to handle or test multitouch. A nice solution would be to look for a second finger down to fire, but I didn't have time for that, so I switched to an approach where touch (or mouse) input simply keeps the ship firing as quickly as it can.
A Bit of Juice
I was not able to add all of the juice that I wanted. In particular, I was hoping to add camera shakes; I found some great tutorials and it would just be a matter of putting it in, but there are only so many hours in a day.
What I was able to add was particle effects, which I have never done in Godot Engine before. The built-in particle editor is nice, although it pales in comparison to those I've used in UE4—mostly Cascade and a bit of tinkering with Niagara. The background starfield is handled with particle effects, and of course the explosions are as well.
A related bit of juice is the smooth transitions between the menu screen and the in-game experience. I was so happy with the starfield that I decided I wanted to keep it running continuously through the game experience. Rather than have a separate scene for the main menu, then, I incorporated it, the gameplay, and the game end screens into the single Level scene. This led to a glut of logic within the Level's script, since I had to handle the states and transitions. In fact, now that I think about it, I probably could have saved myself some headaches if I had thought of the main menu at least as a separate scene that could be instantiated into the Level on top of the continuously-running starfield. This ties back to my other goal and the challenge of making a game in roughly 30 clock hours: I didn't take the time to refactor toward good OO architecture since everything is still relatively small, and there's no maintenance plan.
One of the earliest features I added to the game is actually one of the most clever ones—so clever that I kind of forgot about it until my son asked how I did it. I wanted to sell the illusion of depth in a strictly 2D game, and so to do this, I wanted the player's bullet to shrink as it moved toward the middle of the screen, and for the aliens to start out small and get larger as they move outward. Clearly, these two operations are basically the same: scale the actor based on its distance from the origin. I created a custom scene that, when instantiated into a node, would scale that node based on its distance from the center. It's not exactly the decorator pattern instantiation I was hoping for since it has to break encapsulation to manipulate its parent node, but it had the advantage that I could just drop it in to the Alien and PlayerBullet scenes and it worked like a charm.
Music
Perhaps my favorite part of making the game was composing the music. There are two tracks: the menu song and the game theme. Both were broadly inspired by a 1980s Devo sound. I wrote the shorter menu theme first, and originally it ran through the whole game. Saturday night, I was exhausted from working on the project all day, but after a quick game of Quacks of Quedlinburg with my family, I was invigorated to write what became the main game theme.
I had tinkered with LMMS before, at least enough to know what things I was doing awkwardly. This time, I spent a little time looking at some of the demo projects to get a better handle on how to manage tracks, especially the different drum beats. I also knew that I wanted to keep the song mostly on one note in the bassline. In the main game theme, I did put in what I consider a fun and unexpected cadence It came from a discussion with my friend Andrew Crow, choral director at Ball State University, when I asked him what kinds of chord changes I should be trying to learn to level up my piano improvisation.
For a while, the main theme included a sound like the roar of an overdriven electric guitar, but I replaced that with the more sci-fi pad sound. The last thing I added to the song was the little wood block sounds. I hope that you didn't notice them the first time, but that as you listened you came to love them like I do.
Both of the songs in the game can be downloaded directly from GitHub in Ogg format if you want to give them a listen. Keep in mind that they are designed to loop, so if you just listen straight through they will end abruptly.
Ludum Dare is always a good time. It's a good lesson in humility, to remember that scoping is difficult and expectations must be tempered. The format gives room to explore ideas in keeping with Alan Hazelden's advice that if you can't prototype it quickly, then you should probably work on something else anyway. I imagine the next Ludum Dare will be in the Spring semester, and I hope that my schedule works out so that I can join in again.
This past weekend, I participated in Ludum Dare 46. The theme was "Keep it alive," and as soon as I read it around 9:30 on Friday night, my mind went to breakout-style games. I've always had a fondness for this genre, but I've never built one.
Here's a gameplay video that shows the result of my efforts:
The rest of the post will provide some narrative about how the project came about.
Inspiration
When my wife saw what I was working on, she said, "This used to be the only kind of game." It's true that my inspiration for this project draws from games of my youth: the 1980s and the Commodore 64.
One of my favorite games on the C64 was Krakout. Check out this video of a chap playing the first several levels of the game, and tell me if that's not some of the best SID music you have ever heard. It amazes me what some of these guys could do with three-voice polyphony. On top of that, Krakout had the trippy option to scroll the background with the ball and, of course, some kind of destructible floating heads. I didn't go back to watch the video until after the jam, when I was writing this post. Now I have that music running in the background, and I'm digging it.
I thought about it a bit Friday night and got up Saturday ready to dig in. I decided to use Unreal Engine 4 for a few reasons. One reason was that there were some specific engine features I wanted to explore. Another was I was hoping to encounter some ideas to wrap up my semester's work on tutorial videos that explore Computer Science concepts in UE4. That project has taken a back seat to just trying to keep the lights on this semester. Fortunately, my playlists exist outside of the semester timeframe, so I can continue to explore the project beyond this semester.
What Didn't Make It In
A Little English
One of the ideas I wanted to explore from a game design point of view was the effect of torque or spin on the ball. I have never seen a breakout-style game that does this, so I thought it would be fun. My hope was that I could get this all done using UE4's physics engine. I tinkered with it for maybe two hours Saturday morning and made little headway, but here's some of what I learned.
I was able to get a ball launched so that when it bounced off of a wall, it was given appropriate spin. However, this also slowed it down. It slowed down because of restitution and friction. Restitution was easy to change without hindrance, but when I removed the friction from the surfaces, the ball no longer gained any spin. In retrospect, this is sensible: of course it is the friction of the collision surfaces that would impart a rotation. In a pure, frictionless, inelastic collision, we would expect no other kind of force to be involved. I could not reconcile the desire for spin and the lack of friction, and I had no gameplay at all at this point, and so I abandoned this line of research.
Later in the day, I read about the potential of using a physics motor to drive the forward momentum of the ball, perhaps in a way that I could increase its energy on each bounce instead of reduce it. However, at this time I had decided I could not afford any more effort along these lines.
I had switched instead to writing my own collision logic. I have always had a hard time remembering fundamentals of linear algebra: I feel like I am always learning it from scratch. I was able to do some research to discover the formulae I needed for bouncing off of arbitrary surfaces, and I found this StackOverflow answer to be particularly useful.
After programming the basic bounce logic, I jumped back into trying to get some spin on the ball. I spent too long on this without yielding any fruit, but I do want to share a small success. At one point, I determined that the spin I wanted to add was determined by how the original vector and the resulting bounce vector intersected. Dot product was being used to determine the new angle, but how could I sort out if I should impart a clockwise or counterclockwise spin? Cross product! Yes, friends, I remembered something from linear algebra and deployed it successfully. Huzzah! Unfortunately, I was sinking way too much time into this little bit of polish, and at lunchtime still didn't have a playable game, and so this all went into a dead branch on git.
Destructible Meshes
I had read about UE4's destructible meshes but never used them, and I thought this would be a fun way to use the 3D engine to enhance an essentially 2D gameplay experience. Making destructible bricks was not too difficult, and I quickly had them exploding nicely into shards. Unfortunately, these shards were then bouncing off of the gameplay bounds, but only sometimes: some shards passed through, and some bounced off at very high speeds. I fiddled with the collision settings so that the bricks only collided with the ball but not the bounds, but then the result was that, even if I turned off collision at the time of explosion, some still collided with the ball. It seems to me that the handling of collision on these shards is inconsistent. I followed some advice about tweaking the size settings so that they would not collide at all, but I did not find the engine simulation to match the suggestion. Of course, I was doing destructible meshes in an unconventional way, and so the best I can figure is that what I wanted to do is not what this technology was designed to do.
I looked into the new Chaos destruction engine, which I had seen mentioned in a livestream months ago. I knew plugins were available for it, but I didn't realize that you have to do a 4.23 source build for them to work. That put a mercifully quick end to this exploration.
This was another Saturday morning exploration of polish that left me a little smarter but without any kind of playable game. Over lunch, I expressed my frustration over not following the advice to get something working first, and then add polish. My justification is that the whole project was really just an exploration of polish: of course I knew I could make a breakout game, but the crux of it was making it with these particular ideas in place. My wife said, "Learning is slow." I responded with such vigor that she thought I was mad, but I was really just emphatic about how right she was. Her perspective was that perhaps a game jam was not time to learn something new but to deploy what you already know. Well, maybe next jam I'll try that approach, but I do tend to use them as a timeboxed exploration of something new.
Level Sequences
For all the time I've spent in UE4, I've never really designed levels. My major UE4 release, Kaiju Kaboom, uses procedurally-generated levels. I've never used the level sequencer or matinee to create in-game cinematic effects, and I thought this would be fun. In Goofball, I did explore this for doing some fun camera work, but in the end, everything I was trying to accomplish I could do better with other techniques. For the camera, it was a simple Set View Target with Blend node. I was hoping to make the main game camera do a sort of figure-eight movement that gets more intense with each level, but I ran out of time before I could explore that.
Spline Meshes
I originally had simple stretched cubes to establish the game area, and as I was replacing placeholders with real assets, I realized that this might be a good opportunity to explore spline meshes. When I first learned about spline meshes—probably years ago—I was blown away. I had never really thought about how I would model something like a highway before. Again, because I don't really do any level design as such, I never came across a need for them. It got me thinking, what if I designed the boundary of the game with a spline rather than a static model?
This was driven by whimsy: unlike torque, destructible meshes, and level sequences, I did not come into the jam wanting to explore spline meshes. I was able to get a simple and ugly spline mesh laid down, but what really surprised me was that I was getting collision from the path of the control lines rather than the rendered path of the geometry. I am still puzzled by this, but I realized pretty quickly that this was not core to the project and just dropped it. Perhaps I can take a closer look at this in a future project.
Gameplay Cues and Decorators
Along the lines of finding topics to pursue in a tutorial video, I had hoped to get Goofball to the point where I could explore either simple gameplay cues (as I wrote about a few weeks ago) or the use of the Decorator pattern for stacking powerups. Unfortunately, neither worked out. I never got beyond simple ad hoc handling of visual effects, and without any powerups at all, there was no need for decorators. Still, I think both are interesting topics, and I need to consider whether it's worth making a video tutorial on these. I would have to spend a few more post-LD46 hours with the code to see if I've left it in an amenable state.
What did make it in
Now, let's turn our attention to some of the cool things that are in the game.
Fisheye Lens
One of the main drivers for this project was to play with visual effects, and chief among these was the idea of a fisheye lens effect. You know what I'm talking about. Waughmp Waughmp. I didn't have any idea how to do this, so I started a-Googling. There were a few mentions of FOV tweaking, but I saw some cautions against that and never tried it. I went right for what seemed to be the consensus approach: a post-processing volume. This was exciting to me since this was another thing I had never done.
Emre Karabacak's tutorial was helpful in getting me set up with a minimum working material. My next step was to consider how to stack the effects. Timelines are a useful way in UE4 to play a canned animation, such as running the fisheye intensity up and down over half a second or so. What I wanted was something more like curve addition or scaling. While the intensity is rising, the ball may hit another brick, which should raise the ceiling and extend the curve. I looked into UE4 curve assets (again, something I had never used), but I did not see a way to operate on them, only to evaluate them.
I ended up using the magic of FInterpTo with a pair of values. The target intensity indicates the peak of the curve, and every time there's a ball collision, that intensity increases. That target also falls toward zero. The interpolated intensity will always move toward the target intensity. The result is exactly what I wanted: a peak that can raise arbitrarily high, but falls off, and a visual effect that tracks it.
The standard tutorial code one finds online for a fisheye material has it centered in the camera, but as I played with my game, I realized it could be interesting to track the ball's position with the effect. This also presented me with a good challenge: had I learned enough of the UE4 material editor, and did I understand the fisheye demo code well enough, to make these changes? It took little time and it looked great, so I was happy when this all came together. The basic idea was to get the ball's position, project it to screen space, and then normalize this to put it into UV space. This is then a modification to the RadialGradientExponent's center parameter.
I knew early on in the project that I wanted the profusion of visual effects to be the main source of difficulty escalation in the game. Most breakout games do this with level design, but I wanted to tinker with technology rather than clever arrangements of blocks. One of the last features I added was that, as the player clears boards, the amount of intensity added by ball bounces increases by 50%. This is really disorienting to me as a player, and I think it delivers on the "goofball" promise. (Here's a treat for my readers: Numpad * kills all the blocks on the screen. Use this a few times in a row to ramp up the level, and then check out the insane visuals. Enjoy!)
Having dropped the physics engine and the destructible meshes, I do wonder whether I could have done this effect with reasonable performance in Godot and built the game for HTML5. This certainly would have made it easy to share. I barely know the syntax of GLSL shader programming, but I wonder if my time spent in the UE4 material editor would give me a good grounding for getting into it. That's a challenge for another day.
Music!
The last time I composed any music on my computer was for Please, Sir, my entry to Ludum Dare 28 in (yikes!) 2013. It seems I did not write a blog post about it, but I found my GitHub repository. I remember writing the soundtrack in Rosegarden, which I chose in part because it was most like the Cakewalk composition software I used back in the 1990s to record an album of MIDI tunes. I used to spend a lot more time making music than I do these days, and I miss it sometimes. You can't do everything... but you can do game jams!
One of the things I love about Ludum Dare is that it pushes you to be a renaissance man. The Ludum Dare compo requires you to make the whole thing yourself: programming, design, art, music. A few years ago, they added the Ludum Dare jam, which allows you to work in teams and use others' assets. Given that there's basically infinity jams on the Internet going on now, I don't know why someone would want to come to Ludum Dare to do that. While the Ludum Dare site describes the compo as "hard mode," to me, that's really what makes it stand apart from the rest.
In any case, I was excited to get into LMMS and figure it out. I mentioned before that this was the tool that I recently learned about and then coached my son into using for our March FamJam. Here was my chance to write something for it myself.
One aspect of the tool that surprised me is that every beat/bassline track has the same instruments. This is not at all obvious to me from the interface: it looks to me that my song can have any number of beat/basslines, so why should they be different? This cost me some time as I worked on one beat, set it aside, worked on another beat, and removed instruments from it. Then, back to the original beat, and things are missing.
After making better sense of the interface, I laid down a beat and a single repeating melody, which was just a simple doodle in A minor. My plan was to come back to it and add some more panache, but I ran out of time. Well, what actually happened was that the time I was going to use to add some more audio interest was instead spent helping my son publish his own Ludum Dare entry, but that was a good use of my time.
The number of samples and synths in LMMS is overwhelming. However, it also became a great source of sound effects. All of the sounds in Goofball are pulled from LMMS. My original plan was to tinker with something like bfxr, but as I worked with LMMS, it seemed crazy not to use it.
Color Palette
I did not have a particular look in mind for the game going into it. While the rest of the family was engaged with Ludum Dare participation, my wife was working on a puzzle:
The pieces were spread across the kitchen table, and the color scheme caught my eye. I started replacing placeholder materials with some drawn from this palette, and I dropped the background to pure black. I'm not sure what colors I would have ended up with if my wife hadn't been working on this puzzle, but I was pleased to find such convenient inspiration.
Family
I wasn't the only one working on a Ludum Dare 46 project. As I mentioned above, #1 Son made his first official entry to the jam. He's a teenager with his own GitHub account, and so I hope this was a good experience for him. There doesn't seem to be any minimum age for Ludum Dare accounts, but the infrastructure around it benefits from things like email and Web-based repositories. #2 Son also worked on a game in Construct, although he said he did not want to actually submit it to the Compo. However, this morning, he mentioned that he wouldn't mind sharing it with family and friends, so folks in those categories can watch my Facebook page for links later. #3 Son also made an entry using Kodu. He really wanted to share it, but I don't think it's quite the right time for him to do so, and I'm not sure I can export a game out of Kodu anyway. Still, I love his spirit. #4 Son spent the weekend mostly watching his brothers make games. I suspect that one of these days his interest in reading will kick in, and then there will be no stopping him.
That's the story of Ludum Dare 46 from my perspective. I hope you found something interesting to take away from it. Thanks for reading!
Ludum Dare 38 was the 15th anniversary celebration of one of the world's largest game development events, and this alone was enough to encourage me to participate. I did some digging and was a little surprised to see that the last one I participated in was with Summoned, way back in LD29 (blogged about it here). I know I've followed the themes and done a few sketches since then, but it wasn't until LD38 that I made a full submission. Ludum Dare comes every four months, which means it aligns with the end of the Spring semester, the start of the Fall semester, and the end of the Fall semester—an epic trilogy of bad timing for students and faculty alike. Still, I love the event: it encourages anybody with some spare time and interest to make a thing and make it public. It's the spirit of this blog and of my immersive learning projects to make in public.
LD38 provided another important opportunity for me. A few weeks into the Fall 2016 semester, I decided to invest a significant amount of time learning Unreal Engine, a decision I wrote about in December. Well, it's practically final exam season here at Ball State, so why not give myself a final exam as well: could I make a game in 48 hours for LD38 using what I've learned in Unreal Engine? In some ways, it's like the final exam I gave to my Game Programming students back in 2011, to make a game about Beneficence to demonstrate what they learned, except I had 48 hours, and the theme would come from the Ludum Dare community.
Before the event, I participated in two rounds of community theme voting. At 9PM on Friday, I popped over to ldjam.com and saw the announcement that the theme was "A Small World." Of course, that terrible Disney song was the first thing to come to mind, particularly the rendition from the old 45 I had as a kid. I thought about games taking place on small worlds, and I thought about the board game Small World, but nothing really jumped out at me. That late at night is awfully late for me to start being creative, anyway. After stepping away, I got to thinking about games I've played that have small worlds in them, and my thoughts came to Star Control 2 and it's classic Super Melee space combat.
A friend gave me a copy of Star Control 2 when I was in high school or college, and it quickly became one of my favorites. For those who don't know, the game is now available for free as Ur-Quan Masters. It's an epic space opera taking place over a whole galaxy, complete with planet-roving and resource-gathering long before Mass Effect—and they did it better, too! My goodness, don't get me started on the ridiculous tedium and carpal-tunnel-inducing stress of Mass Effect 2's planet scanning.
But I digress. I decided to make a simple two-player space combat game along the lines of Star Control 2 Super Melee. I also decided to do it primarily in 2D, since I'm gearing up for a 2D reimplementation of Collaboration Station starting this summer—but more on that in another post.
Making Subpar Melee
Saturday morning, I drew a quick red spaceship in Gimp and implemented the fundamental inputs for one player to fly around the screen. I made two planning decisions that morning: to use the Unreal Engine naming conventions and to follow its framework of separating pawn, controller, game state, and game mode. As I worked, I found the former to be a bit troublesome: not every kind of asset I was dealing with had a naming convention, and not every gameplay element had a clear place in the folder-structure taxonomy. It's still not entirely clear to me how conventional these conventions really are, since I have not read enough high-quality code to build an intuition for it. From the tutorials I've seen, I think my next project will take a more emergent approach—when there's a structural problem, refactor, but keep it lean until then. I'll come back to the gameplay framework decision in a little while.
The first major hurdle I encountered was that I wanted to set walls around the play area, such that a player would bounce off of them and take some damage. I watched a Pong tutorial last semester where the developer simply placed boxes around the play area off camera, and that seemed elegant to me. However, I kept passing right through the boxes, despite the physics settings. I don't know how long I was stuck on this, but at one point I was adding spheres into the board with gravity enabled, and watching them fall and pass right through the walls, scratching my head, when I was inspired to fiddle with the box size. See, I had decided to make these boxes look like walls, so I had taken their width to zero... and it turns out that even though the wall will render, a zero-width box will not generate collisions. A silly mistake, but one I won't make again! Setting the walls' width to 0.1 was enough for it all to work brilliantly.
Next I added the planet in the center of the screen and gave it gravity. A quick search confirmed that you cannot set a point source gravity using the canned physics settings, but it was no trouble to give the planet the behavior of pulling every ship instance toward itself, and then to modify the algorithm to make this value inversely proportional to the square of the distance.
With the edges and the center collisions working, I added a damage system, and then I began to add support for exploding when health reaches zero. This is where everything took a turn for the worse, early Saturday afternoon: Unreal Engine suddenly became unreasonably unstable. I couldn't work for a minute without it crashing and restarting. I narrowed the problem down to involving the details panel, especially when dealing with a flipbook animation. I sent about a million crash reports to Epic, so hopefully they find something in there, but I was stymied. I had been working in Windows, since several weeks ago I began learning C++, and the Visual Studio bindings are clearly more robust than the Linux ones I tinkered with. For LD38, I wanted to test my ability to get something up and running quickly, and so I was only using Blueprints—UE4's visual scripting language, which is much faster to iterate with than C++. Since I was not using C++ for this project, though, I thought perhaps I could switch over to Linux... except that the version of UE4 I had installed on my Linux partition was 4.14.x, and this project was already started in 4.15.1. With the wind out of my sails, I rebooted into Linux and started the lengthy clone, dependency download, and build process. I was able to finish painting some miniatures and go out and run some errands, and when the build was complete, I was rewarded with a perfectly stable UE4 running in my preferred operating system. Success!
The next major hurdle was adding the second ship for local multiplayer. At this point, I had a PlayerShip blueprint to represent the ship, and I had written a custom PlayerController to handle transforming the input events into ship events. I had also separated the ship's health and damage into a separate GameState object. It seemed like a good idea at the time, but I had no luck getting local multiplayer working. I thought gamepads would be fun, but UE4 didn't recognize my gamepads. I spent a lot of time just trying to get my old Logitech pads recognized as XBox360 controllers in Linux so that they would be accessible in UE4. Incidentally, this is done through xboxdrv, but it took a lot of reading and fiddling to make any progress. Even when I had the controllers recognized, I had no luck getting the second player to properly be assigned a PlayerController and possess the second ship. Again, I didn't keep track of exactly how much time I whittled away here, but clearly I was not making headway. I'd still like to know what I was doing wrong, although many of the signs point to the fact that custom C++ integrations are needed to do what I wanted to do. I cut my losses and moved forward with a different input scheme: I could get away with using the keyboard for both players if I eliminated the idea of using UE4's built-in multiplayer systems and instead just faked it. I wiped out my custom PlayerController and GameState and put the keyboard events for both players directly into my map, which had references to the red and blue ships. This was straightforward to set up and had me up and testing multiple ships in short order. Remember, kids: the player cannot see your engineering.
Moving into Sunday midafternoon, I finally added the ability to shoot. I spent too long on this, since I started with the Projectile Movement component, which was fine except that I had drawn my sprites aligned to the Y-axis instead of the X-axis. This is a newbie mistake and made me have to manually rotate a few vectors to get projectiles moving the right direction. Then, I decided to tinker with having the projectiles also affected by the planet's gravity, but this required then undoing all the work with Projectile Movement, since I needed a physics object whose velocity I could manually "pull" on. I got that working, but it wasn't really noticeable or fun, and I ended up going back to the original approach.
By Sunday late afternoon I had put in the end screen and title screen, and I kicked back to look at it. My ship drawings were meant to be placeholders, but the comic badness of them had become endearing, so I decided it wasn't worth the time to futz with them. Drawing isn't my strong hand, but it also isn't my interest in this kind of work. The lack of music, on the other hand, was really noticeable. This, combined with the fact that I had never done any audio in Unreal Engine, made me think that this would be the best use of my last push. Of course, the spirit of Ludum Dare compo is that you create a game from scratch, including the music, but at this point I didn't feel like re-learning enough composition software to make a bad custom soundtrack. Instead, I turned to the reliable and amazing Kevin MacLeod (Incompetech.com), who has a browsable collection of CC-BY-licensed tunes appropriate for games. It was a little choppy figuring out how to bring the audio into the game, but no more so than I expected, never having done it before. I grabbed an explosion sound effect from the Unreal Engine Starter Kit and a laser blast from a public domain sounds site.
The last step was to create the shippable executables, which I had also never done before. The build process is slow, and at first it didn't have the window size that I wanted. I discovered that the best way to work with this was by manually editing some .ini configuration files, and once I had that right, it worked fine. I uploaded the Linux binaries, rebooted to Windows, pulled from the project's repository, and built and uploaded the Windows executables. At 8:15PM, with 45 minutes to spare, I posted to Facebook that I was done and went downstairs for a celebratory drink.
A friend with a Mac was interested in trying the game, but of course you cannot build Mac executables without a Mac. (Of course. Because reasons. And thinking different!) On Monday, I built an HTML5 version and uploaded that one too.
There is one "bug" in the game that my son and I noticed when playing together: if both players explode, then red wins. I know exactly where that is in the code, and what to do to fix it, but I decided that I'd just leave the game as-is, in the spirit of the jam. The workaround is to make sure that you get to be red.
What it all means
As I mentioned above, this was a sort of final exam to myself, and I definitely passed. I navigated through the pieces of UE4 that I had been studying and practicing, I troubleshooted a few problems by working with other engine features, and I was able to quickly learn and integrate new features. I'm still not sure how I will teach others to use this engine, but course planning is for another time.
This very modest game took me approximately 16 hours of work. If this were a three credit-hour course like my CS315 Game Programming course, that would be roughly two weeks of effort—except, of course, it's actually much more, because you'd also have to account for the extremely high cost of context switching. I heard a heuristic for designing exams that says that you should give students three times as much time as it takes you to take the exam. Let's assume that this is a good rough estimate, and we can say that my three-week project would then equate to a nine-week project by an inexperienced undergraduate. Now the amount of time I spent learning Unreal Engine the past eight months or so definitely exceeds a single course, and I have a wealth of background knowledge to draw upon. I'm afraid all of this leads me to the unfortunate conclusion that maybe something this simple is still beyond the scope of what I can expect from an average CS315 student in the Fall.
I know I've heard professors say that one of the advantages of using games as a motivating context is that students will put in more hours on them than normally required, but this feels unethical to me. Sure, some students may put in more than the expected nine effort-hours per week for a three-credit course, but the course design should not really encourage nor reward that: that's just encouraging crunch, in a field where we know it's destructive to individuals and families. I would not stop a student from learning, but I also want to be very careful to design a course that permits glorious success within the expected amount of time and effort, given the prerequisite knowledge.
I already received one pre-course complaint from a student whinging about how he doesn't like working in teams, but I think this experience shows me that teams will be necessary. My past experience with pair programming tells me that if I was learning UE4 with a friend or a cohort, I would be much further along now than I would be otherwise. Also, my time investment should help me bootstrap the students, so I can be the mentor for them that I didn't really have on my random walk through YouTube tutorials, documentation, forums, and samples.
Parting thoughts
This has become quite the epic post, but I think that's everything I wanted to record for future-me, when I'm trying to remember the kinds of mistakes I made and my thoughts about implications. I know it's easy to lose sight of how hard it is to learn something new after you've learned it. At last night's Computer Science spring banquet, an alumnus on the panel put it well, talking about programming problems: "None of us know how to do it until after we've done it."
Two final thoughts about Ludum Dare. First, I was tickled to see a LD38 entry from an alumnus I worked with years ago, a creative and clever guy who enjoys the hobby of making little independent games. I'm so glad to see that he is finding joy in making games. Even better though is the second parting thought: one of my CS222 students was inspired by my course to make their first game this past weekend as well. With no other background besides sophomore-level computer science, this student learned Stencyl and made a fun little game from scratch, and shared it with the world as part of Ludum Dare. It doesn't get better than that!