-- speed pool 1k (for #pico1k jam)
-- by paul nicholas

--
-- (function shorthands)
--
c=circfill
s=stat

poke(24365,1)  -- enable dev mode to use mouse input
pal(4,0,1)     -- replace display colour of 4 (brown) with 0 (black)
               -- (explaination futher below...)
--
-- constants/variables
--
l={} -- list of ball objects
h=0  -- build rack count horizontally
y=0  -- build rack y offset 
v=5  -- build rack count vertically

for i=1,16 do -- build the starting rack for the balls
 q=25+h*6     -- x-pos for next ball
 w=y+48       -- y-pos for next ball
 e=i==11 and 6 or (i%2)*3 -- colour for next ball (alternate red/yellow, or black pos)
 if(i>15)q=99w=64e=9 -- if we're on last ball, make it white and pos accordingly
 b=add(l,{x=q,y=w,c=e,a=0,s=0,v=0,b=0}) -- add current ball to the list (table)
 y+=7  -- onto next rack ball
 v-=1  -- 
 if(v<1)h+=1v=5-h y=h*4   -- move to next "column" of rack positions
end

_set_fps(60)   -- used to achieve 60fps without using _update60()
               -- as i want to stop execution when last ball potted
               -- (took more chars using _update60() and stop() )

while(#l>1) do -- while still balls to pot, keep game loop running
 m={}    -- used to store colliding pairs of balls to resolve collisions
 u=s(32) -- mouse x-pos
 i=s(33) -- mouse y-pos
 cls()
 ?"\^pspeed pool \fd"..t() -- print title + time using p8scii pinball-style text ("\^p")
 rectfill(0,25,127,102,3)  -- draw the pool table surface

 for i=0,5 do  -- draw the pockets - rest of black circles are hidden against black bg
  x=i*63       -- (i'm sure there's a more efficient way than this, but it did the trick)
  c(x,26,5,0)
  c(x,101,5)
 end

 for k,b in pairs(l)do  -- for every ball...
  x=b.x    -- temp store frequently-used properties in variables to save on chars
  y=b.y    -- 
  b.v*=.97 -- apply drag/friction to balls' velocities to slow them to a stop
  b.b*=.97 -- 
  x+=b.v   -- apply the velocity to current ball position
  y+=b.b   -- 

  -- if the pixel colour under the ball position is black, kill ball + play "potted" sfx
  if(pget(x,y)<1) del(l,b) ?"\ax3c1"

  for l,t in pairs(l)do -- compare current ball to all other balls
   a=x-t.x z=y-t.y   -- calculate distance from ball
   d=sqrt(a*a+z*z)   -- 
   -- if ball is "other" and close enough, then displace both balls (+ play "hit" sfx)
   if(k!=l and d<6)add(m,{b,t})o=(d-8)/2x-=o*(a/d)y-=o*(z/d)t.x+=o*(a/d)t.y+=o*(z/d)?"\as0c"
  end  
  if(x>124or x<4)b.v*=-1.1  -- if ball hits table boundary,
  if(y>q or y<29)b.b*=-1.1  -- calc rebound angle (+ a bit of bounce acceleration)

  for i=1,3do  -- draw current ball
   -- drawn in 3 layers, from back to front
   -- the table below is the colour information for all 4 ball types:
   --  red (2,8,14), yellow (9,10,7), black (4,4,5) and white (6,7,7)
   -- the reason black uses colour 4 (brown) is because need a way to 
   -- distingush between black ball and black pockets
   -- (and you don't see brown colour drawn as pal() is replacing further up with black)
   c(x+min(2-i),y+1-i,4-i,({2,8,14,9,10,7,4,4,5,6,7,7})[b.c+i])
  end
  b.x=x b.y=y -- store our temp vars back into the ball object
 end

 -- resolve colliding pairs
 for p in all(m)do
  a=p[1] z=p[2]  -- calc distance between curr colliding balls
  d=sqrt((a.x-z.x)*(a.x-z.x)+(a.y-z.y)*(a.y-z.y))
  n=(z.x-a.x)/d  -- calc normal vector
  r=(z.y-a.y)/d  -- 
  v=a.v*-r+a.b*n -- calc dot product tangent
  y=z.v*-r+z.b*n -- 
  o=a.v*n+a.b*r  -- calc dot product normal
  k=z.v*n+z.b*r  -- 
  a.v=-r*v+n*k   -- calc final velocities for both colliding balls
  a.b=n*v+r*k    --
  z.v=-r*y+n*o   --
  z.b=n*y+r*o    --
 end
 -- if mouse button pressed, calculate velocity vector towards mouse position
 -- the further away, the faster the overall velocity will be
 -- (the /4 is to a hack to make it reasonable speeds, given max dist cursor could be)
 if(s(34)>0)b.v=-(b.x-u)/4b.b=-(b.y-i)/4 

 fillp()line(b.x,b.y,u,i)fillp()flip()  -- draw the aiming line, used for "shooting" above
end
Edit
Pub: 23 Aug 2022 04:55 UTC
Views: 330