PicoPicoGameEngine

Quick Links

Source Code

g=ppgraph
rand=math.random
floor=math.floor
co=coroutine

se=ppsemml[1]
se_get="@15-0l32o5cdcecfcgcacb"
se_kill="@15-5l12o6b<b"
se_hit="@15-0l32o6b"

B=ppscreen:size()
Bw=B.width
Bh=B.height

mzw=10
mzh=7

mv={
{0,-1},
{-1,0},
{ 2,0},
{0, 2}
}

mv2={
{0,-3},
{-3,0},
{ 3,0},
{0, 3}
}

mv3={
{0,0},
{1,0},
{0,-1},
{-1,0},
{0,1},
}

mv4={
{0,0},
{16,0},
{0,-1},
{-1,0},
{0,16},
}

mv5={
{0,0},
{0,31},
{31,0},
{31,31},
}

t={
{"DFDFDF00FDFDFD00",
"0000000000000000",
"0000000000000000"},
{"7E80808080808000",
"FEFEFEFEFEFEFE00",
"FEFFFFFFFFFFFF7E"},
{"FF00FF00000000FF",
"0000FFFFFF000000",
"0000FFFFFFFF0000"},
{"A1A1A1A1A1A1A1A1",
"3838383838383838",
"3C3C3C3C3C3C3C3C"},
{"FF7F437F7F253FFF",
"3CFEC2FEFF65FF66",
"30C0C080879F0700"},
{"3C7EDBDBFFFFFF66",
 "0066424200420000",
 "3C7EDBDBFFC3FF66"},
{"3C7EDBDBFFFFFF66",
 "0066424200420000",
 "00664242007E0000"},
{"00664242007E0000",
 "3C7EDBDBFFC3FF66",
 "3C7EDBDBFFC3FF66"},
{"00664242007E0000",
 "3C7EDBDBFFC3FF66",
 "0066424200420000"},
{"81BDA5BD9BDDDBDD",
"003C243C181C181C",
"0000000000000000"},
{"C3BD7E7E7A7E7E00",
"0000000000000000",
"0000000000000000"},
{"C38106001E007E00",
"0000060E1E3E7E00",
"003C7E7E7E7E7E00"},
{"E7C3C3BD20000081",
"100010007E7E7E00",
"1800180020000000"}
}

function sgn(d)
if d<0 then
 d=-1
elseif d>0 then
 d=1
end
return d
end

o=ppoffscreen.new()
o:create(13*8,8)

o.defchar
=function(o,i,d)
local t
local dx=(i-1)*8
t="0123456789ABCDEF"
local function f(o,dx,s,k)
  local c
  for y=0,7 do
    local r,n
    for i=0,1 do
    n=y*2+1+i
    r=s:sub(n,n)
    r=t:find(r)-1
    for x=0,3 do
      local p,z
      p=(r%2)*255
      r=floor(r/2)
      z=3-x+i*4
      c=o:pixel(z+dx,y)
      c[k]=p
      c.a=255
      o:pixel(z+dx,y,c)
    end
    end
  end
end
f(o,dx,d[1],"r")
f(o,dx,d[2],"g")
f(o,dx,d[3],"b")
end

for i,d in ipairs(t)
do
  o:defchar(i,d)
end

o:hflip()
o:bind()
tex=o:texture()

mw=mzw*3+4
mh=mzh*3+4

D=pprect(
  -(mw*16-Bw),0,
  (mw*16-Bw)+16,16)

m=ppmap.new()
m:addLayer("layer")
m:mapSize(mw,mh)
m:clip(0,0,mw,mh)
m:tileSize(8,8)
m:texture(tex)
m:scale(2)

m.maze=function(m)
m:fill(0,0,mw,mh,1)
m:fill(1,1,mw-2,mh-2,2)
for x=3,mw-3,3 do
for y=1,mh-2,3 do
  m:tile(x,y,4)
  m:tile(x,y+1,4)
end
end
for y=3,mh-3,3 do
for x=1,mw-2,3 do
  m:tile(x,y,3)
  m:tile(x+1,y,3)
end
end
local 
function dig(m,x,y)
local loop
local t,o,u,q
loop=true
while loop do
  m:box(x,y,2,2,0)
  t={}
  for i=1,4 do
    q=pppoint(mv2[i])
    o=pppoint(mv[i])
    q:move(x,y)
    o:move(x,y)
    if m:tile(o)==1 then
    elseif m:tile(q)==0 then
    else
     t[#t+1]=i
    end
  end
  if #t<=0 then return end
  t=t[math.random(1,#t)]
  q=pppoint(mv2[t])
  o=pppoint(mv[t])
  u=pppoint(o)
  q:move(x,y)
  o:move(x,y)
  if u.x==0 then
  m:tile(o,1)
  o:move(1,0)
  m:tile(o,1)
  end
  if u.y==0 then
  m:tile(o,1)
  o:move(0,1)
  m:tile(o,1)
  end
  dig(m,q.x,q.y)
end
end
local x,y
x=math.random(0,mw-2)
x=math.floor(x/3)*3+1
y=math.random(0,mh-2)
y=math.floor(y/3)*3+1
dig(m,x,y)
for x=1,mw-1 do
for y=1,mh-1 do
 if m:tile(x,y)==0
 then
   m:tile(x,y,1)
 end
end
end
m:box(0,0,mw,mh,2)
end

m.idle=function(m)
 local t
 t=g:layout(gil:size(),
     true,true,B)
 m.x=t.x-gil.x-16
 if m.x>0 then
   m.x=0
 end
 if m.x<-(m.width-Bw)
 then
   m.x=-(m.width-Bw)
 end
end

m.check=function(m,r)
  local p
  for i=1,4 do
    p=pprect(r)
    p:move(mv5[i])
    p=p/16
    if m:tile(p)~=1
    then
      return false
    end
  end
  return true
end

bt=ppbutton("CREATE")
t=g:layout(bt,true,true,B)
t.y=Bh-t.height-128
bt:pos(t)

t=ppoffscreen.new()
t:create(32,32)
t:circle(16,16,12)
t:paint(16,16)
t:alpha(128)
cur=t

ppvkey:center(Bw/2,Bh-80)
ppvkey:fixed(true)

t=ppsprite.new()
t:tileSize(8,8)
t:tile(5)
t:texture(tex)
t:scale(4)
gil=pprect(16,16)
gil.hitmask=1
gil.hitrect=t:size()
gil.idle=function(s)
 local t,r
 r=pprect(s.x,s.y,32,32)
 t=ppvkey:dir(4)+2
 if ppkey.up() then
   t=3
 elseif ppkey.down() then
   t=5
 elseif ppkey.left() then
   t=4
 elseif ppkey.right() then
   t=2
 end
 if t>1 then
 if s.x==r.x
 and s.y==r.y then
   r:move(pppoint(mv4[t]))
   r.x=floor(r.x/16)*16
   r.y=floor(r.y/16)*16
   if key.x==s.x and
      key.y==s.y
   then
     if not key.get then
       se:play(se_get)
     end
     key.get=true
   end
   if key.get then
     if door:intersect(r)
     then
       door.open=true
       key.sp:hide()
       door.sp:tile(12)
     end
   end
   if door.open then
   if door.x==s.x and
      door.y==s.y
   then
     loop=false
   end
   end
   if port.sp:isVisible()
   then
     if port.x==s.x and
        port.y==s.y
     then
       port.sp:hide()
       life=life+20
       se:play(se_get)
       if life>100 then
         life=100
       end
     end
   end
 end
 if m:check(r) then
 s.r=pprect(r)
 end
 if r and s.r then
   r.x=sgn(s.r.x-s.x)
   r.y=sgn(s.r.y-s.y)
   s:move(r)
 end
 end
 if (interval%4)==0 then
   local f=false
   local k=false
   pphitcheck(u,{s},
     function(a,b)
       f=true
       life=life-2
       if life<0 then
         life=0
       end
       if t>1 then
         a.life=a.life-1
         if a.life<=0 then
           a.hitmask=0
           a.sp:hide()
           k=true
           se:play(se_kill)
         end
       end
     end)
   if not k then
   if f and 
     (interval%8)==0 then
    se:play(se_hit)
   end
   end
 end
end
gil.draw=function(s)
 s.sp:pos(m:pos())
 s.sp:move(s)
 s.sp:draw()
 cur:pos(s.sp:pos())
 cur:move(ppvkey:delta()/2)
 if #pptouch()>0 then
 cur:draw()
 end
end
gil.sp=t

function rpos()
local x,y
x=16+48*math.random(0,mzw)
y=16+48*math.random(0,mzh)
return x,y
end

function mpos()
local x,y,dx,dy
while true do
x,y=rpos()
dx=gil.x-x
dx=dx*sgn(dx)
dy=gil.y-y
dy=dy*sgn(dy)
if dx+dy>10*32 then
  break
end
end
return x,y
end

function mon(t,x,y,q)
local r
r=pprect(x,y,32,32)
local s
s=ppsprite.new()
s:tileSize(8,8)
s:texture(tex)
s:scale(4)
s:tile(t)
r.sp=s
r.q=q
r.speed=0.5
r.d=math.random(2,5)
r.hitmask=1
r.hitrect=s:size()
r.life=15
r.co=co.create(
function(s)
local function lim(d)
 if d<2 then
  d=d+4
 end
 if d>5 then
  d=d-4
 end
 return d
end
local function chk(s,d)
  local r
  r=pprect(s)
  r:move(mv3[d])
  if m:check(r) then
   return true
  end
  return false
end
  local k=1
  local p=s.speed
  local r
  while true do
  local d=s.d
  local q=s.q
  if chk(s,lim(d+q)) then
    d=lim(d+q)
  else
    if chk(s,d) then
    elseif chk(s,lim(d-q)) then
      d=lim(d-q)
    else
      d=lim(d+2)
    end
  end
  s.d=d
  for i=1,48 do
  while true do
  if k>=0 then
  k=k-p
  end
  if k<=0 then
  r=pprect(s)
  r:move(mv3[d])
  if m:check(r) then
    s:move(mv3[d])
  end
    k=k+1
    if k>=0 then
    co.yield()
    end
    break
  else
    co.yield()
  end
  end
  end
  end
end)
r.idle=function(s)
 co.resume(s.co,s)
end
r.draw=function(s)
 if s.sp:isVisible()
 then
   s.sp:pos(m:pos())
   s.sp:move(s)
   s.sp:draw()
 end
end
return r
end

function obj(t)
local x,y
x,y=mpos()
local s
s=pprect(x,y,32,32)
s.sp=ppsprite.new()
s.sp:tileSize(8,8)
s.sp:scale(4)
s.sp:texture(tex)
s.sp:tile(t)
s.draw=function(s)
 s.sp:pos(m:pos())
 s.sp:move(s)
 if s.get then
  s.sp:pos(0,m.height+16)
 end
 s.sp:draw()
end
return s
end

function gameinit()
stage=1
life=100
interval=0
end

function gamestart()

m:maze()

for i=1,120 do
local s
s="FLOOR "..stage
local p
p=ppfont:size(s)
p.y=-100
p=g:layout(p,true,true,B)
g:pos(p)
g:print(s)
g:update()
end

local x,y
x,y=rpos()
gil:pos(x,y)

u={}
for i=1,4 do
local x,y,q,t
x,y=mpos()
q=math.random(0,1)
if q==0 then
 q=-1
end
t=math.random(6,9)
u[#u+1]=mon(t,x,y,q)
end

key=obj(10)
key.get=false
door=obj(11)
door.open=false
port=obj(13)

loop=true

m:idle()
for i=1,120 do
if (i%4)<2 then
gil.sp:hide()
else
gil.sp:show()
end
gamedraw()
g:update()
end
gil.sp:show()

end

function drawlife()
local s
s="LIFE"
g:pos(0,m.height)
g:print(s)
local sz
sz=ppfont:size(s).width
g:fill(sz,m.height,
       320-sz,16,g.blue)
g:fill(sz,m.height,
       life*(320-sz)/100,
       16,g.yellow)
end

function gameidle()
gil:idle()
gil:idle()
m:idle()
for i,u in ipairs(u) do
u:idle()
end
end

function gamedraw()
interval=interval+1
m:draw()
door:draw()
port:draw()
key:draw()
for i,u in ipairs(u) do
u:draw()
end
gil:draw()
drawlife()
cur:pos(ppvkey:center())
cur:move(-16,-16)
t=cur:pos()
cur:move(0,60)
cur:draw()
cur:pos(t)
cur:move(0,-60)
cur:draw()
cur:pos(t)
cur:move(-60,0)
cur:draw()
cur:pos(t)
cur:move(60,0)
cur:draw()
end

function gametitle()
local bt
bt=ppbutton("START")
local p
p=g:layout(
  bt:size(),true,true,B)
bt:pos(p)
bt:move(0,100)
while true do
local s
s="THE TOWER OF"
local w
p=ppfont:size(s)
p.y=-100
p=g:layout(p,true,true,B)
g:pos(p)
g:print(s,g.red)
s="PICOAGA"
p=g:pos()
g:scale(2.5,6)
g:pos(0,p.y)
w=ppfont:size(s)
w=w.width*2.5
g:pos(
  ((B.width-w)/2)+8,
  p.y+32)
g:pivot(g:pos())
g:print(s,g.cyan)
g:scale(1)
if bt:idle(pptouch())
then
  se:play(se_kill)
  break
end
bt:draw()
g:box(bt:aabb(),g.yellow)
g:update()
end
end

function gameover()
for i=1,180 do
local s
s="GAME OVER"
local p
p=ppfont:size(s)
p.y=-100
p=g:layout(p,true,true,B)
g:pos(p)
g:print(s,g.red)
g:update()
end
end

function gameclear()
for i=1,120 do
gamedraw()
g:update()
end
stage=stage+1
end

function gamemiss()
for i=1,120 do
if (i%4)<2 then
gil.sp:hide()
else
gil.sp:show()
end
gamedraw()
g:update()
end
end

function start()
gametitle()
gameinit()
while true do
gamestart()
while loop do
  gameidle()
  gamedraw()
  if life==0 then
    gamemiss()
    loop=false
  end
  g:update()
end
if life==0 then
  break
end
gameclear()
end
gameover()
end