Medical Malpicross
Started: 1/25/2025
Completed: 6/25/2025
Medical Malpicross is a game that I made in Godot where you do horrible torture surgery by playing Picross / Nonograms on flesh. The puzzle moves and shifts around as your unwilling patient reacts to your stabbing.
I have mixed feelings on this project. I do like the idea because it's just absurd and weird. The contrast between an abstract puzzle game like Picross and the horror environment that the puzzles are placed in is very funny and that absurdity is the quality that I wanted to emphasize in this project. Though, the end result is a game that is fine. The idea, when explained, seems interesting, but in actual execution, it's just fine. In my opinion, it isn't that fun to play. I enjoy that I was able to just run with a silly idea, at least, but maybe this one should have been shelved.
You can download it for Windows and Linux here but maybe you shouldn't play this one I dunno.
On a different note, I did enjoy solving the weird technical challenges that popped up. Procedural mesh generation and physics come together to make something interesting and it was a fun learning / experimenting experience.
Making the Flesh Move
I knew from the very beginning that I would want to make the puzzle move and shift around as a reaction to your actions. This would be an interesting visual and gameplay effect, because now the Picross puzzle is all wiggly and you have to aim. To implement this, the first idea that came to mind was using some physics simulation. I probably messed around with Godot's physics springs, but ultimately I decided to roll a custom point-mass and spring simulation based on this blog post.
I make a grid of points and made adjacent points connected together through springs. So, on every physics frame, each point and spring would do its physics stuff based on velocity and position. Each cell in the Picross Puzzle would correspond to a square containing 4 simulated points so they can really stretch and deform. I also needed a way to move the points around so that I can control the grid. I ended up making a system where the outermost points in the grid were not simulated, are but still connected to the other simulated points with springs. That way, I could move them around manually and puppeteer the simulated points indirectly. The end result was ok, but it did limit how much I could control the points.
When I was doing all of the point simulation prototyping, I didn't really think about how I was going to draw the Picross puzzle and make it move around with the points. I just kind of assumed it would work out in the end, so it's good that there actually was a solution that just kind of worked. It's simple: on each frame, make a mesh using the current positions of the simulated points. We know the original positions of each point (like from before the simulation starts), so we can give the points in the mesh the UV coordinate that it would have if it was un-distorted. Any texture we apply to that mesh will naturally be warped in the ways that the point simulation is! I render the current state of the Picross puzzle as a texture (using Godot's SubViewports), apply the texture to the mesh, and boom, we have a Picross puzzle that moves and shifts around.
To make player input work, we just imagine each cell as a quadrilateral and test whether or not the mouse is inside of that quadrilateral. Repeat this for each cell and we can tell what cell the player is hovering over. Well, that's what I would say if I actually did this. At first, I just implemented it as testing if the input is within the bounding box of each quadrilateral because it was simpler to get working. It works perfectly if the cell is a grid-aligned square, but that is obviously rarely the case. I intended to change it to the proper test, but it worked good enough and I just left it.
I made a system to shift the position of the puzzle slightly based on where the mouse cursor is. I imagined that it's an effect where the victim is squirming in restraints trying to avoid the knife that you hold above them. Not sure how noticeable this actually is, but it's there.
And of course, when you actually make an input, this represents stabbing the knife, so the puzzle reacts by jerking in some direction.
By the way, the whole time I was making these systems, I had to keep in mind that the Picross puzzles can really be any rectangular size. The systems that I make would have to be flexible enough (have enough math and numbers in it) to accommodate for any size puzzle.
Aside from physics simulation things, I had to make the systems that would handle the Picross puzzle itself. I made the obvious things like storing a puzzle and player input, as well as checking for mistakes or if the puzzle was complete. I also made a system that would take a solved puzzle and generate the hints so that I could just draw a picture and have the puzzle made automatically from it. This is not the first time that I have made a system like this, so it was fun to just recreate it from memory. It's kind of a fun thing to do if you like programming.
Giving the Flesh Skin
I initially did all of my prototyping in 2D and the point and spring simulation started as a 2D system. I did want the other visuals in the game to be 3D, though. When I made the move to 3D, I figured that I didn't really need 3D movement (and staying in 2D would make things more stable and less likely to get wacky), so the physics simulation stayed 2D. The 2D simulation is basically a 2D plane that is overlaid on top of the relevant 3D elements in the scene.
Detecting input is a bit more complicated, but not that much. There are two objects in play: the ray that the camera shoots out based on the mouse position, and the 2D input plane. I then calculate the point where the ray intersects the plane (I used this guide about ray-plane intersections for the math). I convert that point to simulation space and that's what we need to detect what cell the mouse is selecting.
Very similar to how I make the wiggly puzzle, on each frame, I procedurally generate a mesh that would represent the abdomen area of the body. If you color a cell correctly, then the mesh generates a hole at that spot, because that was a successful stab. If you color cell incorrectly, I just made it mark with an X symbol. There's no penalty for incorrect inputs because I didn't feel like implementing that.
Visual Effects
I added a knife model that follows around the mouse input and stabs when the player clicks. I kind of just threw it together and it was fun to make. When the stab happens, I made blood particles play at the input location. There could have been some complex system that makes the knife and blood splatter move in response to the body moving, but that would be a lot of effort and I didn't do that. What often ends up happening is that the knife clips through the body in unintentional ways but that's fine.
A lot of the visual effects are based on a simulated "pain level". This just means that there's a number that increases when you stab, but goes down naturally over time.
- I made a post processing effect that changes the contrast, saturation, and screen shake based on the pain level.
- I wanted things to be wiggly (just like Memory Mall), so I made a shader to give the flesh a wiggly effect, and control the intensity based on the pain level.
- I made a very simple blood splatter vignette effect using noise textures and the pain level is used to slowly fade the effect out.
I dressed up the visuals to look at least vaguely like a bloody operating table in a mostly dark room. I also found some free screaming and squelchy knife sound effects that I used for when you stab (not recorded in the video below).
I wanted to make the insides of the body peek out with organs and stuff, but I realized at the last minute that it is kind of hard to see where you already colored cells, so I added a transparent black square to help indicate your inputs which kind of undermines all of the effort to make the innards. I really should have tried to make the puzzle drawn onto the body instead of just floating above it, but it was kind of just a consequence of the order of what I was implementing. This is perhaps the greatest regret I have for the project and now it will be like that forever.
Coordinate Hell
All of this explaining of the systems make it seem easy to implement. In practice, it was very annoying. My experience of making this was having to reckon with a bunch of slightly different coordinate systems and having to translate between them EVERY TIME I wanted to do something.
For example, it's useful to be able to index individual simulated points in a 2D array (for example, we need to figure out what points each cell has for input detection). However, when we want to access the cells that those points form, that's a similar, but ultimately different coordinate system, because a grid of points with x rows and y columns would have a grid of cells that is x-1 rows and x-1 columns (yay, fencepost errors).
Similarly, it's nice to be able to only loop through the cells that the player is able to interact with, which is a different coordinate system (it's essentially the cell coordinate system with the origin offset by some constant).
Off the top of my head, the coordinate spaces include:
- Point and spring simulation (for simulating the points and springs, obviously)
- Point and spring simulation cells (for detecting player input and positioning the Picross puzzle + its hints properly)
- Puzzle SubViewport (for rendering the puzzle before it's drawn onto the puzzle mesh)
- Player input cells (for checking player input (and judging it as correct / incorrect)
- Picross puzzle cells (for actually storing / reading a Picross puzzle)
- The 3D environment (for actually containing gameplay objects)
- The procedurally generated flesh (used to generate a 3D mesh for the body)
Every time I wanted to try and reason about the space of the game, I had to make sure that I knew what coordinate space I was in and how it would relate to the others, which ended up slowing things down sometimes. I'm not sure what I would do to remedy this problem. I suppose I could have stored the transformation matrix of each coordinate system so that doing transformations is less error prone.
Making the Levels
So those were the interesting parts of the game to work on. Then I had to actually... make levels for this game??? I was kind of already tired of working on it but I wanted to forge on ahead to get it done.
In the wise words of Ben Esposito:
Nobody told me when you make a videogame you have to make the whole thing.
At this point, My creative inspiration for this project had long since run dry, so actually theming the levels was kind of a pain. I wanted the levels to have some sort of vaguely medical theme, so that was the primary inspiration for the puzzles.
The main limiting factor of this ended up being the camera and size of puzzles. The bigger the puzzles, the harder it is to aim and see because the cells need to be smaller so everything can fit. I did not feel like making a system that would adjust the camera angle, so I just designed things that would work reasonably well with a static camera.
Once I had an idea for a level, I made the full colored version that would appear when you solve the puzzle using Aseprite. Then I would actually turn it into the puzzle that you would interact with and modify the image if necessary. Once I made the levels, I arranged them roughly in increasing difficulty.
I actually really enjoyed making the pixel art for the levels. It was fun to try and convey ideas with a very limited sprite size. Though, some of these are definitely better than others and I am not proud of at least half of them.
By far, the biggest tragedy was the scissors. I was actually really proud of how I got them to look, but the design resulted in an unreasonably difficult puzzle, so I had to mangle it in order to make it easier...
Final Notes
I wanted to make it playable in the web browser, but at the end of the project, I saw that it created some weird visual effects on the 3D flesh mesh and I didn't want to deal with that, so the game is download only. Oops.
Overall, it was a pretty fun idea to work on but only to a point. Eventually, I wasn't really motivated to work on the project, but I knew that if I at least made a tiny bit of progress each day, I would eventually complete it, so that's what I did. Finishing projects is important, but I wouldn't say that it's a virtuous ideal to strive for all the time. Sometimes, you just need to Stop. My stubbornness in not shelving it resulted in an agonizingly long and slow crawl to the finish line. A formidable task that honestly didn't feel that worth it in the end. I made a game about torturing people, but maybe I only ended up torturing myself. I think I still believe in the mechanic for its weirdness (maybe as a funny gimmick in a normal picross game), but I will not be the one to put it in a better game.