PyWeek 29 challenge: “The butterfly effect”
Butterfly Destroyers! - Butterfly Destroyers Development Overview
Posted by flipcoder on 2020/04/12 23:24
Background
----------
Team PythonCoders was an open team started by MysteryCoder, a 13y/o programmer. The team
was international: Our team members were from USA, France, Finland, and UAE.
I myself have been in several gamejams in the past, including GitHub game-off,
where my game was one of the featured winners.
Workflow
--------
Going into this jam we started with our project management using Trello.
We used a Kanban-like layout for tasks. Our columns were:
Early Decisions
---------------
One of the early strategies I suggested was to just start going and not worry too much about
waiting on our decision-making, since we were slower at this at the start,
it was very important to me to just get a flow going.
From my experience with jams, especially with more than a couple members,
being bottlenecked by "analysis paralysis" is a common problem. It's better
to do something and have to scrap or fix it than to discuss every detail before
you add it. In this strategy, the most active people on the team can make the initial decisions
as they arise, This sometimes causes code redundancy, since we may
find different ways to do the same thing, but its often worth the cost of this,
since allowing coders to use the methods they are comfortable with increases
their development speed.
First Steps
-----------
Our team was light on the graphics end, so we initially thought of doing
something in curses, so I threw together a curses-like terminal in pygame (see game/base/terminal.py).
This would be come in handy later, considering our game's scripting would
make heavy use of character-by-character typing during the game.
We had some ideas for games. I pitched the idea of doing something like Top Gun for NES, where it would
seem 3D, but we would try not to overdue it, knowing pygame's limitations were
going to become a problem. I imagined most teams would approach the butterfly theme as something gentle or light-hearted.
We went completely the other direction. I thought doing something comedic where you play
as the military hunting down butterflies for no apparent reason, while playing
it off as serious was quite funny. We decided this would make a cool arcade-like game and went with it.
--------
By the time we decided to move forward on the idea, we already had a basic game base.
I put together an Entity system as ddorn created a nice 2.5D/parallax Camera.
MysteryCoder implemented fog/distance-fading.
One of the core parts of the game's codebase is the signal/slot system, which was extended by both the timer system
(game/base/when.py) and the scene entity list itself. We implemented Scene
as a Signal containing entities as slots. This is the first time I've tried this,
but it had some benefits. The signal system was basically a safely-modifiable list,
where all changes to it during the list's iteration are queued until after
all iterations of it have stopped. This iteration+modification is also reentrant.
This meant all objects could modify the scene without iterator invalidation,
and we don't need to copy the entire scene list every time we iterate.
The modes of the game were implemented as a basic state machine.
The intro, game, intermission, and credits are separate modes that
contain their own update(dt), and render methods.
And finally, one of my favorite parts of the project: The scripting system.
We didn't want levels to be simply X,Y,Z object placements, we wanted
them to be scripts that were stepped through, and could pause/resume/restart
as needed. Multiple scripts could run at once and start/stop each other.
We used python's generators to script
both levels and entity behavior, allowing a single line of code to turn
on and off behaviors of things in the game at any time.
We allowed scripts to be run not just for levels, but for entities and game states as well.
A 3rd use of signals were here: Scripts could yield a condition for when to resume,
very similar to async promises. These were either timer events or fades.
I wrote a timer system called 'When', based on the signal system, that would
register timed events and fades and return a connection/slot that we could
yield from our scripts.
Scripts that needed user input would accumulate events that happened since last yield.
So we could script things like this:
yield script.sleep(5) # resume the coroutine after 5 game-seconds
Or:
yield lambda: not boss.alive # continue the script until the boss dies
Or:
# call faderfunc() with color values from black to white and resume script after
yield script.when.fade(2, (ncolor('black'), ncolor('white'), faderfunc, script.resume))
Look and Feel
-------------
Ddorn added ground tilting and parallax clouds. I added a noise-gradient to
give the ground and sky some depth.
We wanted each level to look different, so we varied sky and ground colors, and later
added weather effects and rocks on the ground.
We made the ship sprite stretch based on movement direction to give it a nice 3d effect
and Ddorn used his input system to smooth the movement of the ship. The player
handling felt really good.
Level Design
------------
Ddorn developed an AI system, allowing spawning of batches
of enemies in different moving configurations and shapes. In my opinion,
this is the most visually impressive parts of the project, and his
math work on this gave us lots of variety in the levels.
Ddorn's text narration during the levels was also great, and had exactly the
comedic tone I'd hoped for.
We did 3 different types of enemies and a boss. AI varied within the
initial butterfly type as well. We didn't get to fully use the Flyers and
ButtaBombers, and the ButtaBombers explosive behavior wasn't finished.
We didn't get everything we wanted to finished, but we were quite happy
with what we got considering the deadline.
Flair
-----
With the scripting, we were able to start polishing the look of the game.
We took advantage of gradients, noise functions, weather effects, particles, etc.
I wanted the game to look solid from the start to give a good first impression.
Music
-----
All of the music was written quickly, probably within a half hour.
I wanted to spend my time on code, but the game needed a memorable soundtrack
to give it the first impression we needed. I wrote 3 songs,
and I was quite happy with it considering the fast-approaching deadline.
Improving Performance
---------------------
We had some concerns about frame rate near the end. We had a memory bug which was a bit of a scare, since at one point the game was filling up
most of my RAM and causing bad fps. We logged like crazy and couldn't find much. This issue only
sometimes happened on certain computers, which made it harder to find.
I'm pretty sure that a different bug I fixed had removed the worst of it right before
We added an fps stabilizer that would disable some of the
effects if the frame rate dipped too low. We fixed the slow intro and score screen
by time-limiting the amount of effects updates, and improved the noise generation using caching.
Conclusion
----------
I think everyone felt it was a fun project (except for the scary last-minute debugging),
and I'm happy we were selected as a winner. I think everyone learned some new things during this.
I know I certainly did. We had some great competition,
but we gained an advantage due to the separation of the Team and Individual categories.
Thanks to my team for all the hard work, PyWeek for hosting this, and everyone who played our game. We've discussed
Project GitHub: https://github.com/PythonixCoders/PyWeek29
Hope to see you all next time!
Lightwing - Lightwing: Postmortem and Playthrough
Posted by Tee on 2020/04/12 17:46
Thanks for the feedback on my game!
First off, I can clearly see from the comments that this game is difficult. :) Here is a playthrough of the game: https://youtu.be/v2EHZ6QngGg.
I'm wondering if anyone actually beat all levels. Let me know if you did. I have trouble balancing games, so it's not surprising to hear that it's hard, but I never really know how hard it is until I read these comments. I tried to make the first few levels simpler, but the difficulty does ramp up pretty quickly in the middle.
Lately I've been alternating between puzzle and non-puzzle games, and this was puzzle time. I find it really fun to design a compact set of mechanics that generates interesting puzzle dynamics. A couple of comments about this one:
1. Level design
Designing levels for this puzzle took me a lot of time, more than my previous puzzle games. I spent so much time just creating each level that I didn't have time to polish the game further. Unfortunately a bug with the undo slipped through (sometimes it fails to undo enemy position).
This time I tried to write a solver to help iterate through the level creation more quickly, but unfortunately the solver was too slow to be of much help for anything a bit more complicated. It was a simple graph search through states, and being able to move the enemies around blows the size of the state space up very quickly. Maybe I could have spent some time improving it but I don't think it'd be worth it. It wasn't completely useless as it helped me understand some of the simpler dynamics of the game and analyze some smaller levels. So not only I spent time writing a solver I barely used, but also I spent many hours designing levels by hand, especially levels 7 through 10.
2. Puzzle mechanics design (minor spoilers ahead!)
This puzzle is surprisingly restrictive in the types of solutions you can have. In particular, you can't have a square loop! The entire goal of the puzzle is to form a cycle in some sense, and you can't even have a simple loop. I was considering adding a mechanic to break this property because it reduces the diversity of levels, but I prefer to minimize the number of mechanics so ultimately I decided against it. The reason why you can't have a loop is because, in a square, you're always going to attract the attention of two of the enemies, and you can't use the "back turned" mechanic because you want them in a 90 degree angle.
As a corollary, if you have three or more enemies, you'll always have at least three enemies in the same line, at least one of which will return fire (haven't quite written a proof but I believe this is true). My hope was that attentive players would notice this, but it's not easy to. I added a distilled version of this property in level 5, and level 7 returns to this exact same property but includes the attraction mechanics. If you did notice this and use this to your advantage, let me know, I'm curious. :)
Anyway, I had a lot of fun designing this one. I spent a large fraction of the time on the mechanics and level design. I wish I had reserved more time for polishing and bug fixing, but it's very hard to find the time.
Fortunately I was able to rate all games this time. This was a great batch, I've enjoyed playing all your games. Congratulations to the winners and thanks mauve for organizing! See you next time!
Miranda the Lepidopterist - Full playthrough video
Posted by Cosmologicon on 2020/04/10 06:06
Nothing Suspicious Here - Mac and Linux File Path Issue fix
Posted by chrisyan2000 on 2020/04/06 04:16
encukou just let me know that the source code doesn't work on Linux or mac because of the file path!
I just uploaded another version that replaced every path with os.path.join on google drive here:
https://drive.google.com/open?id=1vxjWykoH0E8RcxzcZArF2VL5_teLOAoy
You can also watch the youtube video here:
https://www.youtube.com/watch?v=6WImKzi5NLI
Sorry for the trouble!
Magnetic Pictures - If you get stuck in 'Tech magnets are adjustable'
Posted by DR0ID on 2020/04/04 17:53
Caterpillar Effect - Windows fix
Posted by encukou on 2020/04/03 23:19
Miranda the Lepidopterist - The Three-Act Structure and game jam games
Posted by Cosmologicon on 2020/04/02 19:19
Here's some thoughts I had while writing the story for my entry. I'm no expert on this topic so take it for what it's worth. And please correct me or elaborate if you know better!
The three-act structure is a classic storytelling technique most common in motion pictures. I think it also works great for games with a narrative that are, roughly speaking, less than 4 hours long. (Although some Zelda games manage it while being much longer.)
I certainly don't think that PyWeek games need a narrative, but if you want to include one, this structure matches up well with how the player typically encounters mechanics. Essentially, Act 1 is the tutorial or the introduction of the major mechanics, Act 2 is the main gameplay where you introduce variations on the mechanics or more involved challenges, and Act 3 is the final dungeon, boss, challenge, etc. Act 2 can be open and have separate branches, but typically you bring everything together for Act 3. richard's PyWeek 12 entry came with an excellent plot diagram that shows this off visually.
In terms of the narrative, there's a plot shift, also known as a plot point or a reversal, between Act 1 and Act 2, and another between Act 2 and Act 3. These can be twists, where some secret is revealed (e.g. the Act 1 reversal in The Matrix is a twist), but they don't have to be. Within each of the three acts, the protagonists have a different immediate goal. The Act 1 goal can be low stakes, vague, abstract, or mysterious, but Act 2's goal should be clearer, and Act 3's goal should be very clear and concrete (e.g. escape or defeat the boss). Often the act change coincides with a change in location (e.g. every Star Wars movie).
You'll often see it said that Act 1 needs an early inciting incident or call to adventure (e.g. The Wizard of Oz, Jurassic Park), and that's a good idea but IMHO it's okay to just use Act 1 to introduce the status quo of the world and characters, and let the plot events really start with the shift at the end of Act 1 (e.g. The Lion King, Shaun of the Dead, Back to the Future).
Some more general guidelines. Act 2 is the longest, about twice as long as each of the other acts. In my experience this means moving as much exposition as possible out of Act 1 into Act 2. Introduce characters early, ideally in Act 1, even if they're not important to the plot until later. Acts 1 and 2 can take place over days or years, but Act 3 generally happens in a single day, or even in real time.
Again, that's only one way to do things, but I've found it useful, especially this time.
Flutter - Game Submitted
Posted by mit-mit on 2020/04/01 03:46
Also, I've recorded a playthrough the game if interested and want to see the whole experience in one go :)
pollen. - retrospective.
Posted by rdb on 2020/03/31 10:35
puggu - Issue with sound on ubuntu ffmpeg
Posted by pillitoka on 2020/03/29 23:33
If the error is only with game-over sound, please try commenting out the following lines.
game/run_game.py line 148
gameModules/resources.py line 57.
If the trouble is with all sound files, comment out the following.
game/run_game.py lines 71 to 75 and line 148
gameModules/bomb.py line 20
gameModules/egg.py lines 29, 35
gameModules/player.py lines 93, 98, 107, 110
gameModules/spittingSnake.py line28
gameModules/resources.py lines 52 to 59
We apologise for the inconvenience.