February 2016 challenge: “The aftermath”

Picking up the pieces - Post Mortem

Posted by telecoda on 2016/03/21 08:55

Thanks for arranging a great pyweek. It was the first time I've completed it and I learned a lot along the way.
Things I learned
i.) Test the build and distribution EARLY. I developed solely on OSX and tried to get a Windows build out of the last day and failed. Much respect for the people who judged the code and got it running. Its hard work judging lots of games and I really should've delivered a working solution. Next time test this early and continuously throughout the week.
ii.) If I entered again I would probably join as a team. Its better to share workload and having several people kicking each others butts is a great motivator.
iii.) Try out the tools ahead of time. Pyweek is not the best time to learn new tools on the fly. But it sure focuses you on the minimal feature set. (Shipping a build with .WAV files for audio to get around not getting .mp3 & .ogg playing on OSX is a big no, no!)
Thanks to the organisers for running Pyweek, I'm sure it quite a commitment to making this happen as a voluntary task.
Thanks for all the feedback on my game. I wholeheartedly agree with ALL the comments. (Sorry for belittling the subject of the Blitz this was not my intention)
Well done
Well done to the winning teams. I'm amazed at the amount you guys packed into a single weeks development, truly inspiring.

Add a comment

The Last Gardener - Post-mortem

Posted by Jjp137 on 2016/03/20 19:58

The judging period is over, and I'm glad that people had fun with the game. With every PyWeek I participate in, there's always lessons to be learned and traps to avoid for next time.


As I said before, unlike my previous individual entries, this entry was a team entry. I asked my friend, whose username is LegoBricker, if he wanted to join, and he figured that he'll have enough time throughout the week to help out with the game. We both started the week by programming, but I ended up doing most of the gameplay logic and the level design, while LegoBricker primarily worked on the game's appearance by finding the majority of the assets, modifying them to fit the game's needs, and making sure that they showed up in the game. He also did the story sequences and created the images associated with them. I laughed the first time I saw the introduction and ending, and I'm glad that some of you found the plot amusing :)

If my next entry ends up being an individual entry, I should take a page from my friend's book and use public-domain images from Wikimedia Commons as the basis for some images if it's appropriate for the game. That was rather clever, and I never would have thought of doing that.

This entry was also different because it used pyglet, which neither of us were familiar with. Speaking of pyglet...

Pyglet, AVBin, and the future

...well, I did have a feeling that AVBin was going to cause problems for some people, sadly :( I don't know how much I can do about that, though. I'm not really fond of how someone has to go out of their way and download a separate installer just to get music and sound to work, but oh well.

The main reason we went with pyglet instead of what I knew, which was PyGame, is mainly because LegoBricker uses Mac OS X. There are a few problems related to the latest OS X version (El Capitan, at the time of this writing), such as this one that I'd rather not have him, nor anyone else, deal with.

Either way, I thought that pyglet was a good framework to work with. We had to learn a lot about it during the week, but the learning process wasn't too bad. Working with sounds and music with it is probably my least favorite part about it, I suppose, but everything else worked fine for the most part. Having a sprite-heavy game in OpenGL also made using pyglet worth it. I just wish that there was an easier way of drawing primitives since I'm so used to being able to easily draw rectangles in PyGame.

In the future, since SDL 1.2, which PyGame is based of, is old and is no longer really maintained anymore, I might look towards using a library or framework that uses SDL2. There are quite a few SDL2 bindings for Python out there already. It would be nice if there was something like an SDL2 version of PyGame Zero. Of course, I'll have to figure out how to distribute a Python game that uses SDL2 and the 'how to play' instructions associated with it, but that can wait.

Coming up with the idea

So 'the aftermath' was the theme that we didn't initially have any good ideas for. Our ideas for that theme were:

  • A zombie-themed bullet hell game
  • A farming sim
  • Tower defense game where the player has to survive for a period of time

That third idea was actually based on the main idea we had for the theme 'the incantation'. The gameplay would involve the player defending some sort of magician's tower until a giant spell was ready to be unleashed. It would have been fun to make, but maybe we can save it for next time. Or maybe someone here can borrow that idea :p

We were unsatisifed with how uninspiring (and in the case of the third idea, forcefully adapted) those ideas were. Thus, when the theme was announced, we weren't happy at first :p I ended up programming some classes I would need later on, such as a Rect class and some sort of screen manager, but we didn't get around to coming up with the final idea until the next morning. At first, I proposed a combination of the first two ideas. That idea would be a game divided into two phases: daytime and nighttime. During the daytime, it would be a farming simulator where the player can send out people to salvage resources, find more people, and work on the farm. During the nighttime, the player would defend the farm from zombies or aliens or whatever. That would be when the bullet hell gameplay enters the picture.

However, that idea was basically two games, and we didn't have the time to make two games, so we were at a loss for a bit. Then, I remembered watching a YouTube video of a bizarre Touhou fangame in which the main character has to clean up the floor while avoiding bullet patterns. Since one definition of 'aftermath' is 'new grass growing after mowing or harvest,' I basically took inspiration from that gameplay video and made it about mowing lawns while avoiding aliens that have taken over Earth. Therefore, our game fits the theme in more than one way :)

What went right, and what could be better

Well, the game turned out to be fun, and that's the most important part to us :) Of course, I should elaborate.

As one of the judges noted, we liked the constant feedback that the game gave to the player. One of the most important aspects of that is the lawn mowing sound that the drone makes as it moves. It was LegoBricker's idea to implement the sound in that way, and when I pulled his commit from our Git repository and moved around the drone, I was really happy with how it turned out. It really felt that the player was in control of the drone. Seeing the grass get mowed was also satisfying, and before there were enemies and bullets in the game, I spent a few minutes just drawing random shapes in the grass :)

I was also satisfied with the difficulty curve, and it seems that not many people got stuck this time around. Since traditional bullet hell games tend to be very difficult for many people, even on easier settings, I decided early on that having difficulty levels would be close to mandatory. I also wanted to introduce new concepts over time. That's why level 3 is when enemies first change their patterns as the player makes progress, and I delayed the appearance of the big bullets until level 6. I'm curious to know what difficulty setting people played on and how far they got. I think the hard difficulty could have perhaps been left out entirely since, to be honest, I can't get past the third level on hard, but I wanted to have fun with the patterns :)

The only issue with the level design might be that it's probably not obvious to players how the boss battle works. I could have done a better job of communicating to the player that they should just be focused on surviving instead of trying to mow the lawn. Hopefully people figured it out eventually if they got that far.

As for what can be better, well, the code can always be better :) There are a few implementation details that sounded like good ideas in my head but were actually awful ideas in practice. One example is the giant dictionary that is in level_data.py. It sounded like a good idea at the time, and it probably is a good idea if the variables for each level were simple. However, as I added more levels, I kept running into syntax errors, particularly with tuples that contain only one item since the syntax is awkward for them. Even when I fixed the syntax errors, if I passed in the wrong number of arguments for a given pattern, the game would crash once that pattern became active.

Also, I really should have implemented object pooling for the Bullet class. I never implementing object pooling before, and it was the middle of the week before I realized I should have done that, so I didn't really want to break anything. It's something that might require practicing beforehand. The constant allocation of memory for new Bullet objects and the garbage collector having to clean up after the trash that resulted was probably detrimental to the game's performance.

In fact, performance was always an issue since bullet hell games unsurprisingly involve tons of moving bullets and thus a lot of collision detection and position updating. I learned how to use cProfile during the week, and I was able to optimize a few methods and make the game perform better. For example, my initial and horribly lazy implementation of the grass mowing logic checked all ~1000 grass rects at once, but I was able to reduce that number to around 25, if I recall correctly. Also, I noticed that assigning to Sprite.position is better than indvidually assigning to their x and y properties, since Sprite._update_position gets called in all three cases, which is where a ton of time is spent once there are hundreds of bullets on the screen. A lot of time is still spent just moving the bullets around, but it's better than it used to be.

Problems along the way

It's inevitable that participants in game jams will run into some problems at some point, and we hit a few snags along the way. I document them here so that we can try to avoid them next time.

Probably the silliest problem, at least from our perspective, was that the font was missing some commonly used characters. Next time, we should examine the font in something like FontForge first before using it. The font we used was missing some characters such as a single quote or a percent sign. This first came to my attention when I wanted to use a percent sign for the numbers next to the progress bar, but it showed up as a rectangle. I was confused at first, but soon I found out that the font didn't have a percent sign! It didn't have a single quote either, which made writing the story annoying since apostrophes would show up as rectangles instead. It was midway through the week, so it was a bit late to change the font :( The lesson here is to make sure that any font found online is reasonably complete before it's used.

Another problem came up during the last 24 hours when music was added to the game. Shortly after, I noticed that when a lot of bullets are being fired, the music was cutting in and out, which was very distracting. I had LegoBricker test the game on a bullet-heavy level to see if that problem occurred on his computer, and it did more than just occur. The game froze! Of course such a thing would happen on the last day. We tried a few things to solve the problem, but eventually I noticed that the bullet sound has quite a bit of silence at the end, so I asked LegoBricker to trim the file. This seemed to alleviate the problem, at least on our computers. Sadly, PulseAudio didn't like how we play too many bullet sounds at once, which caused me to write that previous diary entry. I thought that we didn't have to worry about the differences between the audio drivers that pyglet supports, but at least there's a workaround for that particular problem.

In closing

One final note: it was amusing to hear the music for the boss level in Tee's game as well :p

Well, I think that's all I have to say. This is rather long, but oh well :) LegoBricker might write his own post-mortem later.

Until next time...

Add a comment

Beam - Beam: Comments on Feedback

Posted by Tee on 2016/03/20 16:53

Thanks for rating my game up to first place in the solo category! This was surprising: I meant this game to be just a short experiment given the little time that I had. I'm glad most of you enjoyed it!

I've already talked about the game in my previous post, so I'd just like to comment on some of the feedback you gave me.

"I keep wanting to move 2D as opposed to 1D"

The previous iteration was actually 2D. I decided to take away one dimension because the laser would end up forcing you to run the shortest distance anyway, and I wouldn't have time to implement obstacles (which was in the original plan). That's also why the room is rotated 45 degrees. :)

"I wish it was a little more forgiving. I died on level 8 and had to start all the way back over like 15 times. Finally beat it, though! :D"

"Honestly, I gave up trying to beat it."

"a bit annoying but it's the point of the game"

"It's a little frustrating. When there's enough debris it's indeterminate where the beams are. And you're reset back to the beginning when you guess incorrectly. The isometric nature the player sprite makes it really hard to tell where you are in terms of the beam grid."

"Only real problem : Really, really, really hard. I could not finish it."

"The game's fairly frustrating. [...] I understand the reasoning behind the reset-to-start aspect of death, but the punishment was more frustrating than anything. Maybe have checkpoints every 3 levels or so and increase the number of levels, so the challenge doesn't drop from 100 to 0 with each death. [...] Maybe a bit unfair in the later stages, but I suppose that's the point."

"It's quite hard to beat this game, I gave up after a few tries."

"very hard to beat"

Ok, I see that the game is clearly too difficult. Sorry about that. But hey, some people beat it, so kudos to those who did. :)

I was in the last hour of the challenge when I playtested it, and I wanted it to be challenging but beatable. It's always hard to balance a game and I may have made it a bit too hard. I personally enjoy challenging games, so I tend to bias a bit to the hard side. My reasoning was that in a game as simple as this one and with quick restarts, it might not be too bad, but I guess I overdid it.

There's a tiny bit of strategy to this game that might be helpful. This is both a guessing and an observation game. One piece of advice is to realize that there are 6 tiles, so 6 possibilities where the beams can hit. I also find it useful to keep in mind the number of beams per level: between 1 and 4, according to the color of the background. For example, in the levels with 4 beams, you know that likely only 2-3 tiles will be safe. And if I realize that I've already spotted the number of beams, I can speed through the rest. Or, in the later levels, if the beginning is sparse, then I know that the end will be full of lasers and I have to be more careful, and vice versa.

"A bit repetitive"

"at the end is playable but quite repetitive"

"Anyway after two level is starting to be boring and very hard to beat. It needs other elements to improve the game experience."

"Tends to get a bit monotonous quickly and loses replayability"

Definitely. I meant the game to give you only a few minutes of fun (hopefully), not more than that. :) Maybe if I had time I would have extended it a bit and made it more interesting.

"I wonder if the levels would have been better if they were more designed as opposed to procedural? But not convinced."

In a more complex version in this game, you're probably right. But procedural levels took much less time to implement, and also, in this simple version, I think if they were designed, it could take away the little replayability the game has. That's a good point though!

"It took me a while to understand the gameplay"

"took me a few attempts to realize how it all worked"

"But still, was unable to understand how to play."

I'm not very good at making it clear how to play my games, even simple one-button ones. Sorry!

On the other hand, I feel like it's part of this particular game dying a few times to realize how the game works. I intentionally didn't tell you how the debris relate to the laser beams because I think it's fun to figure that out.

"I think having the lasers fill the entire squares instead of that thin ambiguous line would've helped with legibility of how far I can actually sprint."

Good point. I kind of like it this way too though, because it allows some room to do tiny sprints between consecutive lasers that "expert" players can do (if there's any concept of "expert" in this game).

"The poor robot; what did he do to deserve being repeatedly lasered"

Haven't you wondered why you see no humans in the facility?

Thanks for your great comments! Congratulations to the team winners and thanks to blakeohare for organizing this Pyweek! See you next time!

Add a comment

Shattered World - 3-D printed versions of game assets

Posted by Cosmologicon on 2016/03/19 20:53

EnigmaticArcher, who did most of the 3-D modeling for Shattered World, just got a new 3-D printer and decided to test it out with a couple assets that might be familiar if you've played the game:

1 comment

Lost Colony - Reflection on PyWeek

Posted by mgrazebrook on 2016/03/15 22:50

I learned a lot working with this team.

I've worked for many years as a programmer including several using Python. Normally I'm the best python programmer around - but only because nobody else does much Python! My last job was as a programmer in a forensic accounting team where hardly anyone else could code. I've also little experience of writing games.

Team Wasabi had some very good programmers. Dan has a few PyWeek trophies and wrote pygame zero, others were brilliant but less famous. Sometimes my code was great - and sometimes I needed to re-think my approach to a problem. As I read others' code, I'd be thinking "yes, that's how I'd have done this ... but I didn't know you could do that". For the first time since I read Gamma's "design patterns" book in the mid 90s, I found myself working with people who used them quite naturally in conversation! Normally design patterns are only interview questions!

It was the first time I've used pyglet, trello and google hangouts. At least agile working methods were familiar.

The project scheduling was uncanny .. we had neither too little nor too much time for what we set out to achieve. I'd expected - at best - a last minute panic on Saturday. Instead we were polishing and adding finishing touches such as the credits screen.

Add a comment

Shattered World - Dialogue process and setup

Posted by Cosmologicon on 2016/03/14 03:18

If you haven't played our game Shattered World yet, you may be surprised to know that it has 118 dialogue clips. We got an email asking about our process for creating dialogue. Hopefully this will be useful to anyone else wanting to record dialogue for their next PyWeek game!


Basically I put out a "casting call" by posting on Facebook. Our voice actors range in experience from high (Randy as the voice of Mel and Pax) to low (me as the narrator). Experience and talent obviously count for a lot, but patience and quick turnaround time are really important for PyWeek, so I favored people I knew could get it done in time.


Because of the nature of PyWeek (a lot of the game doesn't exist until the last minute), your actors will have a very incomplete picture of the game. Try to give them as much as you can. For instance, I failed to mention at any point that the characters are in ships talking to each other over radio, and some of the lines don't make sense without that context, so the actors had a harder time delivering those lines than they should have.

It's helpful to write a couple of sentences about the overall mindset or attitude of the character, and 1-2 words for each line about the emotional state of the character during that line. Think of some famous characters from Star Wars or The Simpsons that are similar to your character. Still, your actors will probably have questions on delivery, so expect this to take some time.

I recommend asking your actors to use their regular voice unless they have a lot of experience. Accents, or pretending to be a different gender or age, are harder than you think to pull off.


There's a big range of possibilities here. Higher-end condenser microphones won't work with USB: you'll need a piece of hardware called an audio interface (more on audio interfaces). Here's what we used:

  • The voice of Ignatius was recorded on a cell phone with the Smart Voice Recorder app.
  • The voices of Mel and Pax were recorded with a MXL 990 condenser microphone and Mackie DFX-6 mixer, loaded into a program called REAPER, and applied a ReaFir FFT filter for noise cancellation and ReaComp compressor to reduce the dynamic range.
  • The other voices (Scamp, Ruby, Hallan, and Narrator) were recorded with a Rode NT1A condenser microphone with Focusrite Saffire PRO 24 interface.

Here's a great comparison between a $36 USB microphone and a $500 condenser mic + interface setup. A professional would obviously consider the more expensive setup to be worth it, but I think for PyWeek the cheaper one is still pretty good. Audio quality varies a lot among cheaper mics. If you're in the market for one, we recommend Samson Go.


Our audio producer (marybee) loaded all the data into a program called Ableton Live, either by directly recording, or importing WAV files. Each character was loaded onto a separate track, which lets you easily adjust the volume or apply effects to all of that character's clips. Overall volumes were adjusted so that all characters are roughly the same volume, and background noise was removed from the spaces between phrases by zeroing out the waveform. The workflow looks like this (click to view full size):

She also selected takes and chose the start and end time of each clip to avoid too much dead air between lines. Each clip (in the red boxes) starts with a fade in and ends with a fade out. Once all the effects are done, the clips can be bounced (exported) one at a time to individual WAV files.

Finally, she applied special effects to some of the characters. Live has a ton of possible filters and we looked at some of them, but in the end we just went with raising and lowering the pitch. I have trouble finding anything that sounds good with the more exotic filters.

If you're looking for a free alternative to Live, Audacity and Garage Band can do the same things. At any rate, you should expect it to take some time to get familiar with the software.

Recording Tips

No matter what microphone and software you're using, there are some things you can do to improve the audio quality.

  • Reduce background noise, like the television.
  • Hard surfaces produce echos, so recording near curtains is better than near a bare wall. In a pinch you can get under a blanket.
  • Don't move or touch the microphone during recording.
  • Speak to a point a little bit above the microphone rather than directly into it.
  • Move the microphone far enough away from your mouth to avoid clipping. You can recognize audio clipping by looking at the waveform in the recording program, or by listening if you know what to listen for.

Okay, that's it. Let me know if you have any questions. If you have any audio tips or resources, feel free to share them too!

Add a comment

Shattered World - gameplay footage

Posted by Cosmologicon on 2016/03/11 16:06

I made a video of the gameplay! Check it out here:

Add a comment

koperkapel - Whoops

Posted by drnlm on 2016/03/10 11:37

Rather embrassingly, we forgot to add the license file to the game repo, and so it didn't make it into the final release we uploaded.

We've now added the intended license to the repo.

For completeness, the text is reproduced here as a formal license grant for the final released version:

Copyright (c) 2016, Adrianna PiƄska, David Sharpe
                    Neil Muller, Simon Cross

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.


Add a comment

The Last Gardener - Note for PulseAudio users

Posted by Jjp137 on 2016/03/08 09:10

It's been brought to my attention that the game may crash when enough sounds are played at once, particularly the bullet sound, with "pyglet.media.MediaException: Too large". I actually don't have PulseAudio installed, so pyglet uses OpenAL instead on my computer, which worked fine during testing. Sorry for overlooking this :\

If this affects you, and you also have OpenAL installed, run the game with 'PYGLET_AUDIO=openal python run_game.py' instead. This will cause pyglet to use OpenAL, which seems to work fine. If you don't have OpenAL and you can't install it, you can turn off sound, although the game might be harder to play with sound off.

Add a comment

Gangs of the Aftermath - How to Play (I ran out of time for a tutorial)

Posted by iminurnamez on 2016/03/07 21:07

The objective of the game is to take control of all the neighborhoods of Aftermath City by managing your gang and attacking enemy gangs.


In general, left click to select or press a button, right click to close menus

F - toggle fullscreen


There are four types of units

Worker - Workers will wander into your territories periodically and join your gang. Workers can be trained and equipped to create the other unit types.

Scavengers - Each turn scavengers will scour the neighborhood they're assigned to looking for resources.

Soldier - Better at defense than attack

Raiders - Better attack than defense

Taking Over Territories

Clicking on an adjacent enemy-controlled territory gives you the option to attack that territory. All of your unassigned Soldiers and Raiders will participate in the attack against all the units assigned to that territory. After each round of attacking you are given the option to press the attack or retreat. Killing all the territory's defenders will give you control of the territory.

Defending Territories

If one of your territories is attacked by one of the other gangs all the units assigned to that territory will participate in the fight to defend it. This means it's best to have all of your units assigned to your territories when not training new units or attacking.

Assigning Units

Click on one of your territories and use the relevant buttons to assign or unassign units from the territory.

Add a comment