Advertisement
nonogamer9

OC-Craft : Minecraft Clone For OpenComputers (Version 0.1)

Aug 6th, 2024 (edited)
212
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.06 KB | Software | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local term = require("term")
  4. local gpu = component.gpu
  5. local computer = require("computer")
  6.  
  7. -- Constants
  8. local WIDTH, HEIGHT = 160, 50
  9. local FOV, RENDER_DISTANCE = math.pi / 3, 20
  10. local WORLD_SIZE, WORLD_HEIGHT = 32, 32
  11. local GRAVITY, JUMP_STRENGTH = -9.81, 5
  12. local PLAYER_WIDTH, PLAYER_HEIGHT = 0.6, 1.8
  13.  
  14. -- Colors
  15. local colors = {
  16.   WHITE = 0xFFFFFF, GRAY = 0x808080, DARK_GRAY = 0x404040,
  17.   STONE = 0x7F7F7F, DIRT = 0x8B4513, GRASS = 0x00FF00,
  18.   WOOD = 0x8B4513, LEAVES = 0x228B22
  19. }
  20.  
  21. -- Block types
  22. local BLOCK_AIR, BLOCK_STONE, BLOCK_DIRT, BLOCK_GRASS, BLOCK_WOOD, BLOCK_LEAVES = 0, 1, 2, 3, 4, 5
  23.  
  24. -- Setup
  25. gpu.setResolution(WIDTH, HEIGHT)
  26. local back_buffer = gpu.allocateBuffer(WIDTH, HEIGHT)
  27.  
  28. -- World generation
  29. local function noise(x, z)
  30.   return math.sin(x * 0.1) * math.cos(z * 0.1) * 0.5 + 0.5
  31. end
  32.  
  33. local world, highest_y = {}, {}
  34. for x = 1, WORLD_SIZE do
  35.   world[x], highest_y[x] = {}, {}
  36.   for z = 1, WORLD_SIZE do
  37.     world[x][z] = {}
  38.     local height = math.floor(noise(x, z) * (WORLD_HEIGHT / 2 - 1)) + WORLD_HEIGHT / 2
  39.     highest_y[x][z] = height
  40.     for y = 1, WORLD_HEIGHT do
  41.       world[x][z][y] = y == height and BLOCK_GRASS or
  42.                        (y < height and y > height - 3 and BLOCK_DIRT or
  43.                        (y < height and BLOCK_STONE or BLOCK_AIR))
  44.     end
  45.   end
  46. end
  47.  
  48. -- Generate trees
  49. local function generateTree(x, y, z)
  50.   if world[x][z][y] == BLOCK_GRASS then
  51.     for ty = 1, 5 do world[x][z][y + ty] = BLOCK_WOOD end
  52.     for tx = -2, 2 do
  53.       for tz = -2, 2 do
  54.         for ty = 4, 6 do
  55.           if x + tx >= 1 and x + tx <= WORLD_SIZE and
  56.              z + tz >= 1 and z + tz <= WORLD_SIZE and
  57.              y + ty <= WORLD_HEIGHT and world[x + tx][z + tz][y + ty] == BLOCK_AIR then
  58.             world[x + tx][z + tz][y + ty] = BLOCK_LEAVES
  59.           end
  60.         end
  61.       end
  62.     end
  63.   end
  64. end
  65.  
  66. for _ = 1, 10 do
  67.   local x, z = math.random(1, WORLD_SIZE), math.random(1, WORLD_SIZE)
  68.   generateTree(x, highest_y[x][z], z)
  69. end
  70.  
  71. -- Find a safe spawn position
  72. local function findSafeSpawn()
  73.   local center_x, center_z = math.floor(WORLD_SIZE / 2), math.floor(WORLD_SIZE / 2)
  74.   local max_distance = math.floor(WORLD_SIZE / 4)
  75.  
  76.   for distance = 0, max_distance do
  77.     for dx = -distance, distance do
  78.       for dz = -distance, distance do
  79.         local x, z = center_x + dx, center_z + dz
  80.         if x >= 1 and x <= WORLD_SIZE and z >= 1 and z <= WORLD_SIZE then
  81.           local y = highest_y[x][z]
  82.           -- Check if there's enough space for the player
  83.           if y < WORLD_HEIGHT - 2 and
  84.              world[x][z][y] == BLOCK_GRASS and
  85.              world[x][z][y + 1] == BLOCK_AIR and
  86.              world[x][z][y + 2] == BLOCK_AIR then
  87.             return x, y, z
  88.           end
  89.         end
  90.       end
  91.     end
  92.   end
  93.  
  94.   -- If no safe spawn is found, return the center of the world
  95.   return center_x, highest_y[center_x][center_z], center_z
  96. end
  97.  
  98. -- Find spawn position
  99. local spawn_x, spawn_y, spawn_z = findSafeSpawn()
  100.  
  101. -- Player setup
  102. local player = {
  103.   x = spawn_x + 0.5,
  104.   y = spawn_y + PLAYER_HEIGHT,
  105.   z = spawn_z + 0.5,
  106.   rotH = 0,
  107.   rotV = 0,
  108.   vy = 0,
  109.   onGround = false
  110. }
  111. local inventory = {[BLOCK_STONE] = 0, [BLOCK_DIRT] = 0, [BLOCK_GRASS] = 0, [BLOCK_WOOD] = 0, [BLOCK_LEAVES] = 0}
  112. local selected_slot = BLOCK_STONE
  113. local playerMovement = {forward = false, backward = false, left = false, right = false}
  114.  
  115. -- Optimized raycast function
  116. local function raycast(x, y, z, dx, dy, dz)
  117.   local stepX, stepY, stepZ = dx > 0 and 1 or -1, dy > 0 and 1 or -1, dz > 0 and 1 or -1
  118.   local tMaxX = dx ~= 0 and (math.floor(x + (stepX > 0 and 1 or 0)) - x) / dx or math.huge
  119.   local tMaxY = dy ~= 0 and (math.floor(y + (stepY > 0 and 1 or 0)) - y) / dy or math.huge
  120.   local tMaxZ = dz ~= 0 and (math.floor(z + (stepZ > 0 and 1 or 0)) - z) / dz or math.huge
  121.   local tDeltaX, tDeltaY, tDeltaZ = dx ~= 0 and stepX / dx or math.huge, dy ~= 0 and stepY / dy or math.huge, dz ~= 0 and stepZ / dz or math.huge
  122.   local bx, by, bz = math.floor(x), math.floor(y), math.floor(z)
  123.  
  124.   for _ = 1, RENDER_DISTANCE do
  125.     if bx < 1 or bx > WORLD_SIZE or by < 1 or by > WORLD_HEIGHT or bz < 1 or bz > WORLD_SIZE then return nil end
  126.     if world[bx] and world[bx][bz] and world[bx][bz][by] and world[bx][bz][by] ~= BLOCK_AIR then
  127.       return bx, by, bz, math.sqrt((bx-x)^2 + (by-y)^2 + (bz-z)^2)
  128.     end
  129.     if tMaxX < tMaxY and tMaxX < tMaxZ then
  130.       bx, tMaxX = bx + stepX, tMaxX + tDeltaX
  131.     elseif tMaxY < tMaxZ then
  132.       by, tMaxY = by + stepY, tMaxY + tDeltaY
  133.     else
  134.       bz, tMaxZ = bz + stepZ, tMaxZ + tDeltaZ
  135.     end
  136.   end
  137.   return nil
  138. end
  139.  
  140. -- Rendering function
  141. local function render()
  142.   gpu.setActiveBuffer(back_buffer)
  143.   gpu.fill(1, 1, WIDTH, HEIGHT, " ")
  144.  
  145.   local sinH, cosH = math.sin(player.rotH), math.cos(player.rotH)
  146.   local sinV, cosV = math.sin(player.rotV), math.cos(player.rotV)
  147.  
  148.   for sx = 1, WIDTH do
  149.     local rayAngleH = player.rotH - FOV/2 + (sx / WIDTH) * FOV
  150.     local rayX, rayZ = math.sin(rayAngleH), math.cos(rayAngleH)
  151.    
  152.     for sy = 1, HEIGHT do
  153.       local rayAngleV = player.rotV - FOV/2 + (sy / HEIGHT) * FOV
  154.       local rayY, rayLen = math.sin(rayAngleV), math.cos(rayAngleV)
  155.      
  156.       local hitX, hitY, hitZ, dist = raycast(player.x, player.y, player.z, rayX * rayLen, rayY, rayZ * rayLen)
  157.      
  158.       if hitX then
  159.         local block = world[hitX][hitZ][hitY]
  160.         local color = dist < RENDER_DISTANCE / 3 and
  161.           (block == BLOCK_STONE and colors.STONE or
  162.            block == BLOCK_DIRT and colors.DIRT or
  163.            block == BLOCK_GRASS and colors.GRASS or
  164.            block == BLOCK_WOOD and colors.WOOD or
  165.            block == BLOCK_LEAVES and colors.LEAVES) or
  166.           (dist < RENDER_DISTANCE * 2 / 3 and colors.GRAY or colors.DARK_GRAY)
  167.         local char = (block == BLOCK_STONE) and "▓" or (block == BLOCK_DIRT) and "▒" or "█"
  168.         gpu.setForeground(color)
  169.         gpu.set(sx, sy, char)
  170.       end
  171.     end
  172.   end
  173.  
  174.   -- Draw UI
  175.   gpu.setForeground(colors.WHITE)
  176.   gpu.set(1, 1, string.format("X: %.2f Y: %.2f Z: %.2f Selected: %d", player.x, player.y, player.z, selected_slot))
  177.  
  178.   -- Draw inventory
  179.   local invText = "Inventory: "
  180.   for block, count in pairs(inventory) do
  181.     invText = invText .. string.format("%d:%d ", block, count)
  182.   end
  183.   gpu.set(1, HEIGHT, invText)
  184. end
  185.  
  186. -- Collision detection function
  187. local function checkCollision(x, y, z)
  188.   local minX, maxX = math.floor(x - PLAYER_WIDTH / 2), math.floor(x + PLAYER_WIDTH / 2)
  189.   local minY, maxY = math.floor(y - PLAYER_HEIGHT), math.floor(y)
  190.   local minZ, maxZ = math.floor(z - PLAYER_WIDTH / 2), math.floor(z + PLAYER_WIDTH / 2)
  191.  
  192.   for checkX = minX, maxX do
  193.     for checkY = minY, maxY do
  194.       for checkZ = minZ, maxZ do
  195.         if world[checkX] and world[checkX][checkZ] and world[checkX][checkZ][checkY] and world[checkX][checkZ][checkY] ~= BLOCK_AIR then
  196.           return true
  197.         end
  198.       end
  199.     end
  200.   end
  201.   return false
  202. end
  203.  
  204. -- Move player function
  205. local function movePlayer(dt)
  206.   local moveSpeed = 4 -- blocks per second
  207.   local dx, dz = 0, 0
  208.  
  209.   if playerMovement.forward then
  210.     dx = dx + math.sin(player.rotH) * moveSpeed * dt
  211.     dz = dz + math.cos(player.rotH) * moveSpeed * dt
  212.   end
  213.   if playerMovement.backward then
  214.     dx = dx - math.sin(player.rotH) * moveSpeed * dt
  215.     dz = dz - math.cos(player.rotH) * moveSpeed * dt
  216.   end
  217.   if playerMovement.left then
  218.     dx = dx - math.cos(player.rotH) * moveSpeed * dt
  219.     dz = dz + math.sin(player.rotH) * moveSpeed * dt
  220.   end
  221.   if playerMovement.right then
  222.     dx = dx + math.cos(player.rotH) * moveSpeed * dt
  223.     dz = dz - math.sin(player.rotH) * moveSpeed * dt
  224.   end
  225.  
  226.   local dy = player.vy * dt
  227.  
  228.   -- Apply movement with collision detection
  229.   if not checkCollision(player.x + dx, player.y, player.z) then
  230.     player.x = player.x + dx
  231.   end
  232.   if not checkCollision(player.x, player.y + dy, player.z) then
  233.     player.y = player.y + dy
  234.   else
  235.     player.vy = 0
  236.   end
  237.   if not checkCollision(player.x, player.y, player.z + dz) then
  238.     player.z = player.z + dz
  239.   end
  240.  
  241.   player.onGround = checkCollision(player.x, player.y - 0.1, player.z)
  242. end
  243.  
  244. -- Physics update
  245. local function updatePhysics(dt)
  246.   player.vy = player.vy + GRAVITY * dt
  247.   movePlayer(dt)
  248.  
  249.   if player.y < 1 + PLAYER_HEIGHT then
  250.     player.y = 1 + PLAYER_HEIGHT
  251.     player.vy = 0
  252.     player.onGround = true
  253.   end
  254. end
  255.  
  256. -- Main game loop
  257. local running = true
  258. local lastTime = computer.uptime()
  259. while running do
  260.   local currentTime = computer.uptime()
  261.   local dt = currentTime - lastTime
  262.   lastTime = currentTime
  263.  
  264.   updatePhysics(dt)
  265.   render()
  266.  
  267.   gpu.setActiveBuffer(0)
  268.   gpu.bitblt(0, 1, 1, WIDTH, HEIGHT, back_buffer, 1, 1)
  269.  
  270.   local e = {event.pull(0.05)}
  271.   if e[1] == "key_down" or e[1] == "key_up" then
  272.     local _, _, _, key, isDown = table.unpack(e)
  273.     isDown = e[1] == "key_down"
  274.     if key == 17 then playerMovement.forward = isDown
  275.     elseif key == 31 then playerMovement.backward = isDown
  276.     elseif key == 30 then playerMovement.left = isDown
  277.     elseif key == 32 then playerMovement.right = isDown
  278.     elseif key == 57 and isDown and player.onGround then player.vy, player.onGround = JUMP_STRENGTH, false
  279.     elseif key == 200 then player.rotV = math.min(player.rotV + 0.1, math.pi/2 - 0.1)
  280.     elseif key == 208 then player.rotV = math.max(player.rotV - 0.1, -math.pi/2 - 0.1)
  281.     elseif key == 203 then player.rotH = player.rotH - 0.1
  282.     elseif key == 205 then player.rotH = player.rotH + 0.1
  283.     elseif key == 28 and isDown then
  284.       local hitX, hitY, hitZ = raycast(player.x, player.y, player.z, math.sin(player.rotH), math.sin(player.rotV), math.cos(player.rotH))
  285.       if hitX and world[hitX] and world[hitX][hitZ] then
  286.         local block = world[hitX][hitZ][hitY]
  287.         world[hitX][hitZ][hitY] = BLOCK_AIR
  288.         inventory[block] = (inventory[block] or 0) + 1
  289.       end
  290.     elseif key == 46 and isDown then
  291.       local hitX, hitY, hitZ, dist = raycast(player.x, player.y, player.z, math.sin(player.rotH), math.sin(player.rotV), math.cos(player.rotH))
  292.       if hitX then
  293.         local px, py, pz = player.x + math.sin(player.rotH) * (dist - 0.5), player.y + math.sin(player.rotV) * (dist - 0.5), player.z + math.cos(player.rotH) * (dist - 0.5)
  294.         local bx, by, bz = math.floor(px), math.floor(py), math.floor(pz)
  295.         if world[bx] and world[bx][bz] and world[bx][bz][by] == BLOCK_AIR and inventory[selected_slot] > 0 then
  296.           world[bx][bz][by] = selected_slot
  297.           inventory[selected_slot] = inventory[selected_slot] - 1
  298.         end
  299.       end
  300.     elseif key >= 2 and key <= 6 and isDown then
  301.       selected_slot = key - 1
  302.     elseif key == 16 and isDown then
  303.       running = false
  304.     end
  305.   end
  306.  
  307.   local endTime = computer.uptime()
  308.   local frameTime = endTime - lastTime
  309.   local fps = 1 / frameTime
  310.   gpu.setForeground(colors.WHITE)
  311.   gpu.set(WIDTH - 20, 1, string.format("FPS: %.2f", fps))
  312. end
  313.  
  314. gpu.freeBuffer(back_buffer)
  315. term.clear()
  316. gpu.setForeground(colors.WHITE)
  317. gpu.setBackground(0x000000)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement