j kongerblog
mountains and websites

blog

ants devlog 3

this is part of a series. see the previous post here


let’s take the issue head on: my attempt to write this as a pseudo-tutorial has failed. i find the writing style draining, boring, forced, etc etc. worse, the more i put it off, the further i get from when i wrote the first part of my little ants simulation, so there ain’t nothing there (or at least there’s less and less there), to build on, it becomes an exercise in bland uninteresting recollection, i would prefer not to.

thus a new beginning, more honest to what i’m actually doing when i write these: let’s look at my furthest draft of the code and reconstruct together what i think my ideas were

the code itself

we’re up to some 200 lines now, so lets put these into little tabs. explanation are after our little guy here, so scroll on by for more

0: basic functions
function _init() 
   -- allow mouse :)
   poke(0x5f2d, 1)

   cur_init()
   ants_init()
   food_init()
end

function _update60()
   cur_update()
   local click=stat(34)
   --left click
   if(1==click) then
      sfx(0,-1,4)
      ants_add(cur_x,cur_y)
   end
   --right click
   if(2==click) then
      food_add(cur_x,cur_y)
   end
   
   food_update()
   ants_update()
end

function _draw()
   cls(4)
   food_draw()
   ants_draw()
   --ants_count()
   cur_draw()
end
1: cursor
function cur_init()
   cur_spr=1
   cur_x=60
   cur_y=60
end

function cur_draw()
   spr(cur_spr,cur_x,cur_y)
end

function cur_update()
   --mouse loc
   cur_x=stat(32)-1
   cur_y=stat(33)-1
end
2: ants

function ants_init()
   ants={}
end

function ants_add(x,y)
   ants[#ants+1]={x=x,y=y,age=0}
end

function ants_loop(func)
   loop_pixels(ants,func)
end

function ants_draw()
   ants_loop(
      function(ant)
         pset(ant.x,ant.y,0)
      end
   )
end

function ants_move()
   ants_loop(ant_move)
end

function ant_move(ant)
   local movement=rnd(100)
   
   if(95<movement) then
      ant.x=ant.x+1
   elseif(90<movement) then
      ant.y=ant.y+1
   elseif(85<movement) then
      ant.x=ant.x-1
   elseif(80<movement) then
      ant.y=ant.y-1
   end
   
   ant.x=loop_screen(ant.x)
   ant.y=loop_screen(ant.y)
end

function ants_age()
   ants_loop(function(ant)
         -- basic rand change to die
         if(ant) then
			local dead=
               flr(rnd(2000-ant.age))
			if(0==dead) then
               del(ants,ant)
			else
               ant.age = ant.age+1
			end
         end
   end)
end

function ants_count()
   local text="ants: " .. #ants
   print(text,2,120,6)
end

function ants_eat()
   -- we actually loop the food
   -- to easy unset it
   food_loop(function(food)
         if(food) then
			local eat=pget(food.x,food.y)
			if(eat==0) -- has ant on it
			then
               --make ant live longer
               foreach(ants, function(ant)
                          if(ant.x==food.x and 
                             ant.y==food.y) then
                             ant.age=ant.age-100
                          end
               end)
               --remove the food
               del(foods,food)
               sfx(1)
			end
         end
   end)
end

function ants_update()
   ants_move()
   ants_eat()
   ants_age()
end
3: loop helpers
function loop_screen(pos)
   if(128<pos) return 0
   if(0>pos) return 128

   return pos
   end

function loop_pixels(arr,func)
   for i=1,#arr do
      func(arr[i])
   end
end
4: food
function food_init()
   f_sprite={2,3}
   foods={}
   food_can_add=0
end

function food_add(c_x,c_y)
   --only add if not delayed
   if(0<=food_can_add) return
   
   sfx(2)
   --reset delay
   food_can_add=25
   local s_offset=
      rnd(f_sprite) * 8
   
   -- loop the sprite to add
   -- pixels
   for x=0,7 do
      for y=0,7 do
         local pix=sget(x+s_offset,y)
         if(0!=pix) then
            foods[#foods+1]=
               {x=c_x+x,y=c_y+y,col=pix}
         end
      end
   end
end

function food_draw()
   food_loop(
      function(food)
         pset(food.x,food.y,food.col)
      end
   )
end

function food_loop(func)
   loop_pixels(foods,func)
end

function food_update()
   food_can_add=food_can_add-1
end

the explanations

i like accordions. let’s do that again:

0: basic functions

this one's mostly straightforward: call the init, update, and draw functions of further tabs. in init, we poke to enable mouse use, in update we handle clicks, and in draw we clear the screen.

1: cursor

another simple one. in `init`, we set our cursor sprite, in `update` we pull in the x and y position of our cursor with inexplicable functions even _i_ dont understand (minus 1, for some sweet visual alignment tricks: it makes sure we dont hide our single pixel ants), and draw draws a sprite to the screen at that position. i think its neat. its simple. its a software sort of thing

2: ants

now we're doing something! we've got a lot here. if you've noticed, i have a tendency to order functions in a sort of least-to-most order, aka 'reverse', so let's describe them in reverse also, starting at the bottom of our code:

ants_update

the simple one: we call all the functions we write above. our ants will move, eat, then age and possibly die

ants_eat

our first hard one, in part reliable on some functions in our food tab (so read ahead!). in short, we have an array of pixels of ‘food’ as well as their x and y positions. we then read the screen data of the foods x and y coords: if its palette is 0, which is an ant, we 1) make the ant live longer by subtracting from its age value and 2) delete the food from the food array (see that tab bb). we also play a sound effect

ants_count

debug func: prints the count of ants to the screen

ants_age

we loop through our ants via the to-be-described ants_loop function and try to kill them via rng. essentially: the closer their age gets to 2000, the higher the chance they die. if they live, we age them by one, increasing their chance to die later

ants_move and ant_move

loop through and move our ants. this parts lame as hell right now, just randomizing the direction and checking to loop the screen. this’ll be a HUGE change point in our shared future

ants_draw

loop our ants and set their pixels on the screen. simple as hell

ants_loop

and you thought you might learn? no! we call a loop pixels functions on our ant, described elsewhere!

ants_add and ants_init

simple: we add an ant object at x and y in ants_add, we create a global ants array in init. this is real simple stuff, unfortunately

3: loop helpers

aint the most complicated things so simple also? `loop_screen` makes sure our position is on the 128x128 screen, `loop_pixels` takes in an array and runs a function on every member of it

why is these together, if so different? i dont’ know. i wrote this months ago

4: food

our last little bit of complexity, then we're through. You've got this, reader. I've got this, writer, too.

in init, we set up three variables. f_sprite holds a list of sprites that we can produce as food, foods holds all the food pixels we’ve set on screen (the same way we’ve set pixels for ants), and food_can_add helps us set a little delay so that we can’t just paint food across our screen

food_add adds food to the x+y off the cursor: first we made sure our food can be added by checking if our food_can_add is zero (or less---so we don’t have to worry about keeping the addable time to zero); if we’re good, we play a little sound, reset our food delay to 25 frames, then pick a sprite at random from our f_sprite variable set above. with that in place, we loop through the pixels of our food sprite and add them to our food array at the cursor location

food_draw loops these pixels to add them to the screen; food_loop makes looping these pixels easier

finally, on food_update, we count our food adding counter down one tick per frame

so: that’s a lot. its also a small bit messy, but oh well. ants are insects who live in dirt, we might as well attempt their lifestyles if we’d like to simulate

next up, back in the code for this, we’ll try to add an ability for our ants to scent out food near them and follow, as well as follow each others scents. let’s give it a go

apologies to everyone for occasionally misspelling it as ‘aunts’. i will not go back and fix this

flat game

finally uploaded this game jam game from a while ago: j.konger.online/flat-game/. it’s finally not a joke one. i did the writing mostly, which is a found/erasure poem from an old religious text

here’s the poem text:

  i vow that my body shine bright in the infinte night, /
for all beings are like me,

  i vow that my body is crystal, the same as compassion, /
dreams on track,

  i vow i shall grant all beings my exhaustible wisdom, /
reviling guilt,

  i vow to lead those astray /
let them be corrected,

  i vow sentience, relapse, violation /
sincerity's a tenet of regret,

  i vow the physically sick are in good / health,
all who pay homage,

  i vow pain as i vow povery:
the helpless will be helped,

  i vow suffering and torture, transformation /
into men,

  i vow free beings, evil thought, control /
incultate them in a righteous honour,

  i vow to save prisoners of disaster /
my supreme power blesses the freed,

  i vow those who suffer from starvatio /n:
hear my name,

  i vow suffer, povery, mosquitos /
wasps by day and night come by my name,

Scooby Doo (weekly flash 2025-23)

In an early draft the story became a Scooby-Doo fan fiction. This was never intended or by design, but rather a convenience of the familiar: the story needed several characters at once and the setting, a gothic castle almost dangling off the edge a narrow cliff, seemed to require a counterpoint of innocence, five young friends (one so near-mythically child-like any competent reader would understand the symbol he was) against the endless night, colorful clothing as though to pollute the corridors and halls, which to this point had only been blue and gold, in each color’s darkest variation, and silent save for arbitrary whispering or creaks. Why were the children there? Did it even matter? They had captured their prey as they always did, their target, clad in the rusted shell of a now-black armor, fallen over down onto the ground. The children surrounded the knight as though to prevent its escape, though it had given up the ghost. Perhaps for the first time ever, their target had died. Purple smoke seeped out of perforations in its helmet, around where the body beneath might have had its eyes, and it pooled or perhaps clouded above the children, blinking now and then as it started to swirl, as though to imitate a hurricane. —Ru-roh, said the most innocent child.

I was living that year in Miami, which I’m assured was nice. It would be a lie to say I stayed indoor most of the time, afraid of heat and interstates and people, but lies are sometimes better than the truth, the way a photograph is better than your vision, as it lasts beyond the moment, and details can be zoomed it. I read the draft on a visit to a friend.

—It’s like a dream, he said, in that there seems to be no ending. No beginning either, I guess, it’s just you’re there forever experiencing, the gang around the knight as he bleeds out.

—When you were writing it? I asked.

—No, he said.

—To read it?

He thought a moment, or stalled, either which manifested as staring at his coffee, unpeeling layers from its paper sleeve the way that I, in nervous moments, unpeel the skin around my thumb.

—The entirety of the image, he said, pressing his most recent peel back. Everything, I think, exists already, so I was just marking it down.

In the story next the cloud was forming words. It was unclear (from clumsy detail work) if it spoke or transmitted thoughts, but the words were at least described as being purple, the way a day might be called warm or cold. It was praying to the children, describing death in abstract detail. It begged forgiveness for the way it manuevered life.

—No, Fred said at once. We cannot offer absolution.

—Yeah man, Shaggy said. Like, we’re no different from you.

—I can only assume you’re attempting to use us, Velma said.

—Look to yourself, Daphne advised.

—What are you even trying to say with this? I asked my friend.

—Some things are images, he said.

It made no sense. I couldn’t see his story as anything more than a joke, at best, a failure or embarrassment at worst. Nothing occurred. Events just happened. It was one more moment among many, none the same.

no doubt the first man that ever murdered an ox was regarded a murderer (2025-22 weekly post)

weekly flash? yes; and revisions, translations, etc

a family visit; little project time; but reading, still, yes!

i only finished the rehearsal this week

confession: my guilty pleasure is watching productivity videos and judging the hosts: buddy, why don’t we just LIVE. i started with a new therapist this week for this and several other issues. how will it affect this unread posts?

goal: be productive in order to be more productive; use the extra time to spread the productivity word; its a form of jesus

An Analysis (weekly flash 2025-22)

Regarding self-immolation, I am terribly afraid. This makes a bit of sense on its face, of course: fire’s already frighting before one even considers the flesh, but once the fire and flesh have touched the result is terror itself: the melting and the charring and pain as well, or perhaps more shockingly the skeleton, which seems (once the fire has reached a certain cohesion) to take over for the musculature as the body’s defining shape. This is nothing more than the fear of fire, of course: a fear as common as worker ants or potholes, as meaningless (almost) as natural fact. Our focus then should be on the words themselves: immolation and its prefix self.

Immolation, as well, is perhaps self-evident: a fear of flame to its completion, as it were: sensation to the point sensation ends. Self is the part that’s strange, as self must muddle motivations. One doesn’t burst to flame as by mistake, as in spontaneous combustion, but rather methodically engages at first in a simple act of purchase, in order to gain such fluid as gasoline, perhaps as well (depending on personal habit) a lighter, the first of several soaking rags, a video camera, microphone equipment, an inconspicuous car, a sufficient map. One does not transform oneself by accident either but rather studies considered patterns of security cameras, memorizes guard schedules, routes, calculates moments long enough a body, once burnt, cannot be doused back to partial silencing recovery by its bold statement’s first audience, the simple or instrumental protectors of property and the sort at the scene of the crime, security types, idiot viewers, certain the greatest act a man might partake in is to recover another’s life, as death by definition (the fool believes) is always meaningless, or if it contains a meaning it’s only a demerit of a sort, a failure maintain duty, not a transmission, one much for meaningful than words, so strong it defies and redefines reality: I at least take no part. The act must be intentional. I, the immolatee, must control it.

j, my counselor tells me, don’t you find the meaning of your terrors apparent? Recall previous discussions of your time spent underground. Not many people have dealt with the literal experience of being held against their will, tied in an acrylic box beneath the earth, dirt and worms and falling rain so tantalizing visible overtop one’s head, etc. The body finds a stasis, you know, with habit. Perhaps we can presume this one result of a sudden resumption of free will, a renewed sort of terror in what you’re now able to do. What if control’s not so different from its lack? Are you understanding?

I close my eyes, we’re only on the phone: she doesn’t notice. These thoughts (even my fears) are just ideas. I am material. I try for the moment to focus on my breath. No matter what I do, the breaths go on.