- WASD moves your guy
- Mouse cursor adjusts vision range
- E opens doors and windows
- R breaks open those that won't open normally
Make sure to admire the graphics.
Ratings (show detail)
This game is so ugly you can even hear the ugliness
CPU-friendly no scatter effect release
ugly cpu friendly thing.png
CPU is no longer suffering, but things still look ugly
ugly cpu hog.png
This game is low res, ugly AND it hogs your CPU. Plus, it doesn't do much yet
F is for Family
- Short – There's a lot of entries and I want the reviewer to get all the fun the game has to offer in 5-10 minutes.
- Randomized – I've been thinking about developing an online dungeon crawling game, and I could use the content generation practice. This game, though, will not be online.
- Shallow UI – A good immersive UI can be pretty good production value. The next best thing is a well-themed small UI that just offers what you need to get going in the game. The worst of all is a bulky, buggy UI that hasn't been polished to fit the game.
- Simple graphics – I'm not a good artist, and I'm a terrible artist in a hurry. Let's take all the shortcuts I can take with the art and call it “artistic choice”.
- Not conspiracy related – Let's be honest, I expect that at least 1/3rd of the entries is going to be conspiracy stuff.
- Not sharknado – For similar reasons as above.
Because the theme pulls so strongly towards the conspiratorial mind, I decided to search a bit for inspirational quotes with the words “behind” and “behind + everything”, and a few interesting ones popped up:
- Nothing is ever cut-and-dried. There's anguish behind everything. - Paul Rudd
- Desperation is the raw material of drastic change. Only those who can leave behind everything they have ever believed in can hope to escape. - William S. Burroughs
- I demolish my bridges behind me - then there is no choice but forward. - Fridtjof Nansen
- Family means no one gets left behind or forgotten. - David Ogden Stiers
The actual idea:The quote about family is the one that hit me hardest, and second was the one about desperation. With that I'm tempted towards a short survival experience navigating dark areas, with creepy ambient audio (I'm happy to know a few places that just sound creepy so I can spend a bit of time attempting to record it) and monsters lurking around, following you based on the sounds you make. And you gotta find your family. So it's a pretty happy setting. :^)
Swap it like it's hot
It comes with a few pitfalls, though:
- You gotta remember to import your modules, not their symbols
- You gotta make one main class as stupidly simple and as crash-resistant as you can
- To simplify swapping, you gotta work with smart modules, rather than smart classes
I'm like 70% through the process of making my game updateable while running, the last steps I can think about ahead of time are:
- Make the game state JSON serializable (that unfortunately means working with few classes and more modules)
- Add hotkeys to dump the gamestate or to reload a gamestate
- Make the game initialization initiate the game with serialized JSON data
Today is (hopefully) probably the only day in which I'm going to focus on trying to make this happen. If I end up stuck in developing this feature it's best I just dump it, as it will probably not pay off in the timespan of a week. I'm sure there's better ways to do this, but this is my first try at this. :)
My current engine model is as follows:
- Game object, which contains a basic loop, and functions to handle input, simulate and render, all which are delegated to an "engine" module, which receives the object itself as well as the game data. All of those functions are written to prevent crashes, as I might want to preserve data that was created as a result of swapped-in data. As well as a swap requester function, which causes the engine try to swap the "engine" module.
- An "engine" module, which actually handles the pygame stuff, such as initializing, polling for events, rendering stuff on the screen, as well as attempting to perform arbitrary game data upgrades upon swap.
- The "gamestate", which is a dict of primitive objects intended to be serialized in JSON and passed around to smarter modules.
If you want to look at the atrocious in-development code, see here: https://github.com/shundread/pyweek24
I'm, like, 30% I should rethink some of my features
My idea for lazying around on the art is using some screen update strategy meant to (very grossly) simulate eyes in straining conditions where shifting focus from bright to dark places leaves after-images, as well as give a sort of surreal feel to the game. My initial implementation involves a lot of random number shuffling, and could desperately use some improvements.
The rendering strategy is as follows (surfaces are 200x200):
- Render the "real world" in a surface
- Render the "light casting" in another surface
- Blit the "dark areas" of the light casting on top of the "real world"
- Shuffle the random numbers matrix
- Update only those pixels to the screen
My 200x200 game, scaled up to 600x600 is running at ~25 FPS, and while the big bottleneck is the screen update strategy (skipping the last step bumps the FPS to 60 with CPU to spare), I'm sure there's a few workarounds I could do to speed up the process, probably pre-calculating some update patterns is one way to go (with the potential of leaving specific pixels "relatively neglected"), another is to play a bit with surfarray and pixelarray.
This VERY CLEARLY is one of the features that could easily turn into one of those time sinks that prevents a game from being completed and won't right now provide good return on investment. So I'll pause further development of this for now and get the rest of the game done before wasting whatever remains of my development hours on making whatever post-processing effects for the game cool and running crisp.
Tomorrow: simple world generation
Some features were expensive
Long story short, the map generation was a very expensive feature. And it's not yet "complete", though any further development on it is pushed back to the end of the queue.
The hot swapping / state saving pair is another one that cost me a bit of time. Hot-swapping itself hasn't been very useful and at times, it's unwanted error-obfuscating feature gets in the way. On the other hand, in preparation for hot-swapping, I also made sure all my data was serializable and now owned by any particular object apart from the non-swappable bits of the program. As a result, I ended up with a nifty and useful save-state / load-state feature, which has already proven useful and will certainly prove further useful when developing monster AI.
I thought a bit about the current state of affairs and came up with the following task priority list for the next available hours, from most important to least important:
- Character/Map collision (let's make it dumb)
- Scatter family members around the map and have them follow the player once they meet
- Signal the player to the exit once the family is collected
- Ending sequence once the exit is reached
- Add static monsters
- Monster wandering behaviour
- Add death and fail conditions
- Add auditory system (player produces sounds, monsters within hearing range hurry to the source of the sound)
- Map generator - produce terrains (grass, roads)
- Make doors interactive (and a source of sound)
- Make windows interactive (and a louder source of sound)
- Add minimap
- Funky post-processing method
- Map generator - adds non-building barriers, decorations
The game is borderline "deliverable" once the ending sequence is added, it is an actual game after death and fail conditions are added, and once the auditory system is in place, it is pretty close to the vision I had for the game in terms of mechanics. In terms of look/feels, the postprocessing step is the most important, but it cannot be made at the expense of any other features before it, because should time be too short then I simply don't have a proper game.
Your shipment of ugly has arrived!
I'm happy with how the project turned out. Initially I had no idea whether I'd even be able to deliver on most of the features, but it turns out I got it mostly covered. Due to my experimentations with state-saving and hot swapping, the end-result code is rather ugly, but so is the game.
As a final test, I did a couple of playthroughs, and for completion's sake I attempted the best ending on both runs, and the first of those (after disabling the see-through-walls vision) was rather frustrating, as I twice walked past the spot where my last family member was hiding, and the second one it went fairly easier.
Hopefully the game drops enough hints about how it works to players who haven't tried it out yet, and the difficulty is fairly balanced. I have on more than one occasion provided unreasonable difficulty levels.
I doubt that I would work on this project any longer now that it's reached this point, but if I did, the first thing to do would be to start working on would be to switch to opengl & shaders for rendering and getting the post-processing effect done right and fast via a fragment shader. After that, no idea. I could probably spend weeks just on content generation.