PyWeek #23 challenge: “The Lesser of Two Evils”

ObPortum - last update after the challenge

Posted by cauch on 2017/03/15 18:13

Thank you all of you for the nice challenge!

I've read the comments, and I've done several tests to see how I can improve the game.
The main concern was about the random aspect of the game. I've tried with more predictable patterns, but I don't really like it.
In fact, I'm not sure I agree with the fact that this game is more oriented "random shooter" than "skill". Of course, if you fire just one bullet, then the fact that you will hit or miss will be random. But the point is that you can fire several bullets correctly placed such that you have 100% chance of destroying the target.
So, the required skill is deeper than just "clicking once a the correct place", it is "clicking several time at the correct places". It introduces aspects that I think are more interesting. For example, you can choose your target or move to a specific position before shooting knowing that some bullets will miss.

I have uploaded the updated version, just for consistency.

Add a comment

G(r)ate mystery. - DNW - feedback?

Posted by DR0ID on 2017/03/12 18:55

Congratulations to all that entered a game.

I really would appreciate more feedback about what prevented that the game could be played:

  1. cant not extract format file from my windows
  2. Gave up. I couldn't boot the game.
  3. F10 key used for starting game, does not work.

1. is probably an issue with extracting gz files on windows. Solution: use 7-zip to extract
2. no idea what the problem might be there. Just give us the log file or at least the traceback of the command line if any.
3. F10 key... I wonder why this does not work on this machine.

For 2. and 3. I would also like to know the os, python and pygame version that were used.
Thanks for the feedback.


My Enemy's Enemy is my Friend - Post-mortem

Posted by mit-mit on 2017/03/12 10:12

Thanks to everyone who played the game and left feedback! I was very happy with how the game turned out overall; after a few early set backs in the first 24-48 hours, I was really questioning whether the whole 3D with numpy/pygame only was a good idea or not, but I'm glad I stuck in there. Even though the game didn't turn out great, and I sacrificed time spent on making the game better by trying to get this to work, I'm really glad I did it, because it was a good experiment, and I learnt a lot from the experience. Some of the things I was most happy with:

Array of 3D effects: All of the 3D effects are essentially drawn using three functions: "pygame.draw.line", "", and "pygame.draw.polygon". In the first 48 hours I had in mind how I was going to use these to draw flat-shaded polygons and projectile effects, and I was just lucky that it pretty much worked out off the bat. I experimented a bit with trying to get texture mapping to work efficiently using pygame.draw.surfarray and numpy functions, but it was pretty much a failure. The only bit of texture mapping I kept was the thin halo of the milky way in the background, which I put in mainly to help with visual orientation.

Motion Dust: The little lines that fly past you as you move. I put these in in the last 12 hours, and I'm really glad they worked (not perfectly) as it's really hard to gauge your motion otherwise, particularly when things are far away.

Ship AI Voice: After playing Universe Factory's last few pyweek entries, I knew I really wanted voice in my game (because it has given their games such a boost in my opinion), but I didn't have the people for it. I ended up using osx built-in command line function "say" using the voice "Vicki" to generate all the in-game AI conversations, and I liked how it turned out (even if she has slightly odd pronunciation at times :) ).

Music: I sat down for at least half a day to try compose and produce the background music for the game. I'm not a composer, so for me I was really happy with how the music turned out; it was exactly the right ambience I wanted that game to have. I wrote the score up in Musescore using a couple of sections of strings, brass, a timpani and a snare drum, and did a little post-processing in Audacity. I really had fun doing this, and it's something I'd like to work on more (I love it when games have good music, something I will aspire to)

I was grinding pretty hard on development for basically every waking hour I had spare over the week, so I'm pretty sure I wouldn't have been able to make it any better in the time I had. In any case, if I did have a bit of extra time I would have concentrated on a getting a few extra things working:

More variation in gameplay and missions: I really wanted to have a few different mission modes (for example a defence related objective, an objective where you are required to disable and board a ship) but I just didn't get anywhere near finished in time to do this. I felt like the gameplay therefore was a bit repetitive. Also, unfortunately, I left very little time for game polish, so alot of the missions I didn't really space out properly (too much time spent travelling between objectives, firing at things really far away). I guess I knew from the start that the game was going to be technically ambitious, and therefore I was going to have to sacrifice having time to polish it, and actually make it a really good game.

Better Story and Alternative Endings: I knew from the start how I was going to use the story to match the theme, but in terms of actually developing the narrative, I did this mostly in little five minute gaps throughout the week, in-between getting the mechanics of the game implemented. So basically the story was a bit ho-hum, but that said, I'm hardly a writer, so it might not have gotten any better with extra time spent :). Also, I was going to have an alternative ending mapped out and feature this a bit more, but I just ran out of time ... I got to 6am after minimal sleep over the past 3 nights and I was just too exhausted to keep going, so I left it as it was. If I had more time I would have made this better.

This was a fun pyweek with lots of great games. Congratulations to the winners Tee and Universe Factory, two really great games! and congrats to everyone who participated and made a game! See you all next comp!

Add a comment

Wing Craft - Day 21

Posted by xmzhang1 on 2017/03/12 03:43

Time to say goodbye, see you all in pyweek24 :)

I want to thank all your suggestions and feedbacks, especially who report the bug in boss 3. I really do not realized it until you said that. And also I really like all the entries, for some entry, I just feel my IQ is not enough to play it. :) And some entry, I do not know how to get it work, I remebered Gato's game using SDL2, I really want to see it, but I did not get it work. And also some entry,like Gumm, show a very good example how to using logging module, I will carefully check it in the future. I have some sugggestions, for one thing, maybe we should add some tags to all the project, like Python 2, pygame, pyglet, etc, or the game genre, STG, ACT, PUZ, etc. For another, how about we can upload vedios here, to introduce our game, how to play it, how to install it. I know there is youtube, but just for me, I have to use VPN to access youtube.

All in all, game is over, life is still on.

Add a comment

A Knight of Curses - A Knight of Curses: Postmortem

Posted by Tee on 2017/03/12 01:36

Thanks for all the feedback! This Pyweek was particularly fun not only in the creation stage but also in playing the entries.

Theme and game design

The theme turned out to be great, even though it wasn't my first pick. It made me figure out how to make a game where you "choose evils" and lose power as you play, which goes against traditional game design. Cosmologicon also discussed this in his postmortem and he has some interesting points.

As a solution, I decided to integrate the decline in power with the objective. You have to increasingly become more and more cursed to win, but the reward is that you lose a stack of curses, heal, and gain progress in the game. Suddenly gaining curses seems a bit more desirable, since you get to heal and progress.

I also put in a lot of thought in the design of curses. I didn't want curses that actually reduced the power of the player (such as reducing the number of lives or speed), but curses that were obstacles in disguise. The spikes and bugs are clearly those types of curses; the others a bit less so. I wanted curses that required some skill to tackle, rather than a sort of inevitable impediment. One of my goals with this was to make the decision a bit more thoughtful: depending on whether you're good at dodging or ignoring distracting messages, you can choose one curse over the other. I hope that each player might have their own ranking of curses.

I was originally going to put nine curses in a 3x3 grid, but then I realized that was way too much, both in terms of time to implement and in terms of increasing confusion. I'm glad I reduced it to five; it works pretty well and I wouldn't have time to do any more than that.


I wanted this game to be challenging. After I submitted the game, I was slightly worried that the last adjustment I made to the balance might have made it less challenging as I wanted it to. But it seems like people still thought it was hard but not too frustrating, which is good because it's what I was aiming for.

It does depend a bit on luck and the curses you get. I find that the compulsive wall touching is the easiest curse, and the slipping sword one is not too bad if you're patient. As I mentioned, I hope that this varies from player to player according to their skills.

The different boss patterns is random, by the way, to answer a comment. They are independent from the curses and get progressively harder in increments of five rounds, up to a third tier (i.e. 0, 5, 10). You're right that maybe I should have made that more clear, but at the same time I think sometimes it's more fun if a game doesn't completely show its hand and lets the player figure things out by themselves. Balancing that is tricky though.


I decided to omit at the last minute what each curse did because I thought it'd be more fun if players tried to figure it out by themselves. Based on your comments, this might have been a mistake and I should have at least added it to the readme file. For anyone who hasn't played it yet and is reading this post, here is what they do, in clockwise order from the top:

- Wall: Adds a distracting flurry of messages that disappear when you touch walls. Because walls need some affection too, you know.
- Spikes: The staple of gaming. Step on them and you get hurt. Just like staples.
- Bugs: Not the programming type. These critters wander around randomly and you lose a life if you touch them. Unless you touch them with your sword, that is.
- Crosshair: Bullets become attracted to you within the range indicated by the circle. Unlike walls, it's not a good idea to touch them.
- Sword: Makes your hands slippery. The sword randomly flies out of your hands after each swing. It can also kill bugs if you're lucky, because flying spinning swords hurt (but not enough to hurt anything larger than a bug, apparently).

I also wasn't clear on the fact that the color of the twin you kill corresponds to the curse you get, but I think that wouldn't be too hard to fix by adjusting the wording of the in-game instructions slightly.

Thanks again for all your feedback and to blakeohare for hosting this Pyweek. I had fun playing your games! Congratulations to Universe Factory for winning the Team category! See you all next time!

1 comment

Population - I've not really posted anything.

Posted by LeopardShark on 2017/03/11 17:01

Sorry, I never really posted anything. No screenshots, no (correction: 1) diary entr(ies|y). Just a very short description. Next time I will try to be more active. I did not spend as much time on this PyWeek as others but THIS IS NOT AN EXCUSE FOR SILENCE.

Add a comment

The Final Choice - Postmortem

Posted by Cosmologicon on 2017/03/10 05:30

I enjoyed this PyWeek. I think the game turned out pretty good, although it was different in some ways from our normal entry.

Game design

EnigmaticArcher had a great idea for Lesser of Two Evils: a game where instead of gaining abilities as you went along, you started out with all your abilities, and lost them as you went along, until by the end you had almost nothing left.

I found this challenging from a game design perspective. It goes against some basic principles of modern game design. Games generally add abilities as you go along, so the player has time to learn them without being overwhelmed. So how can you start a player out with everything unlocked? I think we stayed true to this original vision of an inversion, but to do so, I had to make many design choices to accommodate it.

For one thing, I only chose upgrades that required no skill to use. If one of the mechanics you lose along the way is something that takes skill to use, like wall jumping, and you never use it, you won't lose anything when it's gone. The shoot-em-up genre definitely makes this more possible.

The big challenge is, how do you ask players to make a choice that affects the entire game if they're not even familiar with the mechanics yet? That's a recipe for player frustration. So I balanced the game to be short and focused on replays. Just accept that players will not be able to make an informed decision the first time though, but hopefully the fact that you can easily replay it will mitigate that.

Of course, being focused on replays means you can't make it too easy or offer too much guidance, because it gets old when you repeat it. This time we made it more challenging than usual, more like a typical roguelike or 1980s arcade game.


The portraits and nebulas were from Pixabay. I would have preferred to draw custom character art but I didn't have an artist this time around. It's still a lot of work to find the right portraits, but it's faster than drawing them myself. It's really hard to find free images online. I definitely recommend Pixabay for anyone who doesn't have an artist on their team.

The asteroids were done using a free POV-Ray script I found that generates a 3d asteroid model. However, the script was not set up to easily rotate the object, so I had to figure out enough POV-Ray to rotate the thing and generate the animation frames. It was way more work than it should have been, but still way less work than doing it from scratch.

The rest of the graphics, namely the ships, were done in Inkscape, which I definitely recommend if you like vector art. I would have liked a more coherent design for the enemies, but that's the sort of thing that just takes time.

Other stuff

This is my first game with multiple endings, which I like. I wanted there to be something special for the best ending, so we wrote a song with lyrics, which only plays over the credits if you get the best ending. If you don't feel like doing that, feel free to find the song (ballad.ogg) in the data/music directory.

I generally make the game work on a variety of resolutions, but this is my first game to have two different orientations. It was surprisingly not that hard to support both vertical and horizontal mode. I still can't decide which way I like more, so I'm glad they're both in there.

I think the voice actors all did a good job, but I don't know how crucial voice acting was this time around. Still, that's sort of become our thing, so might as well have it. Anyway it's a good way to get more people on the team and it's kind of fun.

This is the fourth time in a row we managed to scope out a game that we were able to complete more or less as it was originally envisioned, with no major missing features. I think we're getting the hang of it, but it's taken a long time to get to that point.

Thanks for checking it out. Looking forward to your feedback.


Ms. Information - Ms. Info Post-Mortem

Posted by assertivist on 2017/02/27 08:41

Title ScreenGameplay - 1Gameplay - 2

Here's our game! It's a simple 2 button runner where you play as a political pundit on television. Your interviewer is asking the tough questions, and the best way to stay on message and keep approval ratings up is to dodge those questions! We hope you enjoy.

It's been a heck of a week. The day before the compo I managed to accidentally cut a chunk out of my left index finger in the kitchen, requiring a hospital visit and a 9-finger typing strategy. My teammate's car broke down on the way home from work on Wednesday. And somehow, we still managed to finish something!

The best part about it in my opinion is the concept, the wonderful art and music made by my teammates, and all the jokes we came up with. We decided to go with a mobile aspect ratio this PyWeek just for fun, but after it was all said and done, for the first time, we're hoping to continue developing a game AFTER PyWeek. Maybe you will see Ms. Info on the Google Play store after we flesh things out a bit more! Who knows!

Art stuff

So proud of my team for churning out the art so rapidly. We had to pivot our game-play ideas several times to distill what we imagined into something possible in a week, and these guys did their best to keep up with my harried demands and also their busy lives. I think you'll notice the quality on most of our menu screens and character designs. Every time you see an ugly screen with no background, or the Help screen, that was totally last minute programmer art...

Music stuff

I think we did really good with music this time around. We each contributed a song, and of course mine is really simple and brutish, but I think the important thing is to just let the creativity flow and not get too caught up in making everything perfect. I think 3 songs is a lot for a week effort, they are much longer than we normally can do as well!

Programming stuff

I was doing really good with code quality at the beginning of the compo. Use of a FSM library really helped with stability and scene changing, but as soon as crunch time hit most of my diligence to keeping it clean went out the window. Thankfully, the base that the game-play prototype sits on is really solid, and I don't TOTALLY dread going in and cleaning it up, which is a first for me personally.

All that being said, I'm looking forward to going back to a language with types...

All in all...

Can't wait to play all the games. It looks like we only had around 20 entries this time, and I'm totally fine with that, it gives me more of a chance to really enjoy each one!

And please, if you have trouble running Ms. Info, feel free to leave a comment!

Add a comment

A Knight of Curses - Playthrough Video

Posted by Tee on 2017/02/26 22:47

I decided to copy mit-mit's idea and make a short playthrough video of my game, because why not? It's less than 3 minutes, so if you don't have time to play it, you can still take a look at it!

1 comment

G(r)ate mystery. - How our Pyweek23 went - codogupyweek23

Posted by gummbum on 2017/02/26 21:56

The team name is a mashup of our IRC nicks.

DR0ID was the beast of burden upon whose back we rode. His tools (pyknic, pytmxloader), skills and knowledge with Python and Tiled, carried the team. Kudos to DR0ID.

Axiom and Gummbum were challenged to give as much time to Pyweek. Life's demands. Yet we were able to contribute in significant ways.

Gummbum lost two-plus days to life's demands and could not do much until Tuesday. DR0ID lost a couple days to collision-detection and -handling. Some days went by with many hours of no submitted changes. So essentially what you see here is probably a 5-day game at most.

Axiom contributed early by locating some great art and music. He kept us sharp during the week by playtesting. If you want to find the worst bugs, he is your man. :D All true, funny, and invaluable.

So, by Sunday (Day 1) we had the game design well documented. There were far too many features to implement, and the simplistic core mechanics would be a difficult challenge.

Gumm's vision was a Vanguard-like (a 1981 arcade shooter on rails:, but we didn't want a clone. Just to get some early controls and interaction, DR0ID implemented the player ship as a free-roaming entity. Partway into the week it was deemed that putting the game in "runaway train" mode (a la Vanguard) would create some difficult problems that we didn't have time for. So the free-roaming control was kept. But this changed the game's focus. Instead of keeping up with the runway train, the player now set his own pace.

We had a tiny test map that was doing the job. Gumm made a giant map on Wednesday. Wonderful. When DR0ID added rotation to the meteors, it killed performance, of course. Image caching to the rescue! But then we met with an Out Of Memory (OOM) error, hitting the 32-bit limit (3 GB!?)

Well, sooner or later you have to make some real-time monitors. :) Then it was evident we had too many resources. We could force the memory usage down. But we didn't want to give up any of our beautiful resources and effects. Thus some inventive tuning was underway.

The OOM was proven to be an unmeasurable delay somewhere in the Python process. The system kernel had freed the memory (2 GB of images!) after winning a level, but loading more images for the next level resulted in OOM even though the system showed the memory was freed. Not sure what was going on there, but for the sake of time we decided to cut memory requirements by using a rotation step of 2 (180 degrees) for the meteors instead of 1 (360 degrees).

Even at 180 points of rotation, the frame rate still suffered a lot while the cache was building. We fixed that by pre-generating the cached rotations during map loading. But that took 20+ seconds on an Intel i7, and who wants to wait for that? :) Finally we further sacrificed on smoothness of rotation to get the pre-caching performance we needed: bumping the rotation step to 3.

We were still struggling with those issues and more on Thursday. By then we had no game, really. We needed entities and features, otherwise we had a player vs. one dumb baddy in a cave with some madly ricocheting bullets. In retrospect it seems we had tacitly agreed we would make a bullet hell in a cave. I realized this when DR0ID mentioned that is what we had. :D Gumm added sound effects and the game suddenly got fancy. DR0ID quote: "I'm astonished how much difference the sound and sfx can make". Late Thursday it began to come together quickly. But the appearance was still crude, we had no style or consistency, and the screen was full of debugging telltales. I thought we would keep the hand drawn gfx. They were cute and I liked them. But no, DR0ID had other ideas...

Friday was the day it all came together. DR0ID was a whirlwind. The team added entities, features and DR0ID began to work on the final, exceptionally beautiful maps. By end of Friday, we had a great looking game with one map.

Saturday Gumm wrote the story and the pager, and integrated the levels. DR0ID finished the maps. We playtested, tuned and debugged feverishly. (Incidentally, inserting a long delay for the player to read the story allowed the system or process time to free the memory in between levels. This allowed us to push the memory usage back up, so one can run the game--barely--with 360 degree meteoric smoothness. If you're willing to wait for the pre-caching. On the boss level, the game automatically forces the rotation step to 4 because: you *will* be reloading often. ;))

And out plopped a souffle.

DR0ID almost beat the boss level (but he made it, and knows its secrets :)). I could not even get past the first two encounters on the boss level. So I nerfed the baddies by 60% of their health. I left the beefy boss ship alone. Still, I could not beat the boss level. The only way I can win the boss level is to turn on cheats (in settings) and display the walls (F1 in game). Even then I had to retry a few times. Yes, it is that hard. If you win fairly, without cheating, you are pretty heroic in my opinion.

In terms of performance this game is a very impressive powerhouse. I've been studying and optimizing Python-pygame performance as a pet hobby for several years (as I'm fond of telling: ever since they challenged me on pyweek-users: You can't make a scrolling game world, Gummbum, too much pixels for the CPU! :)) thus I know pretty well what the platform is capable of. This game is top tier in processing power. Because you are geeks, here's some info you'll appreciate:

- Images cached @ rotation step 4: 8K images, 494 MB, cache hits 100%
- Images cached @ rotation step 1: 23K images, 1469 MB, cache hits 100%
- Most images have SRCALPHA layer, and more empty pixels than they should
- The background image, and any that don't require transforms are not included in the cache totals

Each game loop:
Idle: 1300 entities (and sprites) total, 301 visible, 215 updated
Peak: 1500 entities (and sprites) total, 700 visible, 500 updated
Collision checks: 10K @ 60 fps, 27K @ 25 fps; 40K (cheating) @ 10 fps


Add a comment