-- 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