The math behind the game is atan2 which I use to get the angle from a thing to another thing:

function ato(from,to)
  return atan2(
    to.x-from.x,
    to.y-from.y
  )
end

And then when you give that angle to cos for the x axis and sin for the y axis you get (x,y) coords that can be multiplied by the number of pixels you want to “move” in that direction. So this function assumes a table like {x,y,a,s} and returns new a new x,y multiplied by s for “speed”…

function amove(●,s)
  s=s or ●.s
  return ●.x+cos(●.a)*s,
    ●.y+sin(●.a)*s
end

I use both those together like this to move the worms each frame. (This symbol: ∧ looks more like a worm in the Pico-8 font. If you didn’t notice I like the emoji for variables 😋)

forin all(∧s) do
  ∧.a=ato(∧,웃)
  ∧.x,∧.y=amove(∧)
end

The astitue reader may have noticed amove allows one to supply their own s instead of the table’s s… this is useful when you want to calculate things along something like a line, I mean the length of a worm. For example if we put everything together then we get this loop that, after a bullet () moves, checks every part of a worm (for ∧t=0,∧.l do where ∧.l is worm length and ∧t is each “tail” pixel) and if they collided deletes both and plays a sound effect. amove is given each ∧t but it’s not actually used to move the worm, just to reconstruct it’s body for collision detection.

forin all(∧s) do
    for ∧t=0,∧.l do
      ∧x,∧y=amove(∧,∧t)
      if flr(✽.x)==flr(∧x)
        and flr(✽.y)==flr(∧y)
      then
        del(bullets,✽)
        del(∧s,∧)
      if #∧s==0 then
        sfx(2)
      else
        sfx(1)
      end
    end    
  end
end