All posts by Eevee

Weekly roundup: All that glistens

Post Syndicated from Eevee original

  • fox flux: I’ve been kind of taking a break from physics, but I did have some ideas about how extrinsic velocity could work, got them working for a conveyor belt, and then extended the same concept to a rough rework of pushing. It works surprisingly well given how little time I spent on it, so that’s very promising.

  • gleam: I put together the first production VN with it, and although I had to cheat and hand-edit a bit, GLEAM grew a bunch of useful stubs of features along the way! It’s getting there. Also I discovered a fascinating edge case in Firefox when you have 800 images visible but all but one of them have zero opacity.

Weekly roundup: Waste not, want not

Post Syndicated from Eevee original

Wee bit late, but I’ve been busy.

  • fox flux: I wrote some push physics tests, now that it’s possible to do that. Removed some old obsolete garbage I’ve hated for like a year, hooray. And then I got stuck in a horrible loop of coming up with a new idea for how to do pushing, realizing it won’t work in some case, making a thousand notes, rinse and repeat.

    I can’t even fall back to spriting, because my tablet broke! Argh.

  • doom: I made WasteNot, a ridiculous ZDoom mod that tracks how much ammo/health/armor you lose by grabbing items when you’re close to the max amount you can carry. Also I put some Doom stuff on Itch and the landing page here.

Very exciting week. I spent a lot of it exhausted, after rushing to invert my sleep schedule in not very much time.

Weekly roundup: Breaking up (code) is hard to do

Post Syndicated from Eevee original

  • irl: I went to the dentist, which I think was the last of the errand backlog, hallelujah.

  • fox flux: Continuing on from last week, I threw myself headfirst into this idea of splitting up base actor code.

    I tried it against Isaac’s Descent HD (my LÖVE port of Isaac’s Descent that I only ever released on Patreon), since it has a very small number of abilities and objects, and just went hog wild.

    The results have been promising! Most of it went much more smoothly than I expected. A little bit was much more horrible than I expected. But within the space of a week I’d gotten a rough first attempt working, ported it to fox flux, and gotten the game… um… mostly limping along. There’s still some lingering fallout, and I haven’t even gotten to Lexy herself yet, but it seems like this will be an overall improvement. I can even write tests now! Tests!

    I also did some more work on the revamped Lexy sprites, but then my tablet broke — again — so that came to a screeching halt.

  • blog: I started on a second post (without finishing the first, hm), or more specifically, I started on a complicated but very cool interactive doohickey to accompany the second post. Very excited. Should probably, like, finish one of them.

  • alice: Planning, writing.

Weekly roundup: Chugging

Post Syndicated from Eevee original

I’m discovering all kinds of ancient damage in myself, but I’m chugging along!

  • irl: We’re making our way through an endless backlog of errands. There are so many. But they’re getting done, which is good! Also the internet was out for a day so that was fun.

  • gleam: It got a big ol’ refactor, which left it working exactly the same, so that’s fun! Stubbed out enough features that it’s now (technically…) possible to use it to make a VN from scratch, rather than just previewing and making minor edits to an existing one. I split apart the player from the editor and ensured the player works standalone; I added a loading screen; and I finally got around to adding back music support. It’s coming along!

  • art: I did like half a dozen daily comics? You know. “Daily”. The last one was… oops, almost a week ago. I’m sure I’ll get back to them real soon now.

    Also some sketching! I’ve almost filled a real physical sketchbook for only the second time in my life.

  • stream: I took a crack at Sigil on UV, trying for 100% kills and secrets, with… mixed results! Great fun, I guess.

  • fox flux: I am admittedly struggling a bit.

    We played Cadence of Hyrule; I found the art style inspiring; I tried to glean something from it that I could apply to my sprite work; and I realized basically everything I’ve drawn is counter to what I most like in pixel art. It was a struggle just to produce the few tiles I have so far, so I don’t know what to feel or do here.

    At Ash’s suggestion, I started trying to draw some Dewclaw tiles, but boy! That’s difficult. How do you design small pieces that can be put together into something sufficiently reminiscent of a city? I don’t even know how to draw a city, not really; I’m remarkably terrible at filling in small details of a concrete place or situation.

    And then I tried to do something technical and split up Lexy’s code — since historically it’s been littered with a ton of if self.form == 'foo' then ... special cases — only to discover that it breaks everything. Now I’m trying a different approach, which is not breaking everything quite as badly, but which has massive repercussions and possibly slows the game down by double-digit percent. Love game development.

  • alice: Still plodding along on Alice’s Day Off. I wrote a half-draft, half-outline of another route. Just been hard to get in the right mood, lately.

  • blog: I started on a post! Wow! Remember when I used to write posts? I’d like to do that again. I’ve got one half-done and ideas for a few more, if I can just get some momentum going again.

I’ll get there.

Weekly roundup: GLEAM

Post Syndicated from Eevee original

Hello. I don’t know how I am! But I did some stuff.

  • fox flux: Workin’ on a new walk animation.

  • gleam: After years of saying I should totally do so, I finally started making a little editor for the Floraverse web VN engine. I’ve been gradually teaching it to load and play back the existing VNs (from scratch, because the old code is Quite Bad), and it’s finally hitting the point where it’s possible to make something from scratch. Sort of. I mean, there’s no saving or loading or exporting, and a bunch of stuff is broken, but you know. Getting there. Maybe I’ll even make a VN myself.

  • art: I started doing daily comics again and then forgot after day 1.

GLEAM has basically taken up my whole week; turns out that while client-side web stuff has improved dramatically, writing an editor is still an incredible pain in the ass. Getting somewhere, though.

Oh, and that marks the end of my journal! Cool, I guess. I don’t tend to fill up notebooks very often.

Weekly roundup: Recharging

Post Syndicated from Eevee original

Hello. I’m kinda up and down but recovering, I think.

  • art: I drew a bunch of porn, most of which is on my porn gallery (warning: porn). I even wrote some stuff, which will never see the light of day.

    I also finished putting all my 2015 art on my clean gallery, if you want to see the arc of my art journey, which slowed considerably after the first couple years. Kinda bummed about that.

  • irl: We have done so many fucking errands you have no idea.

  • gleam: I put together another Floraverse VN, but more importantly (to me anyway?), I’ve actually made some inroads on making a little editor for these things. It’s not entirely functional yet — did you know that drag-and-drop is a huge pain in the ass — but it resembles something and I’m making swift progress. Hallelujah.

  • fox flux: I gathered up like a dozen pages of dense notes and kinda consolidated them into one place, which is nice.

    I also, accidentally, uh, okay funny story, I was taking notes on paper and I doodled Lexy pulling a lever, and later I tried to sprite it based on her current sprite, and I didn’t like it a lot, so I pixel-traced over the drawing instead, and it was way better, and this led me on a journey that ended up with a completely different sprite design. It’s a thousand times better in every possible way, but I’ve also invented a massive pile of work for myself, because now I have to redesign a dozen variants of her and redraw like 200 sprite frames. It kind of feels like I’m back to square one and have accomplished nothing at all on this game, in fact! But fuck me it’s so much better

Next week marks a fun milestone. I’m now on the very last page of the book I’ve been using to jot this stuff down, one week per page. It spans almost four years. I should probably find another one real quick.

Weekly roundup: Vacay

Post Syndicated from Eevee original

I’m burnt out. I just can’t get into anything. And I’ve been dealing with a huge stack of accumulated errands from last month. And it’s fucking hot in here and that just pisses me off all the time???

So I’m trying to step back and chill and draw and hang out with folks and whatever. Sorry. I don’t know why I’m apologizing.

  • fox flux: Added some sparkles to a key.

  • mario maker: Made Star Anise’s Dream Land (5TQJG0MNG), a happy-go-lucky level inspired by my cat, and Koopa Valley (463-9CJPVG), an attempt at some standard friendly SMW-like fare. Also made half of like six other levels, but I’m having trouble even finishing those.

  • art: I’ve been drawing, just, a bunch of porn. It’s nice to be getting back into that. Drawing, I mean, not porn. But porn too.

See you next week.

Weekly roundup: Let’s try that again

Post Syndicated from Eevee original

Hello, hello! It’s been a while. June ended up being an avalanche of errands and personal problems that neatly segued into each other, over and over. Good times! I think everything’s settled down now, but who knows.

Anyway, that gives us three weeks to catch up on:

  • fox flux: Finished and committed a bunch of half-implemented ideas in an attempt to get git clean for once (still more to go though); took a crack at porting sound effects from MilkyTracker and sfxr to Sunvox, which was much harder than expected; experimented with a nighttime palette; drew some new vastly improved swimming sprites from scratch.

    Did some work on the camera, which has always been pretty lazy. (I’ve improved it a lot since that recording, so don’t judge it too harshly.) Started on a redone menu, which should be a great improvement over the demo’s menu which was just “resume” and “quit”. Redrew the base dialogue portraits, and they look fantastic, but apparently I never tweeted about that, but you can see it in the next link!

    After spending all this time on miscellaneous mechanics and other bits and pieces, I decided it was finally time to get a basic gameplay loop going — enter a level, get some stuff, leave the level. The results are extremely rough, but I’ve made a start! It’s turning into a game! Which is weird because it was already a game once!

  • secret game engine thing: Not a lot, but I’ve cleared some design roadblocks that were seriously getting in the way.

  • art: Some doodles. Also I drew some beautiful gift art for my and Ash’s Metapodth anniversary.

  • alice’s day off: Wrote some stuff! It’s a miracle.

Currently attempting to get my ass back in gear, with moderate success.

Weekly roundup: Ironically stable

Post Syndicated from Eevee original

I remain on a fox flux kick. Keep trying to do other stuff as well and then not doing that? Hm.

  • fox flux: Documented the hell out of all my rewritten collision code, removed some old hacks, put some methods on a new type that was an ad-hoc table before, and fixed a final remaining edge case in a satisfying way. Did kinda start writing about all this but didn’t finish it yet.

    Then I fixed all the stuff I’d broken about pushing in the process, and cleaned it up somewhat.

    Water is gradually improving but still kinda rough.

    Also added some experimental candy? Candy is pretty good.

    I did some more overhauling of the palette; I’m really really liking how it’s coming out.

    And also a preposterous amount of brainstorming. Like I’ve got half a dozen sheets of paper with tiny 8pt notes crammed on them. This ought to be a fun game.

Welp, back to that, then.

Weekly roundup: Exactly at the top

Post Syndicated from Eevee original

Hello! I’ve been a little preoccupied with meatspace things again, but here is some digital stuff.

  • fox flux: I have been a busy little beaver. I consolidated 1D and 2D motion, made ground adherence more conservative about how far it tries to drop you, and totally overhauled climbing to not incredibly suck. But who cares about any of that.

    What I really did is spend like a solid week overhauling collision detection. Finally, after years of wanting it, I have overlap resolution and nearly zero-cost contact detection! Which means that if objects overlap by some horrible twist of fate, instead of freely clipping through each other, they’re now free to move apart but not closer together. It’s god damn magic. Also I now know exactly where you’re touching objects which will probably come in handy for like, critters that walk back and forth on a platform without walking off it? Or something? I forget exactly why I wanted that but hey it’s nice.

    As an added bonus, I can finally fix climbing off the top of ladders — instead of hopping off the top and then landing, you stop at exactly the top, which is incredibly satisfying.

    I will almost certainly be wringing a blog post out of all this.

  • art: I worked more on that animation and then kinda forgot about it. Hm. Also some doodling or whatever?

    I drew a little… comic? Series of panels? I drew a thing about a ground adherence bug I ran into, and also a general explanation of ground adherence. It’s on Twitter, though it seems worth preserving elsewhere, once I figure out where that is.

  • gleam: I finally made some kind of real start on an editor for the little Flora VNs I put together. It doesn’t do a lot yet, but it has some UI, which is backwards from how I usually make these things, so that’s promising.

  • stream: Ash streamed some Spyro while I commentated, and then I streamed some Hat in Time while they commentated, and that was all great.

I am juggling too many things but I extremely want to get them all moving so I guess I’ll get back to it!

Weekly roundup: Pushing it

Post Syndicated from Eevee original

I remember saying something about balancing my time better, and that did not happen.

  • fox flux: I basically spent the whole week working on push physics. It was tough going at first, but I finally got it working correctly which feels like a goddamn Christmas miracle.

    I probably did some sprite work in there somewhere too, to let my brain cool down a bit.

    I’m excited about this game, ah! There’s a ton of work to go but I’m actually starting to see some mechanics come together.

  • stream: Ash and I played a ridiculous adventure game for a bit. Hm, maybe we should finish that. It’ll be on YouTube, uh, eventually.

Not so much this week; I ended up nocturnal and that threw me entirely for a loop. Back to waking with the sun now and feeling pretty good, so, fingers crossed.

Weekly roundup: In flux 2

Post Syndicated from Eevee original

  • fox flux: I’m not sure what happened but I mostly did fox flux this week! It’s kind of a huge mess at the moment — I have a thousand lines of uncommitted changes from a dozen different half-finished experimental ideas, which makes starting on a new idea a bit daunting. So I spent some time finishing up and committing about half of that stuff, and then… um… started a few new half-finished experimental ideas. I am good at software development.

    I got a bit lost in the weeds trying to make the physics of pushing blocks work a bit better, which I’d still like to do, but I think it might require completely rethinking how pushing works (mainly in order to avoid a two-pixel gap in some situations, sigh, but that kinda thing’s important to me) and also redoing how friction and whatnot works. I can’t wait.

    Also been finishing up some visual effects I started ages ago but didn’t quite figure out, filling in some missing pixel art (which I think I got a little better + faster at), and fleshing out mechanics + trying out some new ones. It turns out, if you think your game needs more mechanics, a good place to start is to implement the existing ones so you can run around and play with them freely and see what new stuff comes to mind. Who knew?

  • art: I painted a picture. Not porn, for once! I’m definitely gonna do this more often; it was quicker and easier than I expected, and came out better too.

I missed working on fox flux and am glad to be doing it again, but I’ve clearly gotta balance my time across other stuff a bit better, too.

Weekly roundup: Bit of this, bit of that

Post Syndicated from Eevee original

I don’t have a cool theme or pun this week!

  • irl: I did a whole bunch of errands, aggressively slashed my tab/email count, and went hiking. Very exciting for you, I know.

  • secret thing: I taught it to animate tiles and movement, and tried this out with a conveyor belt, which instantly threw a wrench in my whole plan. Hm, well, I’ll figure it out. I wrote about the concept for $4 patrons (who will also be getting a bunch of beta builds when this is usable), if you’re interested.

  • cherry kisses: I have like four logic bugs reported by several different people, and they all feel related, but they’re also completely impossible. Like there is no way any of these could’ve happened. Except they did. And I have no goddamn idea how. I’ve spent like a day and a half wrestling with this and have barely made progress so far, but I would really like to make the game not randomly crash for folks.

    At least it autosaves, I guess.

  • art: I drew more things and I increasingly like them! I don’t know what happened, but I hit a point where I’m aggressively attacking all kinds of small details that I don’t do quite right — details that, formerly, I’d just glaze over because it was hard enough getting the general pose right. So that’s good.

    Still working on categorizing old SFW art, too. There’s just a whole lot of it.

  • fox flux: I picked this back up, but didn’t actually make tangible progress until Sunday, but I’m listing it anyway to pad this list out a bit.

  • streaming: Ash played through Doom II totally blind, while I provided commentary, which I guess doesn’t make it totally blind. Anyway we have a whole playlist of this nonsense now.

I’m juggling half a dozen things and am generally excited about all of them! It’s a nice way to feel.

Weekly roundup: Back to normal

Post Syndicated from Eevee original

As I said before, I was occupied for a bit, but now I should finally be able to get back to doing these weekly! I did manage to get a few things done over the past three weeks:

  • flora: Finished up and published a Luneko species sheet! Happy April Fool.

    That’s Anise. Anise is the April fool, and also he’s happy.

  • blog: I wrote about how the particle wipe generator works, in lurid detail! I think it’s an interesting little read, even if you have no use for the tool itself.

    I also spent a lot of time backfilling old art on my (clean) art gallery. It’s not updated quite yet; there’s a lot to go to, shockingly so, and I haven’t even made it through year one yet. Honestly, I’m kind of embarrassed by how much my output declined over time.

  • art: Speaking of, I’m back to drawing regularly, instead of just saying I wish I were drawing regularly! I think I’ve actually been drawing pretty regularly for like two weeks now. Most of it is porn. I should probably draw some not-porn, too. It’s just, you know, porn is a lot of fun to draw.

  • secret thing: I laid some groundwork for the little game engine I’m writing and haven’t really talked about yet. More on that, including maybe even a name, once I feel like I have some kinda proof of concept.

  • sudoku thing: I taught it about extra regions so now it can be used to play hyper sudoku? I don’t know why I’m even making this. It’s kind of unusable until I add undo/redo and puzzle generation, and both of those are effort. I guess I’ll see if my spite is strong enough to power me through both.

  • streaming: Ash and I played video games on the internet while high and you can watch it if you really want to for some reason.

Hey, that’s not too bad a haul, considering I didn’t even have time to work for most of the month! Got some good stuff going on, glad to see I’m up to speed again at last.

Particle wipe generator

Post Syndicated from Eevee original

Animation of solid orange transitioning to green via a swirl of little fox face shapes

🔗 Particle wipe generator on itch or hosted locally
🔗 Source code

This is a tool for making particle wipes, a type of transition whose name I made up because I don’t think they have a well-known name! They can be used in Ren’Py, RPG Maker, or anything that lets you write a shader.

Most of my games have done screen transitions with simple fades, and I wanted to try something different here, but I couldn’t find a tool to make the effect I wanted. So I wrote my own. If you’re interested, here’s how it works:

The idea

I was inspired by two things. One is Cave Story’s transitions.

The end of Cave Story's intro cutscene, which transitions to gameplay with an animated pattern of diamonds

That looks rad, right? I think it does, anyway. I wanted to do something similar myself.

At a glance, this effect looks pretty simple. The screen is sliced into a grid. A diamond shape starts expanding from the center of each cell until the cell is filled. By staggering when each cell starts, you can make an animation that seems to wipe from the bottom upwards, or from the edges inwards, or who knows what else.

Here’s a frame from the above capture, showing the grid. You can see from the blocks near the middle that it’s the same as the tile grid.

Notice that Cave Story transitions either from a scene to a solid color, or vice versa. Offhand, I don’t think the game ever transitions directly between two scenes.

My guess is that it’s manually drawing solid color on top of the tilemap until the entire screen is obscured, switching maps in the background, then reversing the progress. The various sizes of diamond might even be physical sprites on a foreground layer!

That poses a slight problem for me, because I want to be able to transition directly between scenes as well. Enter inspiration number two: Ren’Py.

Ren’Py is a visual novel engine, and it supports a ton of screen transitions. That makes sense, since visual novels generally don’t have much animated art, so most of the animation happens in transitions and sprite effects.

One such transition is a generic one called ImageDissolve, which can do a mask transition (another term I made up). It takes a grayscale mask, which tells it the order to reveal pixels. Where the mask is black, the corresponding pixels of the “after” scene are shown almost immediately; where the mask is white, those “after” pixels are the last to appear.

(I suddenly realize that Ren’Py does that backwards, with white pixels being first, but that doesn’t make sense to be since black pixels are zero.)

That’s a bit of a mouthful to describe with text, so here’s a basic example. A linear gradient from black to white will play out as a straight wipe in the same direction.

This approach can capture any kind of transition where pixels are revealed in a given order, and if I implement it with a shader (which is very easy), I can emulate the Cave Story style without being limited to a solid color! Neat!

The problem

The problem is… how do I generate the mask image? I searched around a bit and found folks who’d made transitions for use with Ren’Py, but no explanation of how they did it.

Let me think about emulating Cave Story’s effect using the mask approach, one step at a time.

Forget about the wipe effect for now and concentrate on a single cell. When the diamond is just starting to appear, it should be black. When it completely fills the cell — i.e., when it’s big enough that its edges just barely touch the cell corners — it should be white. In the middle somewhere, it should be medium gray. Imagining (or drawing) a few cases suggests a simple diamond gradient, which seems correct.

Now for the wipe effect. All it really does is stagger when the animation starts. The upwards wipe, for example, starts animating all the cells on the bottom row, waits some short amount of time, then starts animating all the cells on the next row up, and so on. An ASCII diagram of this process (for a simplified, smaller screen) might look like:

   00 |                     XXXXXXXX
   01 |                  XXXXXXXX
R  02 |               XXXXXXXX
o  03 |            XXXXXXXX
w  04 |         XXXXXXXX
   05 |      XXXXXXXX
   06 |   XXXXXXXX

My example cell above spans the full range from black to white, but if I want to stagger the cells like this, I need to squash that into a smaller range. What range, though? To get that scaling right, I need to know the total time the entire animation takes.

That’s kind of a weird question, because nothing I’m working with actually measures time! I only have numbers from 0 to 1; the amount of time is really a matter of how fast you play back the animation.

So let me approach this the other way around. The total “time” is 1, the full range of values I’m working with. My example has 8 rows. Each row starts playing after the row beneath it is ⅜ of the way through its animation; call this fraction the “delay”. There are 7 such delays, one fewer than the number of rows, because the first row doesn’t have a delay.

If the length of a single cell’s animation is \(t\) (which is actually a fraction of the length of the whole animation), then the last row starts after a total delay of \(t \times (8 – 1) \times \frac38\). Its own length is \(t\), and that should bring us to the end of the animation, so:

1 &= t \times (8 – 1) \times \frac38 + t \\
&= t \times (7 \times \frac38 + 1) \\
&= t \times \frac{29}{8} \\
\Rightarrow t &= \frac{8}{29} \approx 0.276 \\

And indeed, if you count characters in the diagram, each bar is 8 long out of a total width of 29. Neat! All I have to do is make the bottom cells range from 0 to 0.276, the next row up range from 0.103 to 0.379 (the same size range, but moved up by \(\frac{8}{29} \times \frac38 = \frac{3}{29}\)), and so on.

Easy. Blog post done.


I wanted to use hearts. And hearts create two new issues.

The first is that I don’t know how big a heart would have to grow to cover the entire cell. For diamonds, that was easy: they’re symmetrical in the same way as squares, so it’s obvious that they just need to be big enough to touch the corners. But how big does a heart have to be to fit a square entirely inside it? Do I gauge it by hand in an image editor, or what?

The real problem there is that a heart is, presumably, a bitmap rather than a simple shape with properties I can examine mathematically. And even if it were a shape, the math would get pretty ugly pretty quickly.

But the second problem is worse. Hearts aren’t vertically symmetrical, which means a neighboring heart might poke into a cell and start covering pixels that the native heart hasn’t covered yet.

A 3×3 grid of hearts expanding out of their cells, showing that the top of a heart can grow into the cell above.

This complicates things considerably. If I took the naïve approach of gluing together a bunch of independent cells, then the top of each heart would reach the top of its cell and flatten out into a hard border! Sounds ugly, especially since the grid isn’t really supposed to be visible in the animation. (Technically this could happen with diamonds too, if the delay were high enough, but their symmetry makes it much harder to notice.)

Now, I could fudge my way through both of these problems with sufficient abuse of an imaging library. Draw a very tiny black heart, then draw a slightly bigger almost-black heart, and keep expanding until every pixel has a color, then either scale the colors or go back and do it again knowing the correct range.

But that’s not a very satisfying solution, and it’s not very precise — which is important when I only have 256 values to work with. I can do better!

Doing better

The approach I used for diamonds above is fairly promising. It’s most of the way to a blueprint for figuring out exactly what shade each pixel of the mask should be, independently of any other pixel. The position within a cell tells me how far along in the cell’s animation the pixel is (center black, corners white, everything else somewhere in the middle), and the delay tells me how to scale that to fit correctly in the full animation.

Those seem like reasonable steps. All I have to do is fix them to work with an arbitrary “particle” shape. Somehow.

Step 1: the stamp

Forgetting about the overall animation worked before, so I’ll do it again and concentrate on a single prototype cell. That cell will be repeated (with some adjustment) all over the final mask, so I call it a stamp.

I already know in advance that a single cell doesn’t need to scale from 0 to 1, since I’ll be adjusting it later anyway, so that frees me up to use any arbitrary quantity — as long as it’s scaled by some consistent factor I can eliminate later. A little thinking suggests that what I really want to know is: given a pixel \((x, y)\) within a cell, how big does the heart particle have to grow to hit that pixel? I can express that as a fraction of the particle’s original size (since it should grow proportionally), and then worry about scaling it down later.

The first thing I want to do is change my coordinate system. Consider: for a 10×10 cell, the center is at the point (5, 5), which neighbors pixels (4, 4) and (5, 5). But that would mean the heart would touch the pixel at (5, 5) immediately, whereas it would need to cross a whole pixel to reach (4, 4), even though both pixels touch the center!

Close zoom of the problem described above, with the top-left corners of pixels in red, and their centers in blue

Pixel coordinates refer to the top left corners of the pixels, indicated in red above. The center is a point, not a pixel, and it’s clearly much closer to one pixel coordinate than the other. The fix is to use the centers of pixels, indicated in blue, which are the same distance from where the heart starts. Phew!

(If you don’t do this, you’ll get a very noticeable diagonal gash where the particle touched lower-right pixels earlier than upper-left ones. Guess how I found that out!)

While I’m at it, pixel coordinates are relative to the upper-left corner of the cell, but the most interesting point here is the center. So let’s make them relative to that, too. That means (4, 4) and (5, 5) should really be (-½, -½) and (½, ½), or more generally: given a center at \((c_x, c_y)\), the point I’m actually interested in is \((x + \frac{1}{2} – c_x, y + \frac{1}{2} – c_y)\). Call this, I dunno, \((d_x, d_y)\).

Back to the actual problem, which is: how big does the particle need to grow to hit this point?

Like I said before, I could try scaling the particle up bit by bit (maybe binary search?) until it touches the point, but that still feels goofy and imprecise.

You know, it sucks that the particle is a two-dimensional shape. It would be swell if I could eliminate a dimension here, or something.

And here I borrow a couple techniques from collision detection. Scaling the particle up is equivalent to scaling the entire cell down. If I scaled the cell down towards the origin, the point would trace a straight line.

Animation of a grid scaling down towards the origin, showing that a point traces a straight line

This is very helpful. It means I can solve this problem with a raycast: fire a straight ray into the particle, towards its center, and check each pixel it hits until I find an opaque one. That’ll give me a perfect answer!

But where does the ray start? I have a point in the grid, but not a point on the particle. So the first question is: if the particle scaled up just enough that the edge of the particle image touched the point, where on the particle would that contact be?

The same point as before, but with the particle grown to barely touch it

Call the particle dimensions \(p_w\) by \(p_h\). (My heart is contained within a square, but that isn’t strictly necessary.) In order to reach x-coordinate \(d_x\), the particle would have to be twice as wide as the distance from the y-axis to that point — because it’s centered! — which is \(\left|2 d_x\right|\) pixels wide. Its scale, relative to its original size, would thus be \(\frac{\left|2 d_x\right|}{p_w}\). The scale for touching the y-coordinate would be computed the same way. To actually touch the point, the particle has to reach whichever coordinate is further away, so its scale must be:

s = \max\left(\frac{\left|2 d_x\right|}{p_w}, \frac{\left|2 d_y\right|}{p_h}\right)

A special case crops up here: for a cell with an odd width and height, the center pixel is exactly aligned with the origin, and the scale computes to zero. I’m doing some division in a moment, so that’s very bad — but the center pixel is effectively touched immediately, so I can say the final answer for this pixel is 0 and skip the rest of this anyway.

Now for the fun part! When the expanding particle hits the point of interest, it makes contact at some point on the original particle image. If the necessary scale is \(s\), the contact point is the center of the particle, offset by \(\left(\frac{d_x}{s}, \frac{d_y}{s}\right)\).

And now I raycast from that point to the center of the particle and check every pixel that ray crosses, using a modified Bresenham’s algorithm — originally intended for drawing pixel-perfect lines, but perfectly suited for casting a ray through a grid as well. (Conveniently, I’d already implemented this sort of raycast for collision detection for this very same game! Then I ended up not using it, hm.)

When I find an opaque-ish pixel (alpha of 0.5 or greater), I compute its distance from the center, divide by the distance from the contact point to the center — that tells me how much bigger the particle has to grow for the opaque-ish pixel I found to actually touch the point.

Multiply that ratio by the \(s\) I found earlier, and the result is exactly what I was looking for: the scale of the particle when it touches the point!

Now, raycasting for every pixel in the stamp — a thousand times even for a dinky cell size of 32×32 — is not exactly speedy. But it’s not unbearably slow, either. And this is something that’s generated once and played back a bunch of times, so why not spend a little CPU time upfront making it as high-quality as I can manage?

Anyway, that’s the hard part done! Now I can put the mask together.

Phase 2: the mask

With the stamp generated, I also know how big the particle has to grow for the entire cell to be covered: it’s just the highest scale in the stamp. For a simple full-screen effect, all I’d have to do at this point is scale the stamp values into the range [0, 1] and copy them to every cell in the grid.

But that’s boring; I wanted a wipe, which requires a couple more twiddles.

The wipe is essentially a second animation that controls when each cell’s individual animation starts. Above I considered a row-by-row wipe; for Cherry Kisses I ended up with a column-by-column wipe; Cave Story also has an “inwards” wipe. All of these can be generalized as numbered steps in a grid:

By row      By column   Inwards
77777777    76543210    01233210
66666666    76543210    12344321
55555555    76543210    23455432
44444444    76543210    34566543
33333333    76543210    34566543
22222222    76543210    23455432
11111111    76543210    12344321
00000000    76543210    01233210

The math is basically already done; I did it above. Given the number of steps \(n\) and the delay \(d\) (a fraction of the cell animation time), I can find the length of a cell animation \(t\) as follows:

1 &= t \times (n – 1) \times d + t \\
&= t \times ((n – 1) \times d + 1) \\
\Rightarrow t &= \frac{1}{n d – d + 1}

The process for generating the whole mask is thus:

  1. Iterate over each pixel of the mask.
  2. Figure out what cell it’s in, and the step for that cell.
  3. Find the corresponding value in the stamp, scale it to the size of a cell animation, and add in the delay.
  4. Write that to the mask.

Once every pixel is done, the mask is complete!

Except… this didn’t handle the overlap issue. No problem, though; that’s surprisingly simple to fix.

First, expand the stamp to the size of a 3×3 block of cells. The maximum scale for a stamp should only be taken from the central cell; the others are for the following process.

Then, when reading a pixel’s stamp in step 3 above, read it from the central cell — and also from the neighboring cells. In those neighbors, I read from the stamp cell on the opposite side, in order to know how long it would take for the heart to grow out of that cell and into this one.

(Diagonal neighbors aren’t shown here, but you get the idea.)

Since different cells may have different start times, I may need to add/subtract some extra delay from the neighbors’ values. Then I take the smallest of all these samples to figure out the earliest time that any heart — either in this cell, or one of its neighbors — hits the pixel.

And hey, presto, we’re done! Here’s a (somewhat laggy) recording I took of the very first time I got this working for Cherry Kisses:

It ended up a little nicer-looking than that, of course. (Feel free to play the game to see it in action?) And if you’re curious, here’s the mask from the final game:


There’s one teeny tiny problem still lingering in this approach. I assume that the whole animation ends when the last cell animation ends, but because of cell overlap, it might actually end earlier. And indeed, when I went back to check the Cherry Kisses mask, I found that it ends early — the brightest color in it is #e2e2e2. Oops. So much for that ludicrous accuracy!

That’s still fixable by taking overlap into account when finding the maximum value in the stamp, but I haven’t done it yet, and it’s a bit more complicated if the grid pattern has adjacent cells that are more than 1 step apart. (Those cases can also lead to particles mashing against the cell edge too early, which could be fixed by using a 5×5 or larger stamp…)

That’s it

Yep. The particle generator is just this logic with some knobs bolted on. It has a couple extra features, like a “halo” that highlights the transition point, and using all three color channels for extra precision, but it’s all built on the same basic idea.

There’s a lot of room for experimentation and variety here, and I’ve probably only scratched the surface. This is only a tiny subset of what can be done with a transition mask, too — it needn’t rely on a grid at all! See what you can come up with.

Oh, and here’s the exact shader I used in Cherry Kisses. It’s for LÖVE, so it has a couple non-standard #defines and globals, but you get the idea. The “ramp” is just a tolerance that adds a soft edge around the transition.

extern Image mask;
extern float t;
extern float ramp;

vec4 effect(vec4 color, Image texture, vec2 tex_coords, vec2 screen_coords) {
    vec4 pixel = Texel(texture, tex_coords) * color;
    float discriminator = Texel(mask, screen_coords / love_ScreenSize.xy).r;
    float alpha = clamp((t - discriminator) / ramp + 0.5, 0.0, 1.0);
    pixel.a *= alpha;
    return pixel;

Happy transitioning!

Weekly roundup: Cherry Kisses

Post Syndicated from Eevee original

Hello hello! I finally finished that game I was working on, so now I might actually be back to some sort of normal dev schedule.

Except I’m gonna be kinda occupied for the next week or so. So.

  • cherry kisses: Hey hey I finished making Cherry Kisses, which is super duper NSFW! It’s probably the most well-designed and polished thing I/we have released, though. Whoops! I gotta stop accidentally making sex games.

    There’s some little niceties in there. Maybe I should, like, write about it sometime.

    Also attempted to get it to work on Android, which… is… non-trivial, despite LÖVE being “able” to target Android.

  • particle wipe generator: Cherry Kisses includes a cool heart transition between scenes, which took a surprising amount of effort to create, so I packaged up the code and put some dials and knobs on it. Now you can use the particle wipe generator to make your own particley transitions! Also hosted locally.

    Maybe I should, like, write about how this works sometime. Can’t wait for someone to tell me how I could’ve done it a thousand times more easily.

  • irl: We did some spring cleaning! Very exciting for anyone who doesn’t live here, I know. Our bedroom is no longer half-full of half-unpacked boxes, which is pretty nice.

  • sudoku: I occasionally waste time with a nice sudoku app, which has a free ad-supported version and a paid version. It has a sequel now, which is even better, but which only comes free with ads. I am incensed by this so I started writing my own JS player out of spite. Unclear whether my spite will last long enough to produce something usable.

Pretty happy to be back to makin’ things! I love that I could spin off some throwaway helper code into a little gamedev tool, and I’d definitely like to do more of that sort of thing in the future.

Weekly roundup: Strawberry Jam 3

Post Syndicated from Eevee original

Another double feature. Surprise, basically all I’ve been doing is working on a jam game. Should be back to normal once I get this out the door.

  • art: I doodled, like, once, but then was lost in gamedev all day every day.

  • cerise: I finally, like, planned out the progression of the game, and sat down to write it. Prose is harder for me than you’d think, and there’ve been a number of interruptions over the past month, so it’s taking a little while. I’m nearly done and am pretty happy with what I have so far, though.

    Actually, reading my notes here, I’m amazed how much of the game was done in only the last two weeks of February! I didn’t even have the passage of time working yet, and that’s the most fundamental part of the game.

    I did also cobble together a thing for generating particle wipes, which I think is pretty cool; I’ll probably write about it and release a web version in the near future.

Should be done in a day or two, but I’ve been saying that for a week, so who knows.

Weekly roundup: Off to a good start

Post Syndicated from Eevee original

I already missed a week! But I was mostly working on a jam game so that’s not too surprising.

  • art: Trying to keep up a semi-regular drawing schedule, with mixed success. I’m still working on my character lineup painting, though I’ve hit a few awkward spots that are proving difficult to fix. Sketched some stuff a few times. Drew Lexy with a sword.

  • music: I made part of a song, which was originally going to be for the Strawberry Jam game, and then I forgot about it, whoops. And now I will very much not have time to do music. It was coming out pretty okay, though, which is encouraging!

  • alice’s day off: Hey, remember this? Our wildly explicit VN for last year’s Strawberry Jam, which we intended to finish a few months later, and then, didn’t? Still working on it! I wrote out rough drafts for a couple more routes. This’ll probably become my main priority after this month, so I can actually get another thing done and off my plate.

  • cerise: Spent a lot of time on engine work (some of it not even necessary) and probably not enough on the game itself, and now I only have ten days left oops. Parallax layers are now actors, Tiled support is cleaned up a lot, sprites support four angles (or really, an arbitrary number of angles), physics were updated for top-down mode, and I finally implemented raycasting for realsies. Cleaned up dialogue code a lot, again, and put together basic dialogue UI.

    Fixing raycasting was a fun little problem, and free top-down movement offered an interesting little vector puzzle. Maybe I’ll write about those sometime.

    I also spent a little time porting some of my other LÖVE games to use my updated engine code, which also means they should run on LÖVE 11. I’m not finished yet, but once the month is over, I’d like to get updated releases out. It’ll only really matter for Linux users, since the Windows and Mac downloads include their own copy of the LÖVE runtime, but I’m a Linux user, so.

I better, uh, go get to work on this game.

Weekly roundup: Spectacular return

Post Syndicated from Eevee original

Hey! Miss these? Great! I’m doing them again and no one can stop me.

  • art: I spent half the week rendering. Something, something, joke about rendering and EEVEE. No but really, I found out I’m kind of okay at this and set out to paint a whole lineup of all my Floraverse characters, which turned out to be really hard and time-consuming, but anyway here’s Lexy and slightly weirder Lexy and Cerise. Only, like, seven more to go.

    Hm. If only I’d constructed some sort of art website to put this kind of work on. If… only.

  • fox flux: This game keeps plodding along. I added a little blowing-a-kiss mechanic a while ago, and I finally gave it a real animation, which I then spruced up a bit more after recording that GIF. Also been cleaning up a big mess of half-finished features I left for myself, including particle effects for— well, that would spoil it!

  • strawberry jam: I’m running Strawberry Jam 3, the low-pressure month-long horny game jam! I haven’t gotten very far on my game yet, but most of the work is going to be upfront planning (I hope), so that’s not too worrisome. I just started writing code today, and hopefully will have some kinda rough skeleton done by the 25% point on Friday.

    This is gonna be most of my month! What an exciting topic to come back to.

More coming down the pipe; I’m accelerating all the time.