Ludum Dare 51 Postmortem

Finally getting around to writing about my game for Ludum Dare 51... This was an interesting one because I had even less time then usual! Because of a church event I missed basically the first evening. In spite of this, I'm proud of what I was able to accomplish. I try really hard to put out something complete & polished, and I think I was able to do that on an extra tight time budget.

As usual, I used tic80 and Fennel lang. In my GMTK 2022 Postmortem I talked about how I wanted to be more conscious about challenging myself with learning something new. For this jam I decided to force myself to use a function in tic80 I'd never touched, ttri. Short for "textured triangle", this bad boys got a bajillion parameters but the basic idea is that it draws a triangle filled with an image/texture either from sprite or map memory. I'n my game I used this to simulate perfectly the spread of freshly poured pancake batter on a griddle. I'll try my best to explain the effect.

1. Drawing using ttri

To draw the actual pancake we'll use 2 textured triangles sharing 2 coordinates to turn them into a plane. This let us sample a square sprite and deform it however we want. Here's a (simplified from the actual game) function that draws an image at a position with a texture.

;; draw 2 textured triangles using 4 coords to build out a plane with a full texture
;; - pos: the center x,y position of the pancake, along with a z "height"
;; - radius: radius of the pancake
;; - uv-box: [x y width height] box to pull texture from in map memory
(fn ttri-pancake [pos radius uv-box]
  (let [[s1x s1y] (. spread 1)
        [s2x s2y] (. spread 2)
        [s3x s3y] (. spread 3)
        [s4x s4y] (. spread 4)

        x1 (- pos.x radius)
        y1 (+ pos.z (- pos.y radius))
        x2 (+ pos.x radius)
        y2 (+ pos.z (- pos.y radius))
        x3 (- pos.x radius)
        y3 (+ pos.z (+ pos.y radius))
        x4 (+ pos.x radius)
        y4 (+ pos.z (+ pos.y radius))

        [ux uy uw uh] uv-box
        u1 ux v1 uy
        u2 (+ ux uw) v2 uy
        u3 ux v3 (+ uy uh)
        u4 (+ ux uw) v4 (+ uy uh)]

    (ttri x1 y1 x2 y2 x3 y3
          u1 v1 u2 v2 u3 v3
          true 0)
    (ttri x2 y2 x3 y3 x4 y4
          u2 v2 u3 v3 u4 v4
          true 0)))

2. Spreading things out

With full control of the 4 coordinates in the texture plane, we can create a "spread" effect where right when the batter is poured it kind of oozes out and grows semi randomly. The idea here is to create "spread-rates" vectors for each coordinate on pancake creation. Then each tic we apply that spread rate and then reduce it for the next iteration (so it eventually stops). Here's a function that does that.

(fn create-pancake-data []
  {:spread-rates [[(random 0 0.5) (random 0 0.5)]
                  [(random 0 0.5) (random 0 0.5)]
                  [(random 0 0.5) (random 0 0.5)]
                  [(random 0 0.5) (random 0 0.5)]]
   :spread [[0 0] [0 0] [0 0] [0 0]]})


(fn pancake-update [pancake]
  (each [i [srx sry] (ipairs pancake.spread-rates)]


    ;; apply spread rate to coordinates spread offset
    (let [[sx sy] (. pancake.spread i)]
      (tset pancake.spread i [(+ sx srx) (+ sy sry)]))

    ;; descrease spread rate so it eventually stops
    (tset pancake.spread-rates i [(* srx 0.90) (* sry 0.9)])))

we can then use this new data to expand the "ttri-pancake" function

;; New param!
;; - spread: the list of spread offsets
(fn pancake-tri [pos radius spread uv-box spread]
  (let [
        ;; Deconstruct the spead offsets
        [s1x s1y] (. spread 1)
        [s2x s2y] (. spread 2)
        [s3x s3y] (. spread 3)
        [s4x s4y] (. spread 4)

        ;; to use them here
        x1 (- pos.x radius s1x)
        y1 (+ pos.z (- pos.y radius s1y))
        x2 (+ pos.x radius s2x)
        y2 (+ pos.z (- pos.y radius s2y))
        x3 (- pos.x radius s3x)
        y3 (+ pos.z (+ pos.y radius s3y))
        x4 (+ pos.x radius s4x)
        y4 (+ pos.z (+ pos.y radius s4y))

        [ux uy uw uh] uv-box
        u1 ux v1 uy
        u2 (+ ux uw) v2 uy
        u3 ux v3 (+ uy uh)
        u4 (+ ux uw) v4 (+ uy uh)]

    (ttri x1 y1 x2 y2 x3 y3
          u1 v1 u2 v2 u3 v3
          true 0)
    (ttri x2 y2 x3 y3 x4 y4
          u2 v2 u3 v3 u4 v4
          true 0)))

I had a lot of fun creating this effect, I hope my explanation of how it works is was at least a little helpful. I feel like I'm just scratching the surface of what you can do with the textured triangles function. I'm excited to come up with other fun effects with it!

You can play my Ludum Dare 51 game, Pancake simulator, HERE.