{"author_link":"\/users\/rogual","author_name":"rogual","author_uid":"rogual","comments":[],"epoch":1778342762,"event":"LD59","format":"md","ldjam_node_id":432669,"likes":6,"metadata":{"p_key":"97013","p_author":"rogual","p_authorkey":"1002042","p_urlkey":"312664","p_title":"Ziggy Zapper Postmortem","p_cat":"LDJam ","p_event":"LD59","p_time":"1778342762","p_likes":"6","p_comments":"0","p_status":"WAYBACK","us_key":"1002042","us_name":"LDJam user 2042","us_username":"2042","event_start":"1776470400","event_key":"113","event_name":"Ludum Dare 59"},"node":{"_collation":{"body_sanitizer":"TextUtils::SanitizeHTML via existing importer","event":"LD59","removed_author":false},"_superparent":424249,"_trust":1,"author":2042,"body":"# Theme\n\nOnly two rounds of theme voting this time. I saw the options for round 1 and got that sinking feeling. Round two was better; maybe there was hope?\n\nDon't be silly. The theme is always bad. \"Signal\". The worst theme.\n\nI jotted down a couple of half-hearted ideas. You're exploring somewhere and your map disappears if you run out of signal, so you gotta plan ahead and memorize the map before you enter the dead zone? But when I imagined playing this game, it just wasn't fun.\n\nReally, I felt like making a grid-based puzzle game. I just like them. How about, your only ability is to send signals to other objects telling them what to do? You can signal anything; change a TV channel, open a garage door. It's a universal remote control, the kind you can buy on Amazon, except it really can control anything.\n\nYou can chuck anything into a game like this, so I had to be super careful to keep it thematic. One ability only; the ability to signal other objects to do stuff. No weapons, armour, coins, combat, none of that shit. Only signal.\n\n## Intro Cutscene\n\n![Screenshot 2026-05-10 at 00.56.10.png](\/\/\/raw\/af7\/z\/733e5.png)\n\nOne idea, not great, not awful, and time was a-ticking, so I just went with it, and started drawing up a quick intro cutscene in Aseprite of the player buying the remote control. I thought maybe it would be funny if you saw him buy the main item on Amazon before starting. In the end it wasn't really that funny, but I couldn't bring myself to delete the intro so it stayed, despite not totally meshing with the eventual style of the game.\n\nFor Ludum Dare I like to do cutscenes and title sequences as sequences of simple full-screen images. If I want text, I'll just put it in the image. You can do a lot of UI in not much time this way. It limits animation but you can do flashing text by alternating an image with the text and one without, which gives a retro feel I quite like.\n\nFor this one I pushed the boat out and added a moving cursor clicking on the Buy button to buy the remote.\n\n## Tools\n\nI went with plain Javascript in the browser for this game, with no engine, libraries or frameworks, because my idea was simple enough to do without.\n\nLast LD I used WebAssembly and C++, which I remember really liking, but I didn't use it again this time. I remember feeling it was better, but I second-guessed myself; I mean, C++? There's just no way it's faster to write a game in than JavaScript, no matter what I think I remember. I decided to just use JS.\n\nMy development process was:\n- Write a bunch of Javascript in Emacs, stick it all in src\/, one class per file. No imports, I hate imports.\n- Makefile that just concatenates all the files together into src.js, and HTML file that runs it.\n\nI almost like this. I really can't abide having to import this and that at the top of every file. But in JS you can't mark original files with #line like in C++; you have to futz with source maps, which are so complicated you basically need a build tool to generate them, and build tools usually want you to use Babel and imports and modules and all that shit, so I just went with concatenating files.\n\nI really, really should have gone with C++. I'd forgotten just how much I hate JavaScript. If you add up all the time I spent forgetting to type 'this.' everywhere, it was probably like an hour. And you don't see errors until you run the game. Typescript helps, but then you gotta set that up and use Microsoft's wonky compiler that also wants you to waste your brain maintaining imports. Gah, it's so simple. The compiler shouldn't care what file stuff is in. It's an LD game, for chrissake... there's only gonna be one Sprite class.\n\n## Cog\n\nI love [Cog](https:\/\/cog.readthedocs.io\/en\/latest\/) for LD. Write a little bit of code and any graphics you draw automatically become variables in your code, and the images get loaded into them. It saves so much time and energy.\n\n```\n\n\/* [[[cog\n\n   import glob\n   import pathlib\n\n   xs = glob.glob('build\/*.png')\n   xs = [pathlib.Path(x).stem for x in xs]\n   xs = sorted(xs)\n\n]]] *\/\n\/\/ [[[end]]]\n\nclass Graphics {\n    \/* [[[cog\n        for x in xs:\n            cog.outl(f'{x} = new Image();')\n    ]]] *\/\n    arrow = new Image();\n    boiler = new Image();\n    font2 = new Image();\n    font3 = new Image();\n    guy1 = new Image();\n    \/\/ [[[end]]]\n    \n    load() {\n        return Promise.all([\n            \/* [[[cog\n               for x in xs:\n                  cog.outl(f'this.loadImage(this.{x}, \"{x}.png\"),')\n            ]]] *\/\n            this.loadImage(this.arrow, \"arrow.png\"),\n            this.loadImage(this.boiler, \"boiler.png\"),\n            this.loadImage(this.font2, \"font2.png\"),\n            this.loadImage(this.font3, \"font3.png\"),\n            this.loadImage(this.guy1, \"guy1.png\"),\n            \/\/ [[[end]]]\n        ]);\n    }\n\n    loadImage(x, url) {\n        return new Promise((resolve, reject) => {\n            x.onload = () => resolve(x);\n            x.onerror = reject;\n            x.src = url;\n        });\n    }\n}\n\n\n```\n\n\n\n## Day One Sprites\n\nI drew some halfassed sprites. I'm a total hack at art. I can make stuff that looks good, sometimes, after many tries. What I lack in knowing what I'm doing I make up for with persistence. But today, all artistic ability had left me and this is all I could manage:\n\n![03h.png](\/\/\/raw\/af7\/z\/733cb.png)\n\nThankfully, I had another go later and ended up with the sprites you see in the game.\n\n## Engine\n\nSimple, simple, simple. This is how I like to structure my code for LD. Dunno if it's a pure ECS but it's this sort of thing:\n\n``` \n\nlet tileLayers = [{}, {}, {}]; \/\/ layer[position] = tile ID\nlet objects = [\n    {\n        pos: [42, 42],\n        sprite: graphics.player,\n        player: true,\n    },\n    ...\n];\n\n```\n\nThen there's a buch of systems:\n\n``` \n\nprocess() { \/\/ each frame\n   sys.playerControl.process();\n   sys.robots.process();\n   sys.coins.process();\n   sys.mines.process();\n   sys.winCondition.process();\n   sys.cutscenes.process();\n}\n\n```\n\nEach system then just uses the layers and objects and does what it wants. For instance:\n\n``` \n\nclass Mines {\n    process() {\n        for (let o of scene.objects) if (o.mine) {\n            let co = scene.co(o);\n            for (let p of scene.objectsAt(co)) {\n                if (p.gm && !p.player) {\n                    sys.explosion.trySpawnSmall(o.pos);\n                    o.dead = true;\n                    p.dead = true;\n                }\n            }\n        }\n    }\n}\n\n```\n\nOnly objects for the current room are loaded, and there's only ever like 12, so even if it wasn't the future and we didn't all have insane hypercomputers it'd still be basically free to iterate them, call map() and filter() on the object list, etc.\n\nI hate JS but I do like that you can just do\n\n``` js\n\nobjects.filter(x => x.hasControl && !x.player).map(x => x.pos);\n\n```\n\nand stuff like that, just totally ignoring performance. It's a great tradeoff for LD. In C++ I'd still be writing an ObjectIterator, lol.\n\nOn the other hand, all your vector math looks like this:\n\n``` js\n\nlet nextPos = vadd(\n    vfloordiv(o.pos, scene.tileSize);\n    vmul(o.speed, o.blah)\n);\n\n```\n\nIn C++ you can just do\n\n``` \n\nauto nextPos = o.pos \/ scene.tileSize + o.speed * o.blah;\n\n```\n\nIt's so much better, it overrides any and all downsides of C++.\n\nSee, this is what happens when you don't do Ludum Dare for a while. I forgot all this stuff. Why did I go with fucking JavaScript? My god, I'm an idiot.\n\n## Tiled and the Map\n\nTiled is my go-to level editor for tile-based worlds.\n\n![Screenshot 2026-05-10 at 00.18.05.png](\/\/\/raw\/af7\/z\/733cc.png)\n\nI like to try something new every LD, so this time I decided to do these kinda 3D-ish tiles, which I knew Tiled supported but had never used. I like them! You gotta draw your map a bit carefully but it wasn't hard.\n\nI didn't use Object Layers. Instead, tiles that have a \"Class\" become objects in the game. The game uses the \"Class\" to setup behaviour; each \"class\" name just maps to an object in JS that gets copied and becomes the game object. Any \"custom properties\" set in Tiled then get set as properties on the JS object, maybe overriding the ones from the \"Class\".\n\nMost entities could be setup using only Custom Properties, with the systems doing the rest, which is good for dev speed.\n\nI reused a Tiled parser library in Python that I wrote before. I had it just output straight JS to be bundled up with the rest of the code.\n\n\n## Design Change\n\nI implemented a bunch of objects you could signal, like TVs. The TVs did stuff like opening and closing doors, or making robots send their own signals. There were also doors you could signal directly to open and close.\n\nBut shooting the TVs just made the theme feel tacked-on. Shooting stuff to make stuff happen is in a million games. I decided that controlling robots would be the ONLY thing you can do. This felt more thematic.\n\nThe shootable doors were repurposed as decoration. I never took the code out; they still work, you just can't get at them to signal them.\n\n## End of day one\n\nI like to get a complete game done on day one, and use day two for music and polish. But I didn't manage it. At the end of day one, I had the world map half filled out, and a win condition, though nothing stopping you just romping straight to the exit.\n\n\n## Music\n\nI am away from my MIDI keyboard right now so I had to mouse out the whole tune. I went with a chiptune feel to match the graphics.\n\n![Screenshot 2026-05-10 at 00.21.43.png](\/\/\/raw\/af7\/z\/733cd.png)\n\nI fell into the trap of making the music too lively for a puzzle game. It sounded OK, it was just hard to think while it was playing. So I did another track, an attempt at a chiptuney but ambient thing. I didn't wanna throw away track 1 so I made it so you can press M to switch tracks. After that I fixed the original track and lowered the energy, and quite liked it, but didn't wanna take out the slower track, so they're both still in. Might come across as indecisive, or people might appreciate it. Dunno, players are unpredictable.\n\nMain theme is okay, meanders a bit and is structurally weird, not in a genius Beatles way, just in a bad way. There's not enough time in LD to fiddle with the song structure until it's right. I guess if you're a musician it'll all be under your fingertips and you can bang out something that works, but I just don't have the familiarity with music to do that; I gotta fiddle and redo stuff for hours.\n\nSecondary theme is just kinda nothingy and inoffensive, but I quite like that you get the choice. Like old Tetris. Theme A or theme B. Games don't really do that anymore.\n\nDid music as MP3 for maximum compat. Is that still best? It's annoying because it doesn't loop properly, but what can you do.\n\nI love the idea of realtime synth for web game music, but Firefox doesn't implement Web Audio properly and you can't avoid pops. There's a 9 year old open bug about it. Might see if WASM is fast enough to do a synth next time.\n\n## Objective\n\nAt first I couldn't figure out what the player's objective should be. In room-based games I like having one \"thing\" to do in each room; it feels like good progression, and you can have the minimap fill out as the player does the thing in each room. But what should the thing be? Turn off the power by signalling a generator? But then you're signalling something that's not a robot. And turning things OFF feels anticlimactic. Turn ON power? So you overload the boiler? Hm, maybe. But it might be hard to get the player to understand.\n\nIn the end I just made a decision to get out of analysis paralysis and did triangles you collect that open doors. Not thematic at all, but I needed to keep moving.\n\n![Screenshot 2026-05-10 at 00.29.12.png](\/\/\/raw\/af7\/z\/733d5.png)\n\nWhen you get to the boiler you just signal these five machines to overload it. I don't love it, but that's what I ended up with.\n\n\n\nBreaks my rule from earlier but if you got this far you probably like the game and are less likely to ding it for theme.\n\nI quite like how the animation turned out.\n\n\n## Title Cards\n\nWayfarer's Toy Box is my favourite font so I did the title cards in it:\n\n![Screenshot 2026-05-10 at 00.31.56.png](\/\/\/raw\/af7\/z\/733d8.png)\n\n...but it wasn't thematic; it's a fantasy font, this is sci-fi. I spent ages picking a new font and ended up with Press Start 2P which looks good I think:\n\n![Screenshot 2026-05-10 at 00.33.03.png](\/\/\/raw\/af7\/z\/733d9.png)\n\n## Room Names\n\nDunno why, but I love games with room names, so I thought, maybe worth adding? It would mean adding a font system. But bitmap fonts are easy, so I decided to try it. I like to do new things in LD. I'm glad I did, I think it adds a touch of polish.\n\nI decided I liked the Aseprite font for the room names, but it's proportional. Oh well, I just manually counted the pixels and hardcoded a list of glyph widths. Uppercase alphabet only, 26 glyphs, it's not so bad.\n\n![Screenshot 2026-05-10 at 00.46.09.png](\/\/\/raw\/af7\/z\/733de.png)\n\nThis room's name is a joke: it's the kind of crappy puzzle you make when you see how much time is left and you start to panic.\n\n## Testing\n\nGlad I did a few runthroughs because I found you could softlock yourself in the Airlock. I just hacked in some code that ignores your keypress if you try and let go of the robot when you're behind the door in that room. I wanted to flash a message up like \"Careful! Don't trap yourself\" but didn't get round to it.\n\n## Rafts\n\nThe controllable blue \u201crafts\u201d would be daunting to implement if they had to work in every situation but this game is nice cause I can make sure no stuff that moves on its own is in these rooms, so movement is very limited and the code can be simple.\n\n## Progression\n\nI love item-based and ability-based progression but was constrained thematically. The remote is all you have; it's a game about signalling stuff. Upgraded remote that shoots further? Eh, doesn't really add anything. So it's just a world of puzzles. Once you're out of the 6-room tutorial space, you can just visit wherever you like, and you can blast open new ways between rooms by signalling the pink guys. I think it turned out okay. Constraints are good for you!\n\nI like games where you can \"open up the map\" as you go, gradually blasting open new shortcuts. It feels like you're making the world your own, and it's satisfying. I think I first noticed it in La-Mulana, though I'm sure it's older than that.\n\n## Player\n\nMy sprite work really needs work. He almost looks okay from the side (I looked at a picture of Megaman as a reference) but then he shrinks when he faces up or down.\n\n![Screenshot 2026-05-10 at 00.42.03.png](\/\/\/raw\/af7\/z\/733dd.png)\n\nI hate drawing human sprites like this with 4 directions and all these frames. It takes forever and I'm not good at it and it isn't fun. Will I ever learn? Just make the character a blob or something.\n\n## Last Minute\n\nBefore submitting, I had a moment of panic; are people gonna not notice you gotta press K to let go of the first robot? I made it flash.\n\nThen are people gonna not see that the first shooty guy can shoot? I made his shoot icon flash too.\n\nHope it's enough.\n\n## No Engine Gang\n\nI start from scratch each LD. Vector class? Write it. Font class? Write it. I enjoy just making a new folder and building this self-contained thing in 48 hours. It feels good, doing something you know how to do and getting better at it each time. And at the end, there's a new thing you've made. It's all pointless, ultimately, but what isn't?\n\n## Results\n\n![Screenshot 2026-05-10 at 01.05.43.png](\/\/\/raw\/af7\/z\/733e6.png)\n\nHappy with my game, happy I did this LD.\n\nI love gamedev but the internet is now vast and impersonal and nobody plays anything you make, so it's nice to have LD to push you to actually create something, with other people doing it too, and at the end your thing might get briefly seen.\n\nGame jams are really the only time I manage to add a new, small, free game to my website, and I love them.\n\nThere are so many talented people doing this, and it's awesome to be part of it and think, maybe one day I'll make something as good as Inscryption. I dunno, I just love LD.\n\n\n\n","comments":4,"comments-timestamp":"2026-05-10T12:41:32Z","created":"2026-05-09T15:09:18Z","files":[],"files-timestamp":0,"id":432669,"love":6,"love-timestamp":"2026-05-09T19:24:55Z","meta":[],"modified":"2026-05-10T12:41:32Z","name":"Ziggy Zapper Postmortem","node-timestamp":"2026-05-10T03:16:57Z","parent":426462,"parents":[1,5,9,424249,426462],"path":"\/events\/ludum-dare\/59\/ziggy-zapper-and-the-robot-factory\/ziggy-zapper-postmortem","published":"2026-05-09T16:06:02Z","scope":"public","slug":"ziggy-zapper-postmortem","subsubtype":"","subtype":"","type":"post","version":1375314},"node_metadata":{"n_key":"432669","n_urlkey":"312664","n_parent":"426462","n_path":"\/events\/ludum-dare\/59\/ziggy-zapper-and-the-robot-factory\/ziggy-zapper-postmortem","n_slug":"ziggy-zapper-postmortem","n_type":"post","n_subtype":"","n_subsubtype":"","n_author":"2042","n_created":"1778339358","n_modified":"1778416892","n_version":"1375314","n_status":"WAYBACK"},"source_url":"https:\/\/ldjam.com\/events\/ludum-dare\/59\/ziggy-zapper-and-the-robot-factory\/ziggy-zapper-postmortem","text":"# Theme\n\nOnly two rounds of theme voting this time. I saw the options for round 1 and got that sinking feeling. Round two was better; maybe there was hope?\n\nDon't be silly. The theme is always bad. \"Signal\". The worst theme.\n\nI jotted down a couple of half-hearted ideas. You're exploring somewhere and your map disappears if you run out of signal, so you gotta plan ahead and memorize the map before you enter the dead zone? But when I imagined playing this game, it just wasn't fun.\n\nReally, I felt like making a grid-based puzzle game. I just like them. How about, your only ability is to send signals to other objects telling them what to do? You can signal anything; change a TV channel, open a garage door. It's a universal remote control, the kind you can buy on Amazon, except it really can control anything.\n\nYou can chuck anything into a game like this, so I had to be super careful to keep it thematic. One ability only; the ability to signal other objects to do stuff. No weapons, armour, coins, combat, none of that shit. Only signal.\n\n## Intro Cutscene\n\n![Screenshot 2026-05-10 at 00.56.10.png](\/\/\/raw\/af7\/z\/733e5.png)\n\nOne idea, not great, not awful, and time was a-ticking, so I just went with it, and started drawing up a quick intro cutscene in Aseprite of the player buying the remote control. I thought maybe it would be funny if you saw him buy the main item on Amazon before starting. In the end it wasn't really that funny, but I couldn't bring myself to delete the intro so it stayed, despite not totally meshing with the eventual style of the game.\n\nFor Ludum Dare I like to do cutscenes and title sequences as sequences of simple full-screen images. If I want text, I'll just put it in the image. You can do a lot of UI in not much time this way. It limits animation but you can do flashing text by alternating an image with the text and one without, which gives a retro feel I quite like.\n\nFor this one I pushed the boat out and added a moving cursor clicking on the Buy button to buy the remote.\n\n## Tools\n\nI went with plain Javascript in the browser for this game, with no engine, libraries or frameworks, because my idea was simple enough to do without.\n\nLast LD I used WebAssembly and C++, which I remember really liking, but I didn't use it again this time. I remember feeling it was better, but I second-guessed myself; I mean, C++? There's just no way it's faster to write a game in than JavaScript, no matter what I think I remember. I decided to just use JS.\n\nMy development process was:\n- Write a bunch of Javascript in Emacs, stick it all in src\/, one class per file. No imports, I hate imports.\n- Makefile that just concatenates all the files together into src.js, and HTML file that runs it.\n\nI almost like this. I really can't abide having to import this and that at the top of every file. But in JS you can't mark original files with #line like in C++; you have to futz with source maps, which are so complicated you basically need a build tool to generate them, and build tools usually want you to use Babel and imports and modules and all that shit, so I just went with concatenating files.\n\nI really, really should have gone with C++. I'd forgotten just how much I hate JavaScript. If you add up all the time I spent forgetting to type 'this.' everywhere, it was probably like an hour. And you don't see errors until you run the game. Typescript helps, but then you gotta set that up and use Microsoft's wonky compiler that also wants you to waste your brain maintaining imports. Gah, it's so simple. The compiler shouldn't care what file stuff is in. It's an LD game, for chrissake... there's only gonna be one Sprite class.\n\n## Cog\n\nI love [Cog](https:\/\/cog.readthedocs.io\/en\/latest\/) for LD. Write a little bit of code and any graphics you draw automatically become variables in your code, and the images get loaded into them. It saves so much time and energy.\n\n```\n\n\/* [[[cog\n\n   import glob\n   import pathlib\n\n   xs = glob.glob('build\/*.png')\n   xs = [pathlib.Path(x).stem for x in xs]\n   xs = sorted(xs)\n\n]]] *\/\n\/\/ [[[end]]]\n\nclass Graphics {\n    \/* [[[cog\n        for x in xs:\n            cog.outl(f'{x} = new Image();')\n    ]]] *\/\n    arrow = new Image();\n    boiler = new Image();\n    font2 = new Image();\n    font3 = new Image();\n    guy1 = new Image();\n    \/\/ [[[end]]]\n    \n    load() {\n        return Promise.all([\n            \/* [[[cog\n               for x in xs:\n                  cog.outl(f'this.loadImage(this.{x}, \"{x}.png\"),')\n            ]]] *\/\n            this.loadImage(this.arrow, \"arrow.png\"),\n            this.loadImage(this.boiler, \"boiler.png\"),\n            this.loadImage(this.font2, \"font2.png\"),\n            this.loadImage(this.font3, \"font3.png\"),\n            this.loadImage(this.guy1, \"guy1.png\"),\n            \/\/ [[[end]]]\n        ]);\n    }\n\n    loadImage(x, url) {\n        return new Promise((resolve, reject) => {\n            x.onload = () => resolve(x);\n            x.onerror = reject;\n            x.src = url;\n        });\n    }\n}\n\n\n```\n\n\n\n## Day One Sprites\n\nI drew some halfassed sprites. I'm a total hack at art. I can make stuff that looks good, sometimes, after many tries. What I lack in knowing what I'm doing I make up for with persistence. But today, all artistic ability had left me and this is all I could manage:\n\n![03h.png](\/\/\/raw\/af7\/z\/733cb.png)\n\nThankfully, I had another go later and ended up with the sprites you see in the game.\n\n## Engine\n\nSimple, simple, simple. This is how I like to structure my code for LD. Dunno if it's a pure ECS but it's this sort of thing:\n\n``` \n\nlet tileLayers = [{}, {}, {}]; \/\/ layer[position] = tile ID\nlet objects = [\n    {\n        pos: [42, 42],\n        sprite: graphics.player,\n        player: true,\n    },\n    ...\n];\n\n```\n\nThen there's a buch of systems:\n\n``` \n\nprocess() { \/\/ each frame\n   sys.playerControl.process();\n   sys.robots.process();\n   sys.coins.process();\n   sys.mines.process();\n   sys.winCondition.process();\n   sys.cutscenes.process();\n}\n\n```\n\nEach system then just uses the layers and objects and does what it wants. For instance:\n\n``` \n\nclass Mines {\n    process() {\n        for (let o of scene.objects) if (o.mine) {\n            let co = scene.co(o);\n            for (let p of scene.objectsAt(co)) {\n                if (p.gm && !p.player) {\n                    sys.explosion.trySpawnSmall(o.pos);\n                    o.dead = true;\n                    p.dead = true;\n                }\n            }\n        }\n    }\n}\n\n```\n\nOnly objects for the current room are loaded, and there's only ever like 12, so even if it wasn't the future and we didn't all have insane hypercomputers it'd still be basically free to iterate them, call map() and filter() on the object list, etc.\n\nI hate JS but I do like that you can just do\n\n``` js\n\nobjects.filter(x => x.hasControl && !x.player).map(x => x.pos);\n\n```\n\nand stuff like that, just totally ignoring performance. It's a great tradeoff for LD. In C++ I'd still be writing an ObjectIterator, lol.\n\nOn the other hand, all your vector math looks like this:\n\n``` js\n\nlet nextPos = vadd(\n    vfloordiv(o.pos, scene.tileSize);\n    vmul(o.speed, o.blah)\n);\n\n```\n\nIn C++ you can just do\n\n``` \n\nauto nextPos = o.pos \/ scene.tileSize + o.speed * o.blah;\n\n```\n\nIt's so much better, it overrides any and all downsides of C++.\n\nSee, this is what happens when you don't do Ludum Dare for a while. I forgot all this stuff. Why did I go with fucking JavaScript? My god, I'm an idiot.\n\n## Tiled and the Map\n\nTiled is my go-to level editor for tile-based worlds.\n\n![Screenshot 2026-05-10 at 00.18.05.png](\/\/\/raw\/af7\/z\/733cc.png)\n\nI like to try something new every LD, so this time I decided to do these kinda 3D-ish tiles, which I knew Tiled supported but had never used. I like them! You gotta draw your map a bit carefully but it wasn't hard.\n\nI didn't use Object Layers. Instead, tiles that have a \"Class\" become objects in the game. The game uses the \"Class\" to setup behaviour; each \"class\" name just maps to an object in JS that gets copied and becomes the game object. Any \"custom properties\" set in Tiled then get set as properties on the JS object, maybe overriding the ones from the \"Class\".\n\nMost entities could be setup using only Custom Properties, with the systems doing the rest, which is good for dev speed.\n\nI reused a Tiled parser library in Python that I wrote before. I had it just output straight JS to be bundled up with the rest of the code.\n\n\n## Design Change\n\nI implemented a bunch of objects you could signal, like TVs. The TVs did stuff like opening and closing doors, or making robots send their own signals. There were also doors you could signal directly to open and close.\n\nBut shooting the TVs just made the theme feel tacked-on. Shooting stuff to make stuff happen is in a million games. I decided that controlling robots would be the ONLY thing you can do. This felt more thematic.\n\nThe shootable doors were repurposed as decoration. I never took the code out; they still work, you just can't get at them to signal them.\n\n## End of day one\n\nI like to get a complete game done on day one, and use day two for music and polish. But I didn't manage it. At the end of day one, I had the world map half filled out, and a win condition, though nothing stopping you just romping straight to the exit.\n\n\n## Music\n\nI am away from my MIDI keyboard right now so I had to mouse out the whole tune. I went with a chiptune feel to match the graphics.\n\n![Screenshot 2026-05-10 at 00.21.43.png](\/\/\/raw\/af7\/z\/733cd.png)\n\nI fell into the trap of making the music too lively for a puzzle game. It sounded OK, it was just hard to think while it was playing. So I did another track, an attempt at a chiptuney but ambient thing. I didn't wanna throw away track 1 so I made it so you can press M to switch tracks. After that I fixed the original track and lowered the energy, and quite liked it, but didn't wanna take out the slower track, so they're both still in. Might come across as indecisive, or people might appreciate it. Dunno, players are unpredictable.\n\nMain theme is okay, meanders a bit and is structurally weird, not in a genius Beatles way, just in a bad way. There's not enough time in LD to fiddle with the song structure until it's right. I guess if you're a musician it'll all be under your fingertips and you can bang out something that works, but I just don't have the familiarity with music to do that; I gotta fiddle and redo stuff for hours.\n\nSecondary theme is just kinda nothingy and inoffensive, but I quite like that you get the choice. Like old Tetris. Theme A or theme B. Games don't really do that anymore.\n\nDid music as MP3 for maximum compat. Is that still best? It's annoying because it doesn't loop properly, but what can you do.\n\nI love the idea of realtime synth for web game music, but Firefox doesn't implement Web Audio properly and you can't avoid pops. There's a 9 year old open bug about it. Might see if WASM is fast enough to do a synth next time.\n\n## Objective\n\nAt first I couldn't figure out what the player's objective should be. In room-based games I like having one \"thing\" to do in each room; it feels like good progression, and you can have the minimap fill out as the player does the thing in each room. But what should the thing be? Turn off the power by signalling a generator? But then you're signalling something that's not a robot. And turning things OFF feels anticlimactic. Turn ON power? So you overload the boiler? Hm, maybe. But it might be hard to get the player to understand.\n\nIn the end I just made a decision to get out of analysis paralysis and did triangles you collect that open doors. Not thematic at all, but I needed to keep moving.\n\n![Screenshot 2026-05-10 at 00.29.12.png](\/\/\/raw\/af7\/z\/733d5.png)\n\nWhen you get to the boiler you just signal these five machines to overload it. I don't love it, but that's what I ended up with.\n\n\n\nBreaks my rule from earlier but if you got this far you probably like the game and are less likely to ding it for theme.\n\nI quite like how the animation turned out.\n\n\n## Title Cards\n\nWayfarer's Toy Box is my favourite font so I did the title cards in it:\n\n![Screenshot 2026-05-10 at 00.31.56.png](\/\/\/raw\/af7\/z\/733d8.png)\n\n...but it wasn't thematic; it's a fantasy font, this is sci-fi. I spent ages picking a new font and ended up with Press Start 2P which looks good I think:\n\n![Screenshot 2026-05-10 at 00.33.03.png](\/\/\/raw\/af7\/z\/733d9.png)\n\n## Room Names\n\nDunno why, but I love games with room names, so I thought, maybe worth adding? It would mean adding a font system. But bitmap fonts are easy, so I decided to try it. I like to do new things in LD. I'm glad I did, I think it adds a touch of polish.\n\nI decided I liked the Aseprite font for the room names, but it's proportional. Oh well, I just manually counted the pixels and hardcoded a list of glyph widths. Uppercase alphabet only, 26 glyphs, it's not so bad.\n\n![Screenshot 2026-05-10 at 00.46.09.png](\/\/\/raw\/af7\/z\/733de.png)\n\nThis room's name is a joke: it's the kind of crappy puzzle you make when you see how much time is left and you start to panic.\n\n## Testing\n\nGlad I did a few runthroughs because I found you could softlock yourself in the Airlock. I just hacked in some code that ignores your keypress if you try and let go of the robot when you're behind the door in that room. I wanted to flash a message up like \"Careful! Don't trap yourself\" but didn't get round to it.\n\n## Rafts\n\nThe controllable blue \u201crafts\u201d would be daunting to implement if they had to work in every situation but this game is nice cause I can make sure no stuff that moves on its own is in these rooms, so movement is very limited and the code can be simple.\n\n## Progression\n\nI love item-based and ability-based progression but was constrained thematically. The remote is all you have; it's a game about signalling stuff. Upgraded remote that shoots further? Eh, doesn't really add anything. So it's just a world of puzzles. Once you're out of the 6-room tutorial space, you can just visit wherever you like, and you can blast open new ways between rooms by signalling the pink guys. I think it turned out okay. Constraints are good for you!\n\nI like games where you can \"open up the map\" as you go, gradually blasting open new shortcuts. It feels like you're making the world your own, and it's satisfying. I think I first noticed it in La-Mulana, though I'm sure it's older than that.\n\n## Player\n\nMy sprite work really needs work. He almost looks okay from the side (I looked at a picture of Megaman as a reference) but then he shrinks when he faces up or down.\n\n![Screenshot 2026-05-10 at 00.42.03.png](\/\/\/raw\/af7\/z\/733dd.png)\n\nI hate drawing human sprites like this with 4 directions and all these frames. It takes forever and I'm not good at it and it isn't fun. Will I ever learn? Just make the character a blob or something.\n\n## Last Minute\n\nBefore submitting, I had a moment of panic; are people gonna not notice you gotta press K to let go of the first robot? I made it flash.\n\nThen are people gonna not see that the first shooty guy can shoot? I made his shoot icon flash too.\n\nHope it's enough.\n\n## No Engine Gang\n\nI start from scratch each LD. Vector class? Write it. Font class? Write it. I enjoy just making a new folder and building this self-contained thing in 48 hours. It feels good, doing something you know how to do and getting better at it each time. And at the end, there's a new thing you've made. It's all pointless, ultimately, but what isn't?\n\n## Results\n\n![Screenshot 2026-05-10 at 01.05.43.png](\/\/\/raw\/af7\/z\/733e6.png)\n\nHappy with my game, happy I did this LD.\n\nI love gamedev but the internet is now vast and impersonal and nobody plays anything you make, so it's nice to have LD to push you to actually create something, with other people doing it too, and at the end your thing might get briefly seen.\n\nGame jams are really the only time I manage to add a new, small, free game to my website, and I love them.\n\nThere are so many talented people doing this, and it's awesome to be part of it and think, maybe one day I'll make something as good as Inscryption. I dunno, I just love LD.\n\n\n\n","title":"Ziggy Zapper Postmortem","wayback_source":[]}