Tag: LD48

InvadTris: A Ludum Dare 41 Game

Over the weekend, I participated in Ludum Dare 41. The theme for this Ludum Dare was “Combine 2 incompatible genres”.  The game I produced, InvadTris, is a mashup of Space Invaders and Tetris, combining the static shooter with a block puzzle game.  I’m very happy with it, and am continuing to develop it. It’s already a lot of fun to play.InvadTris

Play and Rate InvadTris

Post-mortem article

 

Great Plays from Ludum Dare 38

Planet Desumaton – siegfriedcroes

Planet Desumation

The gif speaks for itself… Control a small small planet, picking up Asteroids into orbit, and smash them into a large “boss” planet.

Path of the Rabbit – Managore

Path of the Rabbit

A turn based tile strategy game similar to Pipe Dreams. Managore’s games are always top notch, and this is no exception.

Sticky Keys – thevaber

Sticky Keys

A really well polished typing game, with a twist. The keys keep popping off, due to some nasty creepy crawly insects that have infested the keyboard. You have to interrupt yourself and pop the key caps back on in order to keep typing.

Monolith – samlo and david-carney

A rail shooter bullet hell game where you have to lock on to your target by holding still, leaving you vulnerable to enemy fire. It’s high speed and frenetic. The art style is b/w, with what looks to be a procedurally generated fractal landscape, and a monolith that looms over the horizon, and seems to never get any closer.

TARJECTORIES – csanyk

Tarjectories by csanyk for LD48-38: A Small World

Yes that’s right! My own game, this time I think is good enough to qualify as a recommended play. It’s a casual target shooting game played on tiny planetoids that rotate, with procedurally generated levels for added replayability. Patience and accuracy are the keys to doing well. Learn to estimate the gravity and rotation speed of the planet so you can aim your shots correctly. I plan to develop this one a bit further, so stay tuned.

Antivirus – kappaixAntivirus

A nicely designed 2D top down shooter, reminiscent of classics like Gauntlet, 2D Wolfenstein, Berzerk, and Frenzy. When you die you get a fake BSOD game over screen, which adds to the fun. Battle through an area and the size scale changes, making for an interesting and novel transition mechanic.

Plutus – jason-varnell, nathan-hicks, and Apostate Games

Plutus

Hilariously written backstory makes this charming katamari-like feel special. Control the jealous planet (let’s not quibble) Pluto on a quest for revenge and ever greater mass.

Space Mailman – kepons

Space Mailman

Gorgeous but bare-bones wireframe graphics and hard core difficulty make this game tough to play. Deliver mail between planets to make money.

Flight of Claude – lyxil and colm-eccles

Flight of Claude

A beautiful, touching visual story about a baby bird and his nest mates.

Aphosis – urban-logic-games

Aphosis

Divert a doomsday rock on a collision course with Earth by attaching thrusters to stabilize its spin, then attaching a main thruster to push it away. Beautiful graphics, a fantastic musical backing, and extremely challenging game play make this one to try.

That Tiny Pea – thendash

That Tiny Pea

A fairly realistic update of the classic Lunar Lander. Land safely and you are rewarded by being able to step outside and take in the view. It’s hard!

The Life Amoebic – baby-dino-herd

The Life Amoebic

A convincing simulation of an amoeba. Control your amoeba by extending pseudopods with the mouse, and try to grab food to survive, grow, and divide. It’s pretty challenging.

Vixa – spav

Vixa

Spin the world around to dump balls into the green-lit sections and away from the red-lit sections. Green multiplies your balls, red destroys them. Lose all your balls and you’re done. Great graphics and sound, and solid game play make this one a trip to play.

Tiny World Defense – ianmorrison

Tiny World Defense

Fly your spaceship over the surface of the planet, defending it from enemies who want to shrink the planet into nothingness. There were a number of other entries in LD38 with a similar look and feel, a 3D orb-based shooter, where your shots skim over the surface of the planet. Almost like it were a newly-invented genre or something. But out of them all I think this one is probably my favorite of them.

Super Kaiju Dunk City – radmars, emarcotte, steakzzz, ninjavitis

Super Kaiju Dunk City

This is an amazing entry in the Jam category. Super polished, it’s a cross between an infinite runner and a rhythm game, where you control a basketball-dribbling Godzilla-like Kaiju creature, as you relentlessly smash through level after level of targets. I had a blast playing this, and would love to see it as a full-fledged title. There’s not much more to ask for, except maybe an epic boss battle against another Kaiju or super robot, and some kind of breath attack.


That’s all for now… I still have a lot more games left to play. As I find more “great plays” I’ll be adding them here. If you have played something that you think deserves a larger audience, post a comment below.

Until next time!

Debugging TARJECTORIES: a Ludum Dare 38 postmortem epilogue

If you haven’t played TARJECTORIES yet, I encourage you to download and give it a try first.

Next, I encourage you to read the project postmortem article I wrote about the experience I had creating TARJECTORIES over a 48 hour period.

Back? OK.

In the wee hours of Sunday morning, in the midst of my debugging hell hours, I posted this on Facebook:

Debugging a program sometimes is like converting one system of thinking into an equivalent system of thinking, only one that works where the other one fails.

Since you can do this only one keystroke at a time, it’s pretty rough when you’re looking at transitional code and are looking for signposts to remind you of where you are. It’s common when you get distracted briefly to come back to looking at your code, desperate for these signposts.

This can end up making you very confused and waste a lot of time.

How to avoid this?

To put it in more familiar terms, pretend you’re writing a novel, and you want to change some of your characters around, so you need to update the text so that everything Smith says is now said by Roberts. Halfway into this, you’ve forgotten who’s who anymore, and there’s nothing in the manuscript that can help you tell what’s been changed already and what still needs to be changed.

If you keep versions of files, you can run a diff of the current manuscript against the most recently checked in version. If you check in versions at the right time, when things are self-consistent, not in a transitional state, this can be very useful.

If you don’t have, or don’t make use of, these tools, you’re putting a massive cognitive burden on yourself that prevents you from higher order thinking about the problem you’re trying to solve. If you get distracted in the midst of your transitional revision work, it’s like a juggler dropping their balls. One hiccup in the routine and the entire thing falls apart, and the only thing left to do is try to pick it all back up and start over.

The hardest thing is when you keep having ideas and thoughts about what else you’re going to need to do next. Often times a change will have a cascade of changes. Not necessarily code changes, but feature changes, or new features. Each one of these is like someone throwing another ball at the juggler. Even the best juggler can only handle so many things before they slip up and have to drop it. And while a person is juggling, there’s very little else they can do.

If you want to get real work done, don’t be a juggler. They spend most of their time repeating a cycle of familiar tasks that just maintain a status quo, and hardly have time to make any progress with anything else. It looks impressive, but it’s monumentally wasteful.

Learning not to juggle is even harder than learning to juggle, though.

The thing is, when you’re doing game development, design and development are tightly interwoven. It’s not even iterative, it’s sub-iterative. You’re figuring out what’s possible, what’s fun, what you can make work, and figuring out how to make it work, making it, and then seeing what else it needs — all at the same time. It’s inevitable that you will have ideas at every step in that process. And each idea is a ball to juggle. I found it works best to leave myself “TODO” comments throughout the code whenever I have an idea come to me while I’m still in the middle of working on something else, and keeping a notepad handy for things that I observe at runtime. Otherwise, you need to be able to split your conscience like a fractal if you want to have any hope of being able to do all the things that occur to you while you’re in the middle of development.

Holy s—. I’ve been at it since 10pm, and I think I finally just fixed a bug that I’ve been puzzled by for several hours. I can’t even begin to explain all the stupid details that I’d need to in order to convey what I just did.

But here goes anyway.

In my project, I have a planet which has a player on it. I had this working just fine with a single planet.

I wanted to create mutli-planet levels, but when I added a second planet to the game all kinds of things started going wrong because of all these hidden assumptions my code was making about there always only ever being one planet.

So I started disentangling the planet, which was really doing a lot of extra stuff that it didn’t really have any business doing. This stuff was managing other game state, and when you had multiple planets, they ended up screwing with each other as they both were updating the game state. Sort of like a race condition, I guess.

It caused some REALLY bizarre bugs, though.

The level counter went up smoothly until it hit 11, and then it started repeating itself a few times, then skipping a head several numbers, like 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 11, 11, 14, 16.

It also had a strange tendency sometimes to not spawn any player at all, on the second level 11.

I fiiiinally got the problem solved, without realizing that was what I was doing. I just started to give up and work on other problems, when I decided that the planet object should not create its own player. I’d done that early on because it made sense when there is only one planet. With two planets, each would create its own player instance, and then I’d have to go back after and delete one of them at random. This SEEMED to work, but somehow became responsible for the weird level number glitch, and the missing player object on the second level 11.

I STILL don’t get how that exactly worked. It still doesn’t make any sense to me. But when I decided to de-couple the player-spawning duties from the planet object, and instead of two planets each creating a player on it, and then randomly selecting one of those two to delete, I re-did the code to spawn two planets, then randomly choose one of the planets to spawn a single player on.

That fixed it. Like, whoa.

Update: A day later, it finally occured to me what happened, and why. This may not interest many, but for posterity, here’s what was going on:

When I made the game, I started out with a 1-planet room. I had this working so well that I didn’t want to screw it up, so when I was ready to start work on a 2-planet room, I created a new room so I could mess around in it. I had my level counter set up in such a way that after level 8, it would switch rooms to the 2-planet room for planet 9.

I had some code in the LevelUp object that handles this. But the thing about the Level Up object is, it doesn’t do those things when the game room loads. So on the transition into the 2-planet room, there were certain things that weren’t happening. To compensate, I (this was a bad move on my part) copied some code out of the LevelUp object and put it into the Creation code for the 2-planet room, and then failed to maintain this code adequately as I continued to make further changes on the LevelUp object.

So what happened was, when Level 8 is cleared, the LevelUp object does its end-of-level thing, and increments the global level variable, and creates new planets for the next level. It then checks to see if the level is 9, and since it is, it moves to the 2-planet room. The 2-planet room starts, and there’s 2 planets there from the room editor, not from the LevelUp object resetting the level. So nothing weird happens until after Level 9 is cleared, because that’s the first time the LevelUp object levels up in a 2-planet room.

I’m still unclear why the level incrementer goes from 9 to 11 — it seems obvious that it has something to do with there being two planets, but I didn’t have the level incrementer tied in any way to the number of planets. And it’s more mysterious to me still that it gets stuck on level 11, and so displays level 9, 11, 11, 11, 14. If GameMaker Studio had a better debugger, I might have bothered to trace through the script and watch the variables change to understand what’s going on, but I figured out enough to fix the problem without completely understanding it (well let’s hope so).

As to why there was no player at all on level 12, I do understand that. The planet’s Create event creates a player instance, and stores its ID in an instance variable, so it can update the player’s x,y position as the planet rotates. In the two-planet world, of course, I ended up with a player instance on each world. I didn’t need or want both of them, so I figured I’d just randomly destroy one of them, rather than fix it so that there would only be one. So I used a for loop and iterated over an array that should have been as long as the number of planets (2), and picked 1 array index to keep, and destroy all others. I figured I might want to make a 3-planet room at some point, and was trying to make the code work for N-planet rooms, rather than solve the 2-planet problem and leave a 3+ planet problem still unresolved. But sometimes the random chooser picked an array index that was out of bounds for the “keeper”, and so the for loop would go through and destroy all of the player instances. This happened to happen on level 12. It happened consistently on level 12 because the RNG seed value was always the same, and the same number of calls to random() always happen between the start of the game and getting to level 12.

I fixed the code by removing the player create from the Planet object, and put it after the planets are created, using choose() to select which planet if there’s more than 1.

The code works and appears to be bug free, but from a design standpoint it’s still messy. When I get around to doing it over, I will clean things up by removing the 2-planet room, which was only ever supposed to be an experimental room, and re-writing the code so that rather than move to that room when the level incrementer hits 9, it will spawn two planets, instead. This will enable move to remove the duplicate code by getting rid of the now-obsolete experiment room entirely. In retrospect that’s what I should have done in the first place, but because I was so concerned about not screwing up my working 1-planet room, I didn’t want to risk it. But really, all I needed to do was check-in to source control and create a fork to experiment in.

As easy and fast as the progress I made Friday night was, Saturday night was an absolute nightmare of a debugging session, just to figure this thing out and get it working. It’s SO weird how it was sortof almost working. Sometimes it’s a lot better to have something completely not working and obviously wrong. Those kind of bugs are much easier to fix.

The good news, though, is that I kept my Friday momentum through Saturday until I took my long break. I implemented a lot of features and had the game 95% complete, or so I thought. Just that last little bit of debugging took about 7 hours, and now the game is basically done.

So I made excellent progress Friday, and most of Saturday, although I unwittingly introduced this nasty puzzling bug during that progress, which stalled me for the entire night. But I still got so much done so quickly that I’m basically done now.

I have until 9pm Sunday to work on it, but I think it’s pretty good right now.

Ludum Dare 38: A Small World (TARJECTORIES)

Tarjectories by csanyk for LD48-38: A Small WorldMy latest release is called TARJECTORIES, and it’s my entry for Ludum Dare 38, A Small World.

Play and Rate TARJECTORIES at Ludum Dare

The title is a mashup of “target” and “trajectory”. It’s also an easy misspelling of “trajectory”.

You control a little gun turret on a little world, shooting little projectiles at little targets. Use the planet’s spin, and your shot power and gun elevation to put shells on the target.

Destroy all targets on the planet to advance to the next level.

You will need to use your judgment and instincts to know how much power to give the shot, and what angle to fire at. Most targets can only be hit by indirect fire, relying on the trajectory of the shot as its path curves due to gravity. Here’s an early work-in-progress screen capture:

TARJECTORIES - Early work-in-progress

Controls

Adjust your turret’s gun elevation by the left/right arrow keys, or A and D keys.

Adjust gun power by using up/down arrow keys, or W and S keys.

Fire using the Space bar or Enter keys.

Scoring

  • Direct hit: If you hit a target directly with the shot, you will score a base amount of 1000 points. This is doubled for each consecutive hit you make: 2000, 4000, 8000, 16000, 32000, etc.
  • Indirect hit: If you hit the ground near a target, the explosion from your shot may destroy the target anyway. But you will lose your consecutive hit score multiplier, since when your shot hit the ground, technically that was a miss. This will score you 1000 points, and count as your first hit on your next consecutive hit multiplier.
  • Bonus timer: There is a timer in each level, and if you manage to destroy all the targets before it expires, you’ll get bonus points.
  • Perfection bonus: If you mange to hit all the targets in a level without missing (all direct hits), you will earn a perfection bonus. The base perfection bonus is 10000 points * the number of hits scored in the level, raised to an exponent equal to the number of Planets in the level. This is how you get the truly astronomical scores. If you get a perfect bonus on a multi-planet level, you deserve it.

Winning and Losing

The only way to lose in TARJECTORIES is to accidentally shoot yourself. This can happen if your shot orbits your planet and comes back around to hit you, or if your planet is rotating fast enough that it puts you in the path of your shot as it falls back to the ground. Don’t do that.

To win, you must complete every level of the game. You can play again; the game will be re-randomized on your subsequent re-plays.

Download TARJECTORIES

TARJECTORIES is currently able to run on Windows.

The source code is also available for you to download, if you wish.

TARJECTORIES was built using GameMaker Studio 1.4, Bfxr, and Audacity. It took about 22.5 hours of development time for me to built. Everything was built from scratch, by me.

Version History

1.0.0.0

Initial release

Bug reports:

  1. One user has reported a bug whereby two worlds appear on level 1. Unable to replicate. There should be no way for more than one world to be created on level 1, and even if there were, the oPlanet object has collision detection with other oPlanets, and re-positions them in the event of a collision until they are no longer in collision.
  2. FATAL ERROR in
    action number 1
    of Step Event0
    for object oGround_explosion:Push :: Execution Error – Variable Get -2.t_angle(100033, -2147483648)
    at gml_Object_oGround_explosion_StepNormalEvent_1 (line 11) – ex.t_angle = other.t_angle;
  3. Stats tracker fails to count a miss when a shot destroys itself due to timeout.
1.0.1.3 Bug fixes:

  1. Stats tracker fails to count a miss when a shot destroys itself due to timeout. FIXED.
  2. oGround_explosion error referencing non-existent other in Step Event when a collision is detected with a target. Replaced other with the id of the target instance.
1.0.2.4 Numerous tweaks, mostly to the level_timer, minor bug fixes, and polish.
1.0.3.5

“GE” edition released. Feature complete.

1.0.4.8 Fixes the graphical bug some users were reporting where on the first level it looks like there’s two worlds overlapping each other. The bug was the result of using surface and draw functions in the Create event, rather than in the Draw event where they belong. I guess it affects certain users who have certain video cards, because I was not able to replicate the problem on my machine, but a user who did experience the bug confirmed that it was fixed by this release. Final build for Compo entry.

Ludum Dare 36 is at an end

Ludum Dare 36 is officially over with the close of the feedback phase tonight — a bit anti-climactically, as there was no ratings given this time around. Only comments were given, through the new Feedback Friends site.

The ratings system was given a rest as it’s been decided by the powers-that-be that it isn’t working any more, and has more problems than it was worth. But I really liked to have a quantifiable method of comparing my games to others, and seeing my progress from compo to compo. Of course, I fully understand that the numbers are highly subjective and that the ratings shouldn’t be taken seriously, for many reasons (judges being biased, judges not being able to cover the entire competition, etc.) but none of that really mattered to me.

I would have really loved to have known how Ancient Technologies would have done in the rankings if they had done them this time. While I think the lack of originality in creating a simulation in homage to Atari 2600 Asteroids likely would have hurt it overall, I think it would still have fared decently as a well-crafted interactive experience, and done considerably better than my previous submissions in many categories.

I hope they have a new and improve rate and rank system in place by LD37. The most important thing about the rankings system was that it made it easier to find good games. No matter how many times I sift through the submissions, I always miss some great games. I know because I always find out when the rankings come out and I look through the top 10 or 20 games, find some titles that I never spotted even when I looked through every page of submitted games, and invariably these are pretty well done, the 48 or 72 hour creation time notwithstanding. I did find a few games that I felt were well worth playing, some of them truly great, but I’m sure I missed many others, and that’s too bad because without the ranking system, I don’t know how else I’ll find them.

As for the comments, I gave 85 comments, earning me 163 “coolness” points, and an overall balance of 105 coolness; the top-ranked coolness game on the Feedback Friends site had 121 net coolness, so I feel like I was pretty cool this time around.

I figured out that a comment’s point value basically varies by 1-3 points, depending on its length. Follow-up comments on an entry where you’ve commented already earn you 0 points, no matter how long they are, so they’re encouraging you to review as many games as you can, but not to have lengthy conversations with any one creator. To get the most credit for your feedback, then, your first comment should be a long-ish, multi-paragraph length. A quick one liner will only get you 1 point; a few sentences will give you 2 points.

My game Ancient Technologies received 37 comments, all of which were very favorable, and I think objectively speaking this game was my best-made effort I’ve created to date. I think a lot of LD48 reviewers are just naturally friendly, encouraging, and generous when leaving comments, and are reluctant to say that they don’t like a game. Even when I’ve played a game that was just terrible, I often see many positive comments and compliments. But I, for one, think that if there’s a problem with a game that it should be talked about honestly. Otherwise, feedback only serves to stroke the ego and doesn’t help you get better where you need to.

I get bug reports pretty reliably, which is very good; but if something sucks, people don’t seem to be willing to say that. If there’s serious design or implementation problems beyond a simple bug, people don’t seem to be forthcoming with that kind of criticism. If the game crashes, or if some feature described in the game description doesn’t work, or if there’s an obvious glitch with the sound or visuals, I’m sure to hear it; if I just made a game that sucks, wasn’t well designed or implemented, or wasn’t very fun, people don’t want to say that.

I guess that it’s refreshing in a way, considering how oftentimes comment sections are cesspools of abuse, and I’m not saying that I want to see abusive comments on my games; but I would definitely appreciate if players who give feedback on my games cared about them enough to offer suggestions on how to make them more fun, and to do that by pointing out a problem with the game and a proposal for how to fix it, wouldn’t be bad. Even if the suggestion isn’t one that I agree with, I’d rather hear that. Better some negative points than all positive encouragement, yet empty of criticism.

 

Ludum Dare 35

Ludum Dare 35 happened a weekend ago, and although I published a postmortem on my LD48 blog, I haven’t posted here about it.

The theme for this one was Shapeshift. The first idea I had was to do a game that played like the arcade classic Asteroids, but where your ship’s shape would shift according to its state. I did a quick proof of concept Friday night, where the ship stretched under acceleration, and while it was a pretty cool effect, it wasn’t really something that made the game better or more interesting than the original. By late Friday I was convinced I was on the wrong track, and should start over with something else, but wasn’t sure what.

Saturday morning, I woke up and briefly considered just giving up my efforts for the weekend, and working on other stuff with my weekend time. In the afternoon I attended a Cleveland Game Developers “Excuse to Create” event, and started over with a new project. In the morning, I’d thought about another arcade classic, Robotron 2084, and I started getting interested in making a twin-stick arena shooter. In part I was spurred by the discovery that the keyboard for my new Lenovo ThinkPad P50 laptop has poor rollover characteristics, which make playing games on it all but impossible. I started building it at Excuse to Create and by the end of the 3 hour session I knew that I was on the right track. What I ended up with was much closer to a Geometry Wars clone than I had originally wanted, but it plays pretty well and I had fun making it.

I would have preferred to come up with a more original concept than that, but oh well. It’s not an attempt at a straight up clone of Geometry Wars, but more of a knock-off. The shape-shift theme comes into play with the target shapes, which “lose a side” when shot and shift into the (N-1)th sided polygon. This gives the larger shapes a kind of “hit points” which makes them take several hits to completely destroy. I thought that would be a novel enough twist, but in practice it plays feels about the same as the original Geometry Wars.

Along the way I learned a few things, all of which are game design rather than programming lessons.

  1. At one point in my development, I had the power-up items be vulnerable to the player’s shots, and also if the player shot a power-up item, they would lose one level of that power-up. This would have made the game a lot different from Geometry Wars, where it’s safe to shoot indiscriminately because your shot has no bad effects in that game. I had hoped that this change would make my game more about aiming and looking where you are shooting, and being careful. But in testing, it just made the game too difficult. As the difficulty of the game ramps up, it becomes a frenetic twitch game where you mostly dodge and run away from a swarm of shapes that are following you, and there’s not really any opportunity to be selective about when you’re shooting or where you’re aiming, and if you do lose a level of power-up, it’s pretty much instantly lethal.
  2. Spawn location matters. I knew that I needed to spawn enemies far enough away from the player that they would not be prone to crashing into a newly spawned instance that appeared directly in their path, leading to unfair death. But I also learned that spawning near the edge of the view makes the game seem more active, and puts more instances in view especially in the opening seconds of the game, when there are few objects and the pace of the game is slow. The compo release has enemies spawning randomly anywhere in the room, and as a result feels much more sparse and too slow during the opening.
  3. Code mistakes can be fun! My original code for spawning a swarm of enemies accidentally placed them all in the exact same location. Since the movement of the enemies is purely deterministic, this resulted in a “stack” of enemies all piled up on top of each other, looking like a single instance. When shot, instead of destroying the entire stack, the bullet would only destroy the first instance in the stack, and the rest of the stack would continue to advance, looking to the player as though a early-invincible “super shape” that took a great many shots to destroy was inexorably running the player down, and the player’s shots merely chipped off lesser shapes, which then joined in the attack. I liked the effect so much that after fixing the swarm spawn code in the compo release, re-added a toned-down version of this to the post-compo branch.

In looking back over my Ludum Dare games, I’ve come to realize that I’ve felt overly negative about my performance in LD48. I do have high standards for what I think makes a good game, and so naturally I feel disappointed if my efforts fall short of that mark. In my first few events, I was happy just to have proven to myself that I could build something playable in under 48 hours. In later events, I became disappointed that my abilities didn’t improve as fast as I wished they would. And, really, unless I take game development as a full-time occupation, it’d be hard to improve as fast as I would like. But perhaps an even greater sense of frustration has come from my inability to come up with a good idea for a game — or rather, a good idea that I could complete with my abilities in 48 hours that fit the announced theme. Particularly after the submission deadline, when I’d see so many good games produced by others. But if I focus on the 8 games that I did complete, rather than the 6 LD48 events I didn’t submit for, I’m able to view my work more positively. In the immediate aftermath of the event, I would always feel a certain amount of frustration and disappointment in some aspect of the game I’d made — some feature I struggled too much with implementing, some stupid bug that I got stuck on that took too much time to fix, some feature I had to drop for lack of time, something that was missing, but I couldn’t figure out what it was that the game needed, or something that just wasn’t quite right. But looking at what I have produced, there are some good ideas in six of the projects, and I’m happy about that.

>>> Play Shape Struggle <<<

Ludum Dare 31 best plays

Theme for LD31 was Entire Game on One Screen. I’ll be posting capsule reviews of the games I especially liked, adding more as I find them.

Ricochet Heroes35477-shot0[1]

Although it doesn’t fit the theme too well, this is a fantastically well done, unique hybrid of JRPG and video pinball, which pays homage to the original Final Fantasy on NES, and various other NES homages, too.

Welcome to Shady Pines

45848-shot0.png-eq-900-500[1]

Tetris-y digital jigsaw puzzle game played against the clock, with a sense of humor. Really addictive.

birdsong

3479-shot0[1]Another strong showing by Managore, aka Daniel Linssen. Birdsong is the most interesting take on the theme that I’ve seen so far, instead of taking the theme as a constraint, he has crammed an entire metroidvania style side scroller into one screen, and made it playable via a fisheye lens shader effect that zooms in on the part of the game where you are playing. It’s a unique solution that turns the constraint inside out, and makes the game more challenging, both in terms of coping with the visual distortion as things slightly out of view come in, and in terms of providing a tantalizing glimpse of the entire game to the player, from the beginning, and teasing them about what’s coming up, puzzling them as to how to get there. I’m super impressed with this one.

Rudolph

18775-shot0.jpg-eq-900-500[1]

A humorous snowball fight game between Santa and his renegade reindeer. The gameplay is simple and straightforward and very fun. Light on challenge, but delightfully lighthearted to play.

Contact Cowboy

35879-shot0.png-eq-900-500[1]

An asymmetric 2-player vs. game, the player with the knife has to complete a mission that the player with the revolver has to stop. What makes it unique is that the Knife player is able to blend in with a group of civilians, and if the Cowboy shoots the wrong person, he loses automatically. It’s similar in that regard to my much less polished LD31 entry, Color is Everything.

 

 

Color Is Everything: a Ludum Dare 31 Post-Mortem

Originally published here.

Play Color Is Everything

Preconceived notions

Going into this weekend, I knew I wanted to make a game that would serve as a statement about the intolerable state of civil rights in the present-day United States. It seems like almost every day there’s another story about police using excessive and all too often deadly force, often unnecessarily or for very little provocation. We live today in a police state where citizens rights are routinely denied, due process and the right to a fair and speedy trial have been forgotten, and out government doesn’t merely seem unwilling or incapable of doing anything about it, it refuses to do anything about and then punishes those who speak out and demand it — as evidenced by a mockery of a Grand Jury investigation into the police shooting of an unarmed 18 year old named Michael Brown in Ferguson, Missouri, last month, and a 12 year old boy in my home town of Cleveland, Ohio that happened just as the news hit that there would be no trial in the Michael Brown shooting incident. No trial, and then force used to break up peaceful demonstrations which turned them into riots.

One of the finalist themes was Color Is Everything, and I thought that would work perfectly if it was chosen, but for some reason I didn’t expect it to — I just never feel that lucky, I guess. So I looked at the other themes and considered how I might fit my protest statement into a game that satisfied the other themes, and I thought that I could use “Entire game on one screen” if it came up, but I never expected that it would. When it did, I was surprised, but happy because out of all the other themes it was the one that afforded the most freedom of game concept, so long as I could fit everything on one screen.

Design

In designing the game, I focused almost exclusively on the message that I wanted to send, and the actual game play was secondary. I wish I could have spent more time on refining the game, because as it is I don’t feel that it plays very well. But I needed to be very careful about the content of the message. I’m not sure if I got it right or not, but I tried as best I could to come up with a statement that I could put into a game that I could create in under 48 hours.

Early on I choose to sacrifice graphics, and go with a purely abstract game. I did not want to sensationalize with blood splatter, and after briefly considering creating animated anthropomorphic figures, but worried that whatever I might create in a short timeframe would be insufficient and might resemble offensive stereotypes. I decided to go fully abstract and use simple squares of symbolic, literal black and white to represent my people. While it was very easy to make, it afforded me time to consider how to put the message I wanted into the game. I wanted to drive home the point that you can’t tell whether a person is a criminal based on their appearance, that it is their actions that make a person a criminal. Although, really, crime is almost incidental to the reality I’m depicting — the game is really about a dystopian society where police who are sworn to protect and serve the public are allowed to get away with killing people because a corrupt system looks for any excuse to look the other way when they happen to be black.

I had a basic idea that you’d be a policeman, and you’d just patrol around on the screen while people stood about or walked around, and you’d have to figure out who among them is a criminal, and then try to arrest them or, if you wanted, you could shoot them. I gave the game three ending conditions: if you run out of bullets, if you are killed, or if you kill an innocent (white) person. And I implemented a scoring system which I felt reflects the real-world valuation we place on white and black citizens. Arresting or killing a black innocent has no consequences in the game. But arresting an innocent white person deducts points, while killing an innocent white person ends your career in an instant.

Keeping score

I struggled quite a bit with figuring out how to value the arrest and kill scores for black and white criminals. In the end, I took a base value of 100 points, because it’s a nice, round number, and then I adjusted it to reflect the bias in the legal system. I don’t know how well I did, there, but here’s how I came up with the point values: Using wikipedia, I found an article dealing with race and crime in the united states. In it, I found that the data presented in the article was fairly messy, taking numbers from different years, etc. but it said that the incarceration rate for black males is 4749 per 100,000 — about 4.8% of all black men in this country are in prison — while the incarceration rate for white males is only 487 per 100,000, or about 0.5%. I also needed to adjust for the proportion of the population that these groups represent. According to the 2010 US Census, the population classified as white represents about 63% of the total population, while blacks represent about 12%. Multiplying these percentages together, I got 0.63*0.05 = 0.00315, and 0.12*0.048 = 0.00576. Dividing these two numbers into each other, I got 0.00315/0.00576 = 0.546875, and 0.00576/0.00315 = 1.828571428571429, which I rounded to 0.5 and 1.8, respectively. I took those numbers and multiplied them by the base point value of 100, to make a black arrest worth 180 points, and a white arrest to be worth 50 points. Coming up with these numbers gave me a sick feeling.

Killing a person scores much 100x as much points as arresting them, to reflect that ending a person’s life is a higher stakes proposition than simply arresting them. Perversely, this creates incentive to shoot people, if you’re going for a high score, and for the highest score, to preferentially seek out black targets.

I never tell the player that they ought to try for a high score, but I allow the structure of the game to suggest to the player that this is what they ought to do. I expect that most people will try to play this way at first, and perhaps if they think about what the game is telling them, they might try not to shoot as much. It’s possible to play with a strategy of only arresting people, although you will score much slower, you can play longer as long as you manage to avoid being shot yourself by criminals. If you don’t care about arresting the wrong people, you can probably survive indefinitely, and in the long run the extra points you get for arresting black criminals will outweigh the penalty incurred for arresting innocent white people. In thinking about this more, it makes me question why I gave the population equal proportions of black and white people, and criminals and innocents. It might have been a more accurate simulation to give these populations the same proportions as the census and crime statistics show. But while the census figures are less likely to contain institutional bias, the crime numbers really only track incarceration, not criminality, and I don’t know where to find numbers that would reliably measure the proportion of a population that are criminals, broken down by race. So, it’s a limitation of the design, I suppose, but I’m not sure how to do better there. If I had done this, though, it would have pushed the bias toward targeting blacks much higher, because white criminals would be very rare, white innocents would be very common, and blacks would be the only safe targets for arrest and/or extra-judicial killing. This might need to go into the post-compo update, if I continue developing the game.

To provide the player with a bit of incentive to use their gun, I gave the criminals guns as well, with which they can commit murder, and some of them will try to shoot you, so there is some of the self-defense and defending the lives of others in the game, just as it is talked about in the real world whenever one of these shootings takes place. If I had to do it over again, I’d probably use the crime statistics tracked in the game to penalize your score, so that you would have a bit more direct reason to try to identify and stop the criminals. This will probably be addressed in a post-compo version as well.

The Play Experience

My process in coming up with this design was slow and meditative, so I probably spent more time thinking about the design, what it implied in terms of the message it would send, and then carefully creating a design that imparted the right message. Comparatively speaking, I spent very little time actually playing the game, and I think that shows in the play experience. I’m not really satisfied with how the game plays. The AI is extremely rudimentary, and if you allow the game to continue spawning people and don’t wipe them all up by constantly arresting or killing them, very quickly it gets to the point where there’s too much happening on the screen, and you can’t take it all in, which makes your decisions and actions less meaningful. As well, when the screen fills up, very quickly you end up accidentally colliding with people who are walking around oblivious to you, and obviously that removes the aspect of intentionality from the act of arresting them, detracting from the game’s message.

I think, if I did the design over again, I’d try to make the game slower, so that the player would be able to think about their actions and decide to do them, rather than react in a twitchy manner. Perhaps I’d reduce the number of people that can be on screen at one time (there’s currently no limit, which is bad), and I might also slow down the action so that only a smaller number of people are actively doing anything — I considered making the AI’s move in a turn-based fashion, so you could have time to monitor each individuals actions and try to figure out if they’re a criminal or not, which would give the game more of a detective-y feel to it. I’d definitely like to improve the AI a bit more so that it would make the game less random.

Overall, I’m not all that satisfied with the game as a play experience, I think it could be much better — but working on the project allowed me to work through my feelings on the current events. And, working through those thoughts was a more necessary thing for me this weekend. There’s a lot that is wrong with our country right now, especially in government and law enforcement. Reform is badly needed, and seems like a remote possibility at best. It seems like the system of checks and balances, and the rights that we are all guaranteed exist only on paper right now.

Interview: Daniel Linssen

Daniel Linssen is an indie game developer who lives in Sydney, Australia, who I came to know after playing his first Ludum Dare creation, Javel-ein, for LD28. After releasing the full version of Javel-ein, he was cool enough to reach out to me to let me know of its existence, since I had so enjoyed the version he had made for LD28, and since then we’ve corresponded regularly and become digital pen pals. He is also the creator of Busy Busy Beaver (which won Bacon Jam 07) and FFFFFF for Flappy Jam. His most recent game, The Sun and Moon, recently won first place in the Overall category for Ludum Dare 29.

CS: Thank you for agreeing to do this interview. Ready to begin?

DL: As ready as ever!

CS: First, do you prefer to be called Managore or Daniel? What does the name Managore mean?

DL: Daniel. In the past I liked having a unique identity while still being anonymous, but I’ve given up on that.

Fun fact: For a long time “Managore” was absolutely unique. Then a year or two ago a Bulgarian company released an online game called Managore and my uniqueness was lost. Oh well!

The name doesn’t really mean anything. Years ago I started writing a (really terrible) sci-fi novel and one of the characters, some sort of biological experiment, was named Managore. And the name stuck.

CS: How did you get started making games? How long have you been doing it?

DL: The earliest example I can think of is as a kid I designed some Sonic The Hedgehog levels on paper. I think I was around 8 at the time.

CS: That’s something I used to do as well, designing games on paper. I think I did my first game concept when I was six or seven…

DL: I’m pretty sure the levels I designed would have been terrible. I hope yours were better!

CS: Nah, the stuff I drew up wasn’t that sophisticated. I’d do a drawing of a screen shot, and then narrate the rules and the player’s goals, point values, etc. and my mom would write them down for me. I didn’t do anything so sophisticated as a full-blown design doc or anything. It was just about the enthusiasm and instinct to be creative, and wanting to do it for real someday.

DL: There’s an old DOS game called Jetpack and I spent a long time using its level editor. The idea of a level editor was pretty novel for me at the time. Over the years since then I’ve played around with RPGmaker, C++, Valve’s Hammer Editor and Flash but never made anything that I could really call finished.

CS: What game projects did you work on previous to your first LD game?

DL: Well a whole bunch of unfinished or unreleased games, unsurprisingly. Actually the only games I’ve released so far have come from game jams. My first experience participating in a game jam was three years ago, I was working with a friend of mine. The game we made was a one screen rhythm platformer for Reddit Game Jam 05 (the theme was “love”) called Give In. I worked on the player controls (which are way too slippery) and the graphics (which I still kind of like the look of).

After that I started using GameMaker and worked on some exploratory platformers which will probably never see the light of day. Then, half a year ago I took part in the Bacon Game Jam 06 (the theme was “rainbows”) and made an action platformer called Violet, which I think of as my first “proper” game, if you can call it that.

CS: How do you approach a 48 hour event like LD? How is it different from when you are working on a game without external time constraints?

DL: I try to start off well rested but that’s about it. Sometimes I have an idea of what aspects of the development process I want to focus on or improve on. Once I have an idea and I start coding, autopilot tends to kick in.

CS: OK let’s talk about The Sun and Moon. I’ve just read your post-mortem article on the making of it, so hopefully we won’t rehash too much of that. I encourage readers to check it out for themselves.

First, let me just say congratulations on another fantastic game. For the record, out of 1493 entries for the LD29 Compo, you placed 1st Overall, 1st in Theme, 2nd in Fun, and 3rd in Innovation. This was just your second LD entry! Obviously, no one expects to win a category, but how well did you think The Sun and Moon would do when you finished it?

DL: Well I went into it hoping to make a game which I could be as proud of as my previous LD game, Javel-ein, and I think I achieved that. When I finished, I was really happy with how things had gone. Everything (well, except the music, but I was too tired to realize that at the time) had pretty much falling into place and the game’s mechanic ended up being a lot of fun. I was lucky not to run into any major hurdles along the way.

My hope was to get a medal in some category but I knew there were so many utterly fantastic games to compete with, so it was always something I was hoping for but never really expecting.

CS: How does it feel to have won the Compo?

DL: It feels amazing. I couldn’t believe it. It’s a dream come true.

CS: What does the title, The Sun and Moon, mean?

DL: Good question. I have all these good answers for why I chose “Violet” and “FFFFFF” and “Busy Busy Beaver”, but I don’t really have a good answer for The Sun and Moon. I was really struggling to come up with a unique and meaningful name. I had all these ideas written down. They’re pretty bizarre so they might be entertaining to read:

A World Divided, The World Beneath, It Spoke Quietly And No One Heard, A Hollow World, The Sun and Stars Both, The Sun and The Moon.

If you’re curious about ISQANOH… I honestly have no idea. I liked the sound of it.

Anyway, because it is such an abstract game, at least as far as my games go, I wanted the name to be up to the player’s interpretation, but I did have a reason for choosing “The Sun And Moon”. As I was developing the game I realized I needed to make the player change appearance while underground, and from that point onwards the player kept reminding me of the Yin and Yang concept. The dark version which falls and the light version which rises. The air and the ground. Complimentary forces. And one representation of the Yin and Yang is the Sun and Moon, so I went with that.

CS: Yeah… what was interesting to me about the title was, there wasn’t really any literal sun or moon in the game! I wondered about that, and was interested to hear what the story was, if there’d been some plan to get them into the game but you ran out of time, or… if, like the Sun and Moon were just metaphorical somehow..

DL: I worried that people might find the name a little too… artsy? But as far as I know that hasn’t been the case.

CS: I think it’s a fine title!

CS: The core mechanic of The Sun and Moon is to traverse a series of obstacles by selectively passing through solid platforms. How did you come up with the idea? How long did it take you to refine the specific mechanics (requiring a jump/fall to pass through the floor, buoyancy within a solid platform, the acceleration/momentum upon ejecting out of a solid platform, etc.)

DL: It just sort of came to me, after a long string of bad ideas. I was thinking about a bubble in a world made of water and air, and the idea evolved from there. I had a pretty vivid image in my head early on of diving into the floor and shooting up into the air and from that point I felt like I had come up with something fun. I stuck with that mental image and built the mechanic around it.

Originally you didn’t have to jump to pass through the floor. I planned to make the player “wobble” up and down if you were standing on the surface and held down the action key. The way I happened to code it meant that when you held down the action key, since your vertical speed was zero, the “wobble” wasn’t there. This worked well enough so I just left it that way.

CS: At what point did you realize you were on the right track?

DL: When I started making the levels. I posted a gif of one of the first levels I made and the responses were really encouraging. The more levels I made, the more content I was with how my game was going.

CS: How long did it take you to build the basic engine?

DL: Surprisingly not long at all. I mentioned it in the post mortem but I made a movement and collision engine called the Beaver Engine which I used as my starting point. The Beaver Engine is a stripped down version of Busy Busy Beaver, one of my previous game jam games, which took about 12 hours to write the code for.

It took a little rewriting to add in the underground physics and make it all work properly but overall the basic engine was pretty painless.

CS: What design decisions were hardest to make?

DL: We’ve already talked about it, but the name! I was actually starting to panic a little towards the end because I couldn’t come up with a name! Oh, also the player’s trail. I went through five or six iterations before I found something I was happy with.

CS: What features/ideas did you drop from the game?

DL: I’ve started to get a pretty good idea of how much I can realistically get done in a game jam, so I kept my feature list pretty minimal. I actually had time near the end to add in a few features such as the level select screen, which I wasn’t originally planning on including.

Speaking of features I wasn’t originally planning on including, I should definitely mention how much of an absolutely huge help it was having you give the game a go a few hours before the deadline. I remember you saying you wish there was a way to know which level you were on, which led to the level number appearing at the beginning of each level, and you said it would be useful to know which level had been played last, which led to the player sitting on top of the last played level in the level select screen. These were really important features that I wouldn’t have thought of at the time.

CS: Absolutely! It was an honor to have been asked, and to be able to provide a little feedback so you could refine the finishing touches on the game that ended up taking 1st Overall. I remembered thinking right away that it was a very strong entry, and I liked it from the first couple levels. I had the idea about the level numbers because when I was giving you feedback, I didn’t have an easy way to reference which level I was talking about. So it was a fairly obvious suggestion.

DL: Fairly obvious to anyone but me! I guess it just really helps to have a fresh perspective with an eye for what’s important.

CS: True; when you’re in the final hours before deadline, your focus tends to be on the most critical elements of the game, and finding bugs. Being able to look at the game with a fresh perspective just isn’t possible, so it’s valuable to be able to get feedback from someone who hasn’t been staring at it for the last 40+ hours!

How would you compare The Sun and Moon to your other games, Javel-ein and Busy Busy Beaver?

DL: Well I knew while making BBB that it just wasn’t going to be that innovative, so I focused on making it fun and silly and pretty. For The Sun and Moon I went the opposite direction and focused on making it unique and innovative, at the expense of a story, detailed graphics and humor.

And then Javel-ein is sort of a blend of the two.

CS: This game focuses on mechanics rather than story, and, I think, stands up well on those merits. Have you thought about adding story elements to the game, or do you plan to leave it abstract?

DL: I’ve thought about it, but I honestly don’t know what direction I could take it.

CS: Your sense of level design and mechanics for 2D platformers is, if I may say so, pro quality. Can you describe your process for designing levels?

DL: In general, if I have a game mechanic to work around, I try to explore that mechanic in as much depth as possible. For The Sun And Moon, I looked at all the different types of movement that the mechanic allowed for (e.g. diving down into the floor, jumping up and through a block, falling off a tall platform and diving deep into the ground below, jumping through a thin wall, jumping into and up through a block) and came up with levels that made the player use these tricks. I wrote all my ideas down on paper first since I’d often have multiple levels ideas come to me at once.

CS: Do you have interest in making other types of games than 2D side scrolling platformers?

DL: Definitely! I think it’s just been the case that the ideas I’ve had that have worked the best have always been tough platformers. On the backlog I have a color-based puzzle game I’ve been working on as well as an idea for a top-down naval exploration game.

CS: The art style of The Sun and Moon would be best described as a minimal, GameBoy style. But it works very well, especially the “clouds” in the background. How did you come up with the idea for them?

DL: For the clouds? Early on the background was a solid color, and I realized that if you flung yourself really high into the air it was impossible to tell how fast you were going. To fix this I decided to add a parallax background in. My game, with its monochrome palette and dark-foreground-on-light-background style, already looked far too similar to Luftrausers, so I wanted something abstract and different.

When I was coming up with the idea for my naval exploration game I experimented with perlin noise and other techniques to generate a huge ocean with lots of islands and interesting coastline, so perlin noise was still fresh in my mind. Because Photoshop’s “Render Clouds” filter creates tileable perlin noise I knew I could use that to quickly make a suitable background.

CS: Interesting that it was a feature driven as much by gameplay needs (having a reference so the player could gauge their speed) as much as cosmetic needs. Visually it’s a very pleasing effect!

How much have you added to the game post-compo?

DL: I’m up to 67 levels at the moment, though I lot of the newer ones still need some work. I’ve added controller support and made the game run on mobile devices. I’ve added a timer for each level that records your best time. I have a lot of ideas for mechanics that could add variety to the gameplay and I’m currently playing around with these to see which ones work the best.

CS: Wow, sounds like you’ve been busy! What are your plans for developing the game further?

DL: Even more levels! However many I can come up with while making sure each level is still unique and fun. I’ll work on the visuals a little bit but I want to keep it looking minimalistic.

More importantly, the music is going to be completely redone.

CS: How about some technical questions?

DL: Sounds good!

CS: You use GameMaker: Studio for your games. Do you work with any other programming tools or environments? What do you like about GM:S? What do you wish was better?

DL: Not at the moment. I think what I like the most about GM:S is that I’m so familiar with it. And that it’s very easy to prototype new ideas. There are, unfortunately, a lot of things I wish GM:S did better. The built-in level editor leaves a lot to be desired, the program occasionally crashes and I lose progress, Windows builds and html5 builds can be wildly inconsistent, and a lot of other, smaller issues.

CS: How did you get into GameMaker?

DL: Two of my favourite games, An Untitled Story and Spelunky, were made in GameMaker. They inspired me to begin making games seriously so I guess I thought it was a good idea to use what they used.

CS: Are you active on the GMC forums? Are there any other good sites for game development that you frequent?

DL: Not at all. I browse /r/gamedev and /r/indiegaming on reddit, but that’s about it.

CS: You mentioned in your post-mortem that you experimented with a couple of different motion trail techniques, before settling on a line drawn out behind the player. How did you make the line taper?

DL: Okay so each frame an object is created. This object stores the players current location (x,y) and the player’s previous frame location (x_p,y_p). The object draws a line from (x,y) to (x_p,y_p) of a certain thickness, starting at 5 pixels and decreasing by half a pixel each frame. So, at any one time, the trail is made up of 10 objects, each drawing a line of varying thickness.

If the player is underground it’s a little different. It still creates objects which store the player’s current location but these objects draw a circle instead of a line, and instead of the circles shrinking their visibility is decreased each frame.

CS: Thanks to gravity acceleration, you can achieve some pretty high vertical speeds. Was it a problem to handle collisions at such speeds? Did you have to do anything special to make it work?

DL: Good question! Because every object in the game (except the collectables, come to think of it) is 16 by 16 pixels, I only needed to make sure that the player never moves more than 16 pixels each frame, so I set the terminal velocity to 14 pixels a frame, just to be safe. I think the terminal velocity is pretty hard to notice in general.

CS: Is there anything else you’d like to say?

DL: Only that participating in Ludum Dare has consistently been a fantastic experience.

CS: I have to agree. Not just making games and having other people play them, or even getting to play a lot of cool games made by other people, but getting to know a few of the people in the indie scene, both through their work and through actual correspondence. Perhaps that’s been the most rewarding part of it all. Congratulations on your accomplishments, good luck in the future, and thanks for taking the time.

DL: It was my pleasure, thank you for interviewing me!

 

Ludum Dare 29 results

Voting results for Ludum Dare #29 were announced earlier tonight. My Jam entry, Alamagordo, fared pretty well, considering:

Rank (of 1004) Category Score (of 5)
Coolness 100%
#69 Humor(Jam) 3.60
#110 Theme(Jam) 3.70
#424 Mood(Jam) 2.97
#546 Audio(Jam) 2.53
#581 Graphics(Jam) 2.80
#592 Innovation(Jam) 2.52
#648 Fun(Jam) 2.33
#662 Overall(Jam) 2.58

The 69 and 110 rankings are the best that I’ve done so far in a Ludum Dare judging, narrowly edging the #70 ranking I received for Humor in my LD25 game, Bad Puppy.

Considering that Alamogordo was a last minute entry that I threw together in about 10 hours development time, and was intended as more of a joke entry than a game with ambition, I’m pretty pleased at how it was received, overall. I was going for humor and theme, and the other categories weren’t as important for me — I only cared about making the game look, sound, and feel like an Atari 2600 game, and I’m reasonably pleased with my work in that regard. It’s admittedly not very fun to play, nor innovative, nor very good overall, so I feel like my scores are pretty fair overall. I was also very pleased by the fact that I was able to build the game very quickly, with no false starts, rework, or getting stuck in debugging. In my previous LD games, I often found that I’d get stuck on a technical problem that should have been easier to solve than it turned out to be, I think mainly due to self-imposed pressure. This time, I felt mentally unhurried, confident that I was capable of doing what I had set out to do, that I knew how to do what I was doing, and didn’t have to spend any amount of time experimenting and figuring it out, and that helped me to build a clean, well-organized project. Although the game isn’t much, I’m pleased with the code that I wrote for it.