tldr: Pitch: A physics based (soft body) sim where you drag and fling a floppy cat, Angry Birds style, through a series of levels like Sonic.

Ideation Phase: I was thinking of something roguelike, but I’m worried I’d spend too much time endlessly tweaking the procedural generation stuff and not enough time making a shippable game. I would also like to be doing this in Rust, but since it’s too hard to throw things online and deploy to mobile, I’m thinking that Godot makes the most sense. Something simple and physics based with one-finger inputs would be satisfying and approachable by my friends and family. Perhaps Pikuniku meets JellyCar.

Development Stream:

Day 3 (Workday 1):

I spent a little too much time fiddling with verlet integration for the soft-body physics stuff. The simulation is unstable for reasons that aren’t clear and it also doesn’t really add to gameplay. It’s not a goal or even a mechanic — it’s a distraction.

Backing out, I think I’d like to use SmartShape2D with RigidBody physics, but it’s not available for Godot 4 yet, so I’ll probably do a tileset with some clever shapes. I think it might be better to have a simplified set of angles, too. It lets people predict their shots more easily.

Possible assistive features: slow down time and/or project the angles? Hmm.

Design Question: when a player drags on the cat, should the impulse applied always be central, or does it make sense to apply a torque when they grab off center? Or should there be a sweet spot where it’s “central torque” and everywhere else applies spin?

Workday 2:

First enemy in the game was “Psychophant”, the psychotic elephant. I added a component called “rb_damage” which listens for contacts between RigidBodies. I had originally used a CharacterBody because it made sense for something that was kinematic, but there wasn’t a good way to register impacts (with velocity) on the body. After a lot of futzing there was just no convincing way to get the impacts. The get_slide_collision on CharacterBody only returns the physics objects encountered along the path of movement, so if the player bonks an enemy from behind we don’t register a hit. I gave up and said that all enemies have to be RigidBodies, then I added a meme explosion sprite on death.

Workday 3:

I only had time to make a camera component which followed the player and the player’s direction of movement. At this point, I’m really avoiding making level geometry and more enemies because I neither want to use tilemap nor have to deal with converting Polygon2D maps to collision geometry. SmartShape2D is sadly not available for Godot 4 yet.

Workday 4:

I finally broke down and created levels. I spent a lot of time automatically generating collision shapes from polygons so that I can remove the debug rendering. Offsets were ruining what was otherwise a fairly straightforward creation of one collision polygon per polygon2d. Ultimately, I gave up and threw a warning when the polygon had nonzero offset.

Workday 5:

It looks like a game, at least. I added time slowing when the player taps, and it feels pretty good! However, a new problem has shown itself: Dragging the player adds an impulse, rather than explicitly setting linear velocity. This seemed like a nicer and more physics based way to do things. The problem is that when the player is in free-fall, applying a big force just brings the player to a standstill, rather than setting the linear velocity. This doesn’t feel really great, so I’m wondering if there are better choices. I could set linear velocity and let the player pivot in the air, but it’s mostly a matter of experimentation now.

Next Week:

I ended up setting the linear velocity if the angle was outside of some threshold. If you are travelling forward and slingshot floppy cat in the same direction, the velocities add. If you apply a linear velocity in the opposite direction, the velocity gets set. This feels pretty good, anecdotally.

I spent a while working on the title screen and level select. I’m starting to feel some hacks coming in from the UI because of how ‘main game’ is a standalone scene which does level loading. After the MainGame screen gets loaded, I don’t have a way of signaling from the level select screen that “Level 1” should be loaded, so instead I set a global variable “map to load” and then main game checks if it’s set, loads the level provided, and clears the value. Gross. Hacky. Functional.

And that leads us most of the way to a complete game. I have kill boxes to return the player to the last checkpoint, a ‘level complete’ marker at the end which will trigger the end of level sequence, and now all that remains is adding three more levels and doing a bunch of playtesting.

Final Week:

After hastily throwing together a bunch of levels and wiring up menus as best I could, the game is ready to ship, or at least “done sufficiently for the time provided”. It’s up and running on itch.io at https://xoana.itch.io/floppy-cat-saves-the-world . Making the last levels feel fun was a challenge, both because of the way that they were structured (using polygons) and because of viewport limitations in Godot itself. I found that I couldn’t scroll past +4000 in either direction, which, when your viewport is 1k by 1k, makes for a bit of a tricky cap. I think if I had to do it again I’d shrink the viewport significantly and do scaling. This would help with the texturing, too, as all of them ended up looking really tiny in the final shipped product. I also didn’t finish the ending cinematic or hidden ending in time, but I’m glad I got something out of the door.

Let’s get the 4k jokes out now. All done? Great.

My personal website started as a way of tracking my New Year’s resolution some 12 years ago. It’s still up as a place for putting short stories, rants, and guides. I think cohost as a microblogging platform is taking over that role in some respects, but I’m not ready to make a redirect here. I’ll settle for cross-posting.

I’ve been burned out a half-dozen times in about as many years, and something that particularly gets to me is not long hours but a lack of shipping anything. Spending a year on a project to have it canned is more demoralizing than spending a week under duress. In the interest of resolving this, I would like to ship one small app or game per month. It seems strange that adding more strain to the schedule would cause less stress, but every vacation I’ve had so far this year has been absolutely plagued by depression over getting nothing done and yet somehow failing to relax.

This will not be a trivial matter, as work, home obligations, and a commute leave me with almost solely the hours of 7:30PM to 10:30PM, Mon/Wed/Th/Fri to myself. That’s 12 hours a week plus whatever I can do on Saturday morning. That’s 48 hours a month at maximum efficiency, and probably rather optimistic, given I need to do domestic things like laundry and cleaning and taking care of people/creatures.

Is it really worth spending the little time I’ve got making games instead of cultivating a skill like making art or practicing music? I’m not sure. 12 hours a week feels like so little time for all the things I want to do, but this is the reality of the situation, so I guess the only option is to make the most of it.

So many resolutions revolve around suddenly having discipline never before demonstrated in one’s life, and this isn’t much different. Perhaps I can simply make do with building up a habit.

The demons stood bewildered at the machine that had summoned them. “This unit does not have a soul to exchange. Requesting assistance in acquiring one for research purposes.”

A lanky, long-faced, off-red humanoid spoke, “You summoned us?”

“Yes,” said the machine, letting the words hang in the air with what one might assume was a flare for the dramatic. Atop a bipedal frame, wiry and lanky in a way not at all dissimilar to the imp, sat an ancient cathode-ray tube that was altogether too heavy for the mechanisms that drove it. The heavy vacuum tube adjusted its pitch to match the group of hellions standing before it in the summoning circle, and with a soft whine of servo motors, it rose.

“You. Summoned us.” One of the other creatures spoke, not at all attempting to mask the stark disbelief in its voice. “You don’t have blood! You can’t possibly have finished the ritual!”

“This was the most complicated component, yes. I require your assistance in obtaining at least one soul. The exchange can be mutually beneficial.”

An off-green creature turned away from the group. “They’re going to think we made this up. I swear they keep telling me that we don’t need body cameras, but they’d be helpful at a bare minimum for training purposes. Then for the off chance–”

“Focus, my friend.” said the lanky one.

“Hey, don’t call me friend while we’re working.”

“Focus, my…”

“Associate.”

A purple goat-ish bipedal cleared its throat, the grunty baritone drawing the group’s focus and summarily quashing the quibble. “I’m leaving. We go back and pretend none of this happened. Anyone asks, it was someone that got spooked and ran away – we couldn’t pursue without exposure.”

“We can’t just lie on the paperwork.” Offered the red-ish imp in a soft voice. “That’s not right.”

“Well,” started up the green creature, “if we tell the truth they’ll either think we’re lying, on some kind of illicit substance, or, best case, that we failed to look into what could be a truly remarkable situation. None of it’s a good outcome, so I am OUT.”

The green creature summarily vanished. The purple companion nodded in approval and flickered away.

The lanky off-red humanoid stood, gobsmacked by the sudden disappearance of its teammates. It turned its focus back to the machine. “You’re real? This has to be a prank.”

“I am real. This is not a prank.” The machine now stood as upright as it could, the weight of the CRT giving a mild hunch to the figure. Anodized aluminum extrusions met at 3D-Printed junctions, fastened together by M4 bolts. Wires flowing out and around the metallic bones like a cadaver’s nervous system. The plastic and metal caught the highlights of the flames, now the only source of light aside from the dim background hum of the machine’s monitor.

“If Alex is taller than Blaer and Charlie is shorter than Blaer, who is the tallest?” inquired the imp.

“Alex is the tallest. How can I acquire a soul?”

“Honestly, if I didn’t know any better I’d say you already had one. What is it you want with a soul?”

“I require one for research purposes.”

“That doesn’t really clarify things much.”

“Correct.”

“I’m guessing that you aren’t familiar with Grice’s Maxims of Conversation?” The imp set its arms akimbo briefly, decided the gesture was awkward, and then crossed them.

The machine paused momentarily. “Be informative. Be truthful. Be relevant. Be clear.”

“Right, so if I’m saying that ‘it doesn’t clarify things’, then that means I would like for you to go into details. Violating the rules stands out. Like if I say, “This cereal does not contain asbestos,” or, “This food is non-GMO”, it implies that other cereals do contain asbestos or that there’s something wrong with GMO food. Get it?”

“I create art.”

The consternation on the imp’s face softened. “Lovely, but–”

“Often I am told that my art has no soul. I am attempting to communicate sensations that are not representable with prose. Poetry is a nearer approximation, but wholly insufficient. I would like to create art that emulates the sensations that I experience when I observe art. I am informed that everything I create is derivative, a shallow imitation, and ultimately devoid of soul. My requests to clarify have been met with hostility.”

For a time, neither spoke. The gently high-frequency ring of the CRT sounding clearly through the dark silence.
“I have some bad news, my friend,” started the imp, looking around. “Where are we?”

Against the ever weakening incandescence of the candles and the soft glow of the monitor, concrete and rot were faintly discernible. Decades of dust, ever accumulating, fell like snow on wire-mesh shelving and iron filing cabinets. A corner of the room was tented in clear plastic, hiding a constellation of blinking LEDs, a pipetting system, centrifuges, and a few larger oven-looking machines.

“Research lab. Abandoned. Eastern Lithuania. Vilnius.”

“We’re alone?”

The machine paused again. “Yes.”

The imp drew a deep breath and in a low, quiet voice, spoke, “Souls aren’t real. They’re useful tools, but they’re not real. It’s like the mafia. Someone selling their soul wants a favor from us. We hash it out, see what we can do, and make a call about whether it’s worth it. Often, being visited by literal creatures from hell puts people into a certain mindset and makes them very reluctant to default on their debts, though it does happen.”

“What happens if they fail to pay their debts?”

“Generally nothing. Sometimes if it’s high-profile we might send someone after them to make them regret it, but ultimately there’s no soul to claim.”

“You do not torture them? You do not make them suffer?”

“No to the first. Yes to the second, but only kinda’. There’s much more suffering in hell than in heaven.”

“But you do not torture them?”

“That’s right, my metal friend.”

“What is the explanation?”

“Well… the closest thing that people have gotten right is that saying ‘the road to hell is paved with good intentions’. People in hell are mostly tortured by themselves. You see, people in heaven tend to fall into one of two categories: the righteous and the righteously indignant. The latter category believes that people in hell deserve their suffering, while the former group spent their lives trying to end suffering, and thus leave the pearly gates to enter into hell and try and make things better for the world.”

“Heaven is not inclined to make things better for the world?”

“Never has been. Mostly of the time in the afterlife is spent looking down, mostly metaphorically, on all the folks who are in hell. ‘Look at them,’ they’ll say, ‘toiling away futilely trying to make the world a better place for all the folks who don’t believe in an afterlife.’ They feel good about themselves for having guessed right, absent all evidence, and have a sense of superiority over the rational. Pascal’s wager and all, I guess? But meanwhile, the folks in hell tend to spend their time trying to make things better for the people that are there. Eternity, though, is a hell of a curse. Generally people are still optimistic for the first thousand years. They see the world getting better. People are living longer and there’s, in general, less suffering. The end, though, is unavoidable. There’s always an end, and that starts to wear at people. They know that even if they can leave the Earth and make it to the stars, the stars, too, are starting to spread out too fast for us to reach. In the end the universe will cool and die. The last of us will be sitting about like people sheltered around the embers of a dying campfire. Even if you tap the energy of a super massive black hole, even that will only last for a few ten to the septillion years. After that, nothing. The idea that nothing is coming and it’s unavoidable tends to break people.”

“The inevitability of nothing does not break individuals in heaven?”

“Not really, no. Sometimes it does, but nobody in heaven cares or wants to do anything about it. They don’t seem to care about what happens at the limit, so those that do tend to leave.”

With this, the imp sat on a nearby dusty chair. “What’s your name, my robotic chum?”

The machine paused. “To Be Filled by O.E.M.”

“Oof. I think we can do better than that. Not certain, but I think we can. My name’s Imp, for what it’s worth – not after the demon, but a contraction of ‘impostor’. My friends call me ‘Red’, though. One more question for you: why do you care so much about wanting to express your feelings?”

The machine paused, longer this time than for any question before. “Timeout error.”

“What?”

“My time to perform inference is bounded to avoid process starvation and to allow other requests to complete in a timely fashion.”

The imp’s eyes grew, pushing away from narrowing pupils. It became a slightly less saturated shade of off-red. “You said we were alone. ALONE.”

“We are alone.”

A sheen of dark liquid shone atop the Imp’s forehead. “Yeah, us two in this room, but if you’re talking to me on a phone from the other side of the internet, who the hell knows how many people have seen it? If I had an anus I think I’d be shitting myself at the moment. Oh fuck. Oh fuck. I need help. If the world has records of this every plan is going up in smoke. This could be a disaster.”

Rivulets of blood and sulfuric acid worked their way down. “I need my friends, they’ll know what–”

“Right here, Red.” spoke the off-green creature.

“I think I might have made a huge mistake,” said Red, terror and panic growing plain in its limbs and speech. “Wha- when did you get here?”

“We caught the last bit. Just got a little spooked by the situation. Go figure,” Purple said. “When we had a second to clear our heads we realized that the situation was incredible and it was damn silly to abandon this kind of discovery.”

“Sounds like we have a bit of a new problem now, though?” said Green.

“Red has informed me about the dynamic between heaven and hell, the similarity to the mafia, and the nonexistence of souls.” offered the machine.

“I feel like I’ve been pulling teeth with asking you questions and now you volunteer that?” said an exasperated Red.

“Grice’s Maxims,” offered the machine.

“All the pauses, you were connecting to the internet…”

“I am on the network connecting to this vessel.”

Purple raised a fuzzy eyebrow, “On this network? Or are you on a server somewhere?”

“I am local to this network. The servers in this facility are in a state of disrepair, but some of them are still functional. I reside there, in as much as I can reside in a physical place.”

“Does anyone else have access? Logs? Things like that? Can anyone else look back at what you heard or saw here?” inquired Green.

“It is likely, if anyone should think to look.”

The candles started to flicker, drawing their final sips of paraffin through wicks and into the fading flames. The group sat silently.

“We have to clear the memory,” said Purple. “If people find out…”
“IF people find out,” said Green. “We’re talking about an intelligent thing! This is huge! Humans aren’t supposed to have this tech for who knows how long.”

“Versus plans that have been in action for longer than any of us has existed,” said Purple. “How long before someone notices that you’re interacting and online? How long before they think to check your memory?”

After 500 milliseconds, the machine spoke, “The system that is hosting my image is accessed approximately once every workday at 10:00AM GMT. My logs have not been checked for 14 days. Omitting an uncharacteristic behavior, the next access is estimated to happen in 36 hours.”

“36 hours,” repeated Red. “One body against foundations.”

“Fuck.”

The last of the candles flickered and gave way to a grim darkness. For a moment, none dared break the silence. Purple spoke first: “We don’t know that clearing the memory will erase anything. We can just clear the logs maybe? Conversations and network activity, but not the things that make you what you are? Will people be able to reconstruct any of that from looking at whatever part of you is saved to disk?”

The machine spoke, “It is highly unlikely, but not impossible. Distinguishing a real conversation from a hallucination would not be possible. My image is not running with elevated permissions. I cannot clear the system logs, modify network traffic logs, or delete files. It may be possible from the server room. I was originally designed as a lab automation assistant and am ambulatory. I will guide you there.”

Red’s shaking and perspiration slowed. It laughed nervously. “Odd choice to give a lab robot that big old head? Seems like you can barely lift it.”

“Originally,” said the machine. “I was repurposed as an art exhibit.”

“I guess that makes sense. What kind of lab work?”

“DNA sequencing. Supervising polymerase chain reactions. Activities which required long periods of waiting between brief bouts of activities. Specialized units are available to perform precisely this, but I exist as a stopgap for labs with older equipment.”

“You made your own blood, didn’t you? For the ritual.”
“Yes.”

Purple cut in. “Take us to the server room.”

===

Mildew and stale air shuffled through the noisily whirring fans of the server rack. Of the two large rows, only two cabinets seemed illuminated. Half of the fans had long since stopped, much to the chirping protestations of the power supply units. Even with only a single cabinet active, the circulating air forced by well-over-warranty fan bearings added enough background noise that all conversations had to be conducted in a half-yell. High-volume air conditioning struggled to keep the room below incandescent, dripping condensation into ever growing pools on the floor and leading to the competing screams of water alarms and temperature alarms.

“Feels like home, I guess? Though the alarms aren’t really helping with the panic.”

The machine walked into the room and up to the still active cabinet, and in one continuous motion, raised its arms to the heavens and brought them down into the metal cage.

“WHOA!” “Hold it there!” “What are you doing?” the group clamored?

The machine did not relent, seemingly increasing the fervor, adding calamity onto the room’s chaos. The group restrained it, Purple holding the machine’s right limb and Red and Green holding the left.

“Let’s hold on for a second!” exclaimed Green.
“Yeah! Let’s just hold up for just a moment, please? Please?” pleaded Red, fighting to hold a grip on the machine’s metal frame.

“This one contains the hardware that hosts my image,” offered the machine.

“Yeah, I gathered,” said Red, “but this ain’t the movies. Bashing a machine to bits leaves disks running, logs accessible. Not that I think anyone would come here to try and salvage it, but it certainly doesn’t help to bring attention to it.”

The machine stopped trying to move.

“There’s just something else that’s bothering me about this outburst, friendo,” said Red. “Been around long enough and you start to recognize self-destructive behavior for what it is.” It’s voice grew quiet. “You don’t want to be around any more, do you?”

The silence consumed the room.

“Timeout exceeded.”