Xelostar

ThreeD_API_v0.5.1_Demo3

Jul 22nd, 2018
303
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.26 KB | None | 0 0
  1.  
  2. -- Made by Xelostar: https://www.youtube.com/channel/UCDE2STpSWJrIUyKtiYGeWxw
  3.  
  4. local path = "/"..shell.dir() -- path to this program
  5.  
  6. os.loadAPI(path.."/ThreeD") -- loading the APIs
  7. os.loadAPI(path.."/bufferAPI")
  8. os.loadAPI(path.."/blittle")
  9.  
  10. local objects = { -- all objects in the game
  11.     {model = "box", x = 4, y = 0.5, z = 0},
  12.     {model = "spike", x = 4, y = 0.5, z = 2},
  13.     {model = "spike", x = 4, y = 0.5, z = 4, rotationY = 45},
  14.     {model = "emerald", x = 4, y = 0.5, z = 6},
  15.     {model = "pineapple", x = 4, y = 0.5, z = 8, rotationY = 0},
  16. }
  17.  
  18. local playerX = -3 -- player position
  19. local playerY = 0
  20. local playerZ = 1
  21.  
  22. local playerSpeed = 3 -- player movement speed
  23. local playerTurnSpeed = 180 -- player turn speed
  24.  
  25. local keysDown = {} -- keysDown[key] is true if the key is down (for smooth input)
  26. local blockThickness = 0.9 -- the size of the hitbox for the solid blocks from the middle of the object
  27.  
  28. local FoV = 90 -- field of view
  29.  
  30. local playerDirectionHor = 0 -- camera direction
  31. local playerDirectionVer = 0
  32.  
  33. local screenWidth, screenHeight = term.getSize() -- size of the screen
  34.  
  35. local backgroundColor1 = colors.lime -- ground color
  36. local backgroundColor2 = colors.lightBlue -- sky color
  37.  
  38. local ThreeDFrame = ThreeD.newFrame(1, 1, screenWidth, screenHeight, FoV, playerX, playerY + 0.5, playerZ, playerDirectionVer, playerDirectionHor, path.."/models") -- making a new frame where the camera is 0.5 blocks above the player
  39. local blittleOn = true -- blittle is turned on by default
  40. ThreeDFrame:useBLittle(blittleOn) -- set the frame to use blittle
  41.  
  42. local totalTime = 0 -- time in seconds elapsed since the start of the program
  43.  
  44. local function rendering()
  45.     while true do
  46.         ThreeDFrame:loadGround(backgroundColor1)
  47.         ThreeDFrame:loadSky(backgroundColor2)
  48.         ThreeDFrame:loadObjects(objects)
  49.         ThreeDFrame:drawBuffer()
  50.  
  51.         os.queueEvent("FakeEvent") -- to prevent "too long without yielding" errors without slowing down the program
  52.         os.pullEvent("FakeEvent")
  53.     end
  54. end
  55.  
  56. local function free(x, y, z) -- for collision detection. Tests to see if there's a hitbox (x, y, z) is in
  57.     for _, object in pairs(objects) do
  58.         if (object.solid == true) then
  59.             if (x >= object.x - blockThickness and x <= object.x + blockThickness) then
  60.                 if (y >= object.y - 1 and y <= object.y + 0.5 + 0.2) then -- the height is done differently, since the  player has to have a certain height (different collision from feet and head)
  61.                     if (z >= object.z - blockThickness and z <= object.z + blockThickness) then
  62.                         return false -- collision detected
  63.                     end
  64.                 end
  65.             end
  66.         end
  67.     end
  68.  
  69.     return true -- no collision detected
  70. end
  71.  
  72. local function inputPlayer(time) -- time is the elapsed time in seconds since the last time this function was executed
  73.     local dx = 0
  74.     local dy = 0
  75.     local dz = 0
  76.  
  77.     if (keysDown[keys.left]) then
  78.         playerDirectionHor = playerDirectionHor - playerTurnSpeed * time
  79.         if (playerDirectionHor <= -180) then
  80.             playerDirectionHor = playerDirectionHor + 360
  81.         end
  82.     end
  83.     if (keysDown[keys.right]) then
  84.         playerDirectionHor = playerDirectionHor + playerTurnSpeed * time
  85.         if (playerDirectionHor >= 180) then
  86.             playerDirectionHor = playerDirectionHor - 360
  87.         end
  88.     end
  89.     if (keysDown[keys.down]) then
  90.         playerDirectionVer = playerDirectionVer - playerTurnSpeed * time
  91.         if (playerDirectionVer < -80) then
  92.             playerDirectionVer = -80
  93.         end
  94.     end
  95.     if (keysDown[keys.up]) then
  96.         playerDirectionVer = playerDirectionVer + playerTurnSpeed * time
  97.         if (playerDirectionVer > 80) then
  98.             playerDirectionVer = 80
  99.         end
  100.     end
  101.     if (keysDown[keys.w]) then
  102.         dx = playerSpeed * math.cos(math.rad(playerDirectionHor)) + dx
  103.         dz = playerSpeed * math.sin(math.rad(playerDirectionHor)) + dz
  104.     end
  105.     if (keysDown[keys.s]) then
  106.         dx = -playerSpeed * math.cos(math.rad(playerDirectionHor)) + dx
  107.         dz = -playerSpeed * math.sin(math.rad(playerDirectionHor)) + dz
  108.     end
  109.     if (keysDown[keys.a]) then
  110.         dx = playerSpeed * math.cos(math.rad(playerDirectionHor - 90)) + dx
  111.         dz = playerSpeed * math.sin(math.rad(playerDirectionHor - 90)) + dz
  112.     end
  113.     if (keysDown[keys.d]) then
  114.         dx = playerSpeed * math.cos(math.rad(playerDirectionHor + 90)) + dx
  115.         dz = playerSpeed * math.sin(math.rad(playerDirectionHor + 90)) + dz
  116.     end
  117.    
  118.     if (keysDown[keys.space]) then
  119.         dy = playerSpeed + dy
  120.     end
  121.     if (keysDown[keys.leftShift]) then
  122.         dy = -playerSpeed + dy
  123.     end
  124.    
  125.     -- if where the player will move to is free (no collisions) then move there
  126.     if (free(playerX + dx * time, playerY, playerZ) == true) then
  127.         playerX = playerX + dx * time -- multiply by time so that dx becomes blocks per second
  128.     end
  129.     if (playerY + dy * time >= 0) then
  130.         if (free(playerX, playerY + dy * time, playerZ) == true) then
  131.             playerY = playerY + dy * time
  132.         end
  133.     end
  134.     if (free(playerX, playerY, playerZ + dz * time) == true) then
  135.         playerZ = playerZ + dz * time
  136.     end
  137.  
  138.     ThreeDFrame:setCamera(playerX, playerY + 0.5, playerZ, playerDirectionHor, playerDirectionVer) -- set the new camera position according to the player (again the height is 0.5 blocks above the feet)
  139. end
  140.  
  141. local function keyInput()
  142.     while true do
  143.         local event, key, x, y = os.pullEventRaw()
  144.  
  145.         if (event == "key") then -- detect key presses
  146.             keysDown[key] = true
  147.             if (key == keys.g) then -- if the button is supposed to be pressed once, we'll deal with the processing of the input here
  148.                 if (blittleOn == false) then
  149.                     blittleOn = true
  150.                     ThreeDFrame:useBLittle(true)
  151.                 else
  152.                     blittleOn = false
  153.                     ThreeDFrame:useBLittle(false)
  154.                 end
  155.             end
  156.         elseif (event == "key_up") then -- detect key releases
  157.             keysDown[key] = nil
  158.         elseif (event == "mouse_click") then
  159.             local objectIndex, polyIndex = ThreeDFrame:getObjectIndexTrace(objects, x, y) -- detect on what and object the player clicked
  160.             if (objectIndex ~= nil) then -- if the player clicked on an object (not void)
  161.                 local modelName = objects[objectIndex].model
  162.                 local model = ThreeDFrame:getModel(modelName)
  163.                 table.remove(model, polyIndex)
  164.                 ThreeDFrame:loadModel(modelName, model)
  165.             end
  166.         end
  167.     end
  168. end
  169.  
  170. local function updateGame(time) -- time is the elapsede time in seconds since the last time this function was executed
  171.     totalTime = totalTime + time -- increase the total time that has elapsed
  172.     for objectNr, object in pairs(objects) do
  173.         if (object.model == "pineapple") then -- for all pineapples:
  174.             object.y = math.sin(totalTime*2)/4 -- set their height according to totalTime to make them smoothly bob up and down
  175.             object.rotationY = object.rotationY + 50*time -- increase their rotation according to the time that has elapsed (50 degrees per second of rotation)
  176.         end
  177.     end
  178. end
  179.  
  180. local function gameUpdate() -- this function uses some trickery to estimate the time elapsed more precise than 1 Minecraft tick (0.05 seconds)
  181.     -- a lot of the time, withing each game tick about three frames are rendered which means that the accuracy is more like 0.02 seconds
  182.     local timeFromLastUpdate = os.clock() -- the time frome last update
  183.     local avgUpdateSpeed = 0 -- this indicates the average update speed in seconds per frame
  184.     local updateCount = 0 -- keep track of the frames drawn between each game tick
  185.  
  186.     while true do
  187.         local currentTime = os.clock() -- the current time
  188.         if (currentTime <= timeFromLastUpdate) then
  189.             updateGame(avgUpdateSpeed) -- still the same game tick as the last frame, so just update it with the average delay
  190.             inputPlayer(avgUpdateSpeed) -- same for the player input
  191.  
  192.             updateCount = updateCount + 1 -- increase the update counter
  193.             if (updateCount >= 3) then
  194.                 sleep(0)
  195.             end
  196.         else -- if the next game tick is here:
  197.             local timeOff = -avgUpdateSpeed * (updateCount - 1)
  198.  
  199.             updateGame(currentTime - timeFromLastUpdate + timeOff) -- update the game normally with the difference in time minus the time we estimated wrongly to compensate
  200.             inputPlayer(currentTime - timeFromLastUpdate + timeOff) -- same for the player input
  201.  
  202.             avgUpdateSpeed = 0.05 / (updateCount + 2) -- calculate the new average delay between each frame
  203.  
  204.             updateCount = 1 -- set the update counter to 0 to restart counting
  205.             timeFromLastUpdate = currentTime -- update the time since the last update
  206.         end
  207.  
  208.         coroutine.yield()
  209.     end
  210. end
  211.  
  212. parallel.waitForAll(keyInput, gameUpdate, rendering) -- handle input, the game mechanics and the rendering simultaniously
Add Comment
Please, Sign In to add comment