Advertisement
GopherAtl

wolf3d proof of concept (cc lua)

Feb 28th, 2013
2,575
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.26 KB | None | 0 0
  1. local buffer=term
  2. local loadedAPI=false
  3.  
  4. if redirect then
  5.   buffer=redirect.createRedirectBuffer()
  6.   print("redirect API found, using buffer")
  7. else
  8.   local pe=printError
  9.   rawset(_G,"printError",error)  
  10.   local ok, err=pcall(os.loadAPI,"redirect")
  11.   if not ok then
  12.     print("trying "..shell.dir().."/redirect")
  13.     ok,err=pcall(os.loadAPI,shell.dir().."/redirect")
  14.   end
  15.   if ok then    
  16.     print("Loaded redirect API, using buffer")
  17.     buffer=redirect.createRedirectBuffer()
  18.     loadedAPI=true
  19.   else
  20.     print("redirect API not found or could not be loaded, drawing directly; this may cause flickering.")
  21.   end
  22.   rawset(_G,"printError",pe)
  23.  
  24. end
  25.  
  26.  
  27. local mapW, mapH=16,32
  28. local map={
  29.   "1111111111111111",
  30.   "1   12         1",
  31.   "1 111111111111 1",
  32.   "1 1      1   1 1",
  33.   "1 1 1111 1 1 1 1",
  34.   "1 1   1  1 1   1",
  35.   "1 111 111111 111",
  36.   "1   1          1",
  37.   "111 11111111 1 1",
  38.   "1 1          1 1",
  39.   "1 111111111111 1",
  40.   "1   1 1    1   1",
  41.   "1 111 1 1111 111",
  42.   "1     1    1   1",
  43.   "1 11111111 111 1",
  44.   "1              1",
  45.   "1111114  4111111",
  46.   "1              1",
  47.   "1              1",
  48.   "1  3  3  3  3  1",
  49.   "1              1",
  50.   "1              1",
  51.   "1  2  5  5  2  1",
  52.   "1              1",
  53.   "1              1",
  54.   "1  2  5  5  2  1",
  55.   "1              1",
  56.   "1              1",
  57.   "1  3  2  2  3  1",
  58.   "1              1",
  59.   "1              1",
  60.   "1111111111111111",
  61. }  
  62.  
  63. local colorSchemes = {
  64.   {0,8}, --white+gray
  65.   {3,11}, --blue
  66.   {6,14}, --red
  67.   {5,13}, --green
  68.   {4,1}, --yellow/orange
  69. }
  70.  
  71.  
  72. local function cast(cx,cy,angle)
  73.   --direction vector
  74.   local vx,vy=math.cos(angle), math.sin(angle)
  75.   local slope=vy/vx
  76.   --next distance, x and y axis points
  77.   local ndx, ndy
  78.   --steps, distance and block
  79.   local dsx, dsy, bsx, bsy
  80.   if vx<0 then
  81.     local x=(cx%1)
  82.     bsx=-1
  83.     ndx=math.sqrt(x*x*(1+slope*slope))
  84.     dsx=math.sqrt((1+slope*slope))
  85.   else
  86.     local x=1-(cx%1)
  87.     bsx=1
  88.     ndx=math.sqrt(x*x*(1+slope*slope))
  89.     dsx=math.sqrt((1+slope*slope))
  90.   end
  91.  
  92.   if vy<0 then
  93.     local y=(cy%1)
  94.     bsy=-1
  95.     ndy=math.sqrt(y*y*(1+1/(slope*slope)))
  96.     dsy=math.sqrt((1+1/(slope*slope)))
  97.   else
  98.     local y=1-(cy%1)
  99.     bsy=1
  100.     ndy=math.sqrt(y*y*(1+1/(slope*slope)))
  101.     dsy=math.sqrt((1+1/(slope*slope)))
  102.   end
  103.  
  104.   local x,y=math.floor(cx),math.floor(cy)
  105.   while x>0 and x<=mapW and y>0 and y<=mapH do
  106.     local hitD
  107.     local isX
  108.     if ndx<ndy then
  109.       --x crossing is next
  110.       x=x+bsx
  111.       isX=true
  112.       hitD=ndx
  113.       ndx=ndx+dsx
  114.     else
  115.       y=y+bsy
  116.       isX=false
  117.       hitD=ndy
  118.       ndy=ndy+dsy
  119.     end
  120.     local wall=map[y]:sub(x,x)
  121.     if wall~=" " then
  122.      
  123.       return colorSchemes[tonumber(wall)][isX and 1 or 2], hitD
  124.     end
  125.   end  
  126. end
  127.  
  128. local w,h=term.getSize()
  129. local centerX, centerY=math.floor((w+1)/2), math.floor((h+1)/2)
  130.  
  131. local px, py=9,25
  132. local dir=0
  133. local fx,fy
  134. local speed=.1
  135. local turnSpeed=4
  136.  
  137. local function turn(amt)
  138.   dir=dir+amt
  139.   fx,fy=math.cos(math.rad(dir)), math.sin(math.rad(dir))
  140. end
  141.  
  142. turn(0)
  143.  
  144. --build table of angles and base distances per scanline
  145. local screenDist=.55*w
  146. local scan={}
  147.  
  148. for x=1,w do
  149.   local t={}
  150.   scan[x]=t
  151.   t.angle=math.atan2(x-centerX,screenDist)
  152.   t.dist=((x-centerX)^2+screenDist^2)^.5/screenDist
  153. end
  154.  
  155. local function redraw()
  156.   if buffer.isBuffer then
  157.     term.redirect(buffer)
  158.   end
  159.   for x=1,w do
  160.     local wall,dist=cast(px,py,math.rad(dir)+scan[x].angle)
  161.     if wall then
  162.       --calc wall height based on distance
  163.       local height=scan[x].dist/dist
  164.       height=math.floor(math.min(height*centerY,(h+1)/2))
  165.       term.setBackgroundColor(colors.gray)
  166.       for y=1,(h+1)/2-height-1 do
  167.         term.setCursorPos(x,y)
  168.         term.write(" ")
  169.       end
  170.       for y=centerY+height+1,h do
  171.         term.setCursorPos(x,y)
  172.         term.write(" ")
  173.       end
  174.       term.setBackgroundColor(2^wall)
  175.       for y=centerY-height,centerY+height do
  176.         term.setCursorPos(x,y)
  177.         term.write(" ")
  178.       end
  179.     end
  180.   end
  181.   if buffer.isBuffer then
  182.     term.restore()
  183.     buffer.blit()
  184.   end
  185. end
  186.  
  187. local function clampCollision(x,y,radius)
  188.   --am I *in* a block?
  189.   local gx,gy=math.floor(x),math.floor(y)
  190.   if map[gy]:sub(gx,gx)~=" " then
  191.     --I am. Complete fail, do nothing.
  192.     return x,y
  193.   end
  194.  
  195.   --ok, check the neighbors.
  196.   local right=math.floor(x+radius)>gx
  197.   local left=math.floor(x-radius)<gx
  198.   local front=math.floor(y-radius)<gy
  199.   local back=math.floor(y+radius)>gy
  200.  
  201.   local pushed=false
  202.  
  203.   if right and map[gy]:sub(gx+1,gx+1)~=" " then
  204.     --push left
  205.     pushed=true
  206.     x=gx+1-radius
  207.   elseif left  and map[gy]:sub(gx-1,gx-1)~=" " then
  208.     --push right
  209.     pushed=true
  210.     x=gx+radius
  211.   end
  212.  
  213.   if front and map[gy-1]:sub(gx,gx)~=" " then
  214.     --push back
  215.     pushed=true
  216.     y=gy+radius
  217.   elseif back and map[gy+1]:sub(gx,gx)~=" " then
  218.     --push forward
  219.     pushed=true
  220.     y=gy+1-radius
  221.   end
  222.  
  223.   --if I wasn't pushed out on any side, I might be hitting a corner
  224.   if not pushed then
  225.     --square rad
  226.     local r2=radius^2
  227.     local pushx,pushy=0,0
  228.     if left then
  229.       if front and map[gy-1]:sub(gx-1,gx-1)~=" " then
  230.         --check front-left
  231.         local dist2=(gx-x)^2+(gy-y)^2
  232.         if dist2<r2 then
  233.           local pushd=(r2-dist2)/2^.5
  234.           pushx,pushy=pushd,pushd
  235.         end
  236.       elseif back and map[gy+1]:sub(gx-1,gx-1)~=" " then
  237.         local dist2=(gx-x)^2+(gy+1-y)^2
  238.         if dist2<r2 then
  239.           local pushd=(r2-dist2)/2^.5
  240.           pushx,pushy=pushd,-pushd
  241.         end
  242.       end
  243.     elseif right then
  244.       if front and map[gy-1]:sub(gx+1,gx+1)~=" " then
  245.         --check front-left
  246.         local dist2=(gx+1-x)^2+(gy-y)^2
  247.         if dist2<r2 then
  248.           local pushd=(r2-dist2)/2^.5
  249.           pushx,pushy=-pushd,pushd
  250.         end
  251.       elseif back and map[gy+1]:sub(gx+1,gx+1)~=" " then
  252.         local dist2=(gx+1-x)^2+(gy+1-y)^2
  253.         if dist2<r2 then
  254.           local pushd=(r2-dist2)/2^.5
  255.           pushx,pushy=-pushd,-pushd
  256.         end
  257.       end
  258.     end
  259.     x=x+pushx
  260.     y=y+pushy
  261.   end
  262.  
  263.   return x,y
  264. end
  265.  
  266.  
  267.  
  268. print([[
  269. Basic wolfenstein 3d-style rendering engine proof-of-concept
  270. controls:
  271. asdw - move
  272. left/right - turn left/right
  273. q - quit
  274.  
  275. Press any key to begin...]])
  276.  
  277. os.pullEvent("key")
  278.  
  279. local frameTimer=os.startTimer(0.5)
  280. local prevTick=0
  281. local dirty=true
  282. while true do
  283.   px,py=clampCollision(px,py,.25)
  284.   if dirty then
  285.     redraw()
  286.     dirty=false
  287.   end
  288.  
  289.   local e={os.pullEvent()}
  290.   if e[1]=="key" then
  291.     if e[2]==keys.left then
  292.       turn(-turnSpeed)
  293.       dirty=true
  294.     elseif e[2]==keys.right then
  295.       turn(turnSpeed)
  296.       dirty=true
  297.     elseif e[2]==keys.up or e[2]==keys.w then
  298.       px=px+fx*speed
  299.       py=py+fy*speed
  300.       dirty=true
  301.     elseif e[2]==keys.down or e[2]==keys.s then
  302.       px=px-fx*speed
  303.       py=py-fy*speed
  304.       dirty=true
  305.     elseif e[2]==keys.a then
  306.       px=px+fy*speed
  307.       py=py-fx*speed
  308.       dirty=true
  309.     elseif e[2]==keys.d then
  310.       px=px-fy*speed
  311.       py=py+fx*speed
  312.       dirty=true
  313.     elseif e[2]==keys.q then
  314.       break
  315.     end
  316.   end
  317. end
  318.  
  319.  
  320. if loadedAPI then
  321.   os.unloadAPI("redirect")
  322. end
  323.  
  324. term.setBackgroundColor(colors.black)
  325. os.pullEvent()
  326. term.scroll(1)
  327. term.setCursorPos(1,19)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement