Advertisement
nonogamer9

3D tech demo game for opencomputers

Aug 5th, 2024 (edited)
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.27 KB | Gaming | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local keyboard = require("keyboard")
  4. local gpu = component.gpu
  5.  
  6. -- Set screen resolution to fit a Tier 3 GPU
  7. local width, height = 160, 50
  8. gpu.setResolution(width, height)
  9.  
  10. -- Create two buffers
  11. local frontBuffer = {}
  12. local backBuffer = {}
  13.  
  14. -- Initialize buffers
  15. for y = 1, height do
  16.     frontBuffer[y] = {}
  17.     backBuffer[y] = {}
  18.     for x = 1, width do
  19.         frontBuffer[y][x] = 0x000000
  20.         backBuffer[y][x] = 0x000000
  21.     end
  22. end
  23.  
  24. -- Function to clear the screen
  25. local function clearScreen()
  26.     gpu.setBackground(0x000000)
  27.     gpu.fill(1, 1, width, height, " ")
  28. end
  29.  
  30. -- Clear the screen before starting
  31. clearScreen()
  32.  
  33. -- Function to set a pixel in the back buffer
  34. local function setPixel(x, y, color)
  35.     if x >= 1 and x <= width and y >= 1 and y <= height then
  36.         backBuffer[y][x] = color
  37.     end
  38. end
  39.  
  40. -- Function to clear the back buffer
  41. local function clearBackBuffer()
  42.     for y = 1, height do
  43.         for x = 1, width do
  44.             backBuffer[y][x] = 0x000000
  45.         end
  46.     end
  47. end
  48.  
  49. -- Function to swap buffers and draw to screen efficiently
  50. local function swapBuffers()
  51.     local changes = {}
  52.     for y = 1, height do
  53.         for x = 1, width do
  54.             if frontBuffer[y][x] ~= backBuffer[y][x] then
  55.                 table.insert(changes, {x = x, y = y, color = backBuffer[y][x]})
  56.                 frontBuffer[y][x] = backBuffer[y][x]
  57.             end
  58.         end
  59.     end
  60.    
  61.     -- Sort changes by color to minimize GPU calls
  62.     table.sort(changes, function(a, b) return a.color < b.color end)
  63.    
  64.     local currentColor = nil
  65.     for _, change in ipairs(changes) do
  66.         if currentColor ~= change.color then
  67.             gpu.setBackground(change.color)
  68.             currentColor = change.color
  69.         end
  70.         gpu.set(change.x, change.y, " ")
  71.     end
  72. end
  73.  
  74. -- Maze generation using Recursive Division
  75. local function generateMaze(width, height)
  76.     local maze = {}
  77.     for y = 1, height do
  78.         maze[y] = {}
  79.         for x = 1, width do
  80.             maze[y][x] = 1
  81.         end
  82.     end
  83.  
  84.     local function carve(x, y)
  85.         local directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
  86.         for i = #directions, 2, -1 do
  87.             local j = math.random(i)
  88.             directions[i], directions[j] = directions[j], directions[i]
  89.         end
  90.         for _, dir in ipairs(directions) do
  91.             local nx, ny = x + dir[1] * 2, y + dir[2] * 2
  92.             if nx > 0 and nx <= width and ny > 0 and ny <= height and maze[ny][nx] == 1 then
  93.                 maze[ny][nx] = 0
  94.                 maze[y + dir[2]][x + dir[1]] = 0
  95.                 carve(nx, ny)
  96.             end
  97.         end
  98.     end
  99.  
  100.     maze[2][2] = 0
  101.     carve(2, 2)
  102.     return maze
  103. end
  104.  
  105. local map = generateMaze(15, 15)
  106.  
  107. local player = {
  108.     x = 2.5,
  109.     y = 2.5,
  110.     angle = 0
  111. }
  112.  
  113. local enemies = {}
  114. local bullets = {}
  115. local enemyBullets = {}
  116.  
  117. -- New function to spawn enemies randomly
  118. local MAX_ENEMIES = 10
  119. local function spawnEnemy()
  120.     if #enemies < MAX_ENEMIES then
  121.         local x = math.random(1, #map[1])
  122.         local y = math.random(1, #map)
  123.        
  124.         -- Ensure the enemy doesn't spawn inside a wall
  125.         while map[y][x] == 1 do
  126.             x = math.random(1, #map[1])
  127.             y = math.random(1, #map)
  128.         end
  129.        
  130.         table.insert(enemies, {x = x + 0.5, y = y + 0.5})
  131.     end
  132. end
  133.  
  134. local function draw()
  135.     clearBackBuffer()
  136.  
  137.     -- Draw walls
  138.     for x = 1, width do
  139.         local cameraX = 2 * x / width - 1
  140.         local rayDirX = math.cos(player.angle) + cameraX * math.sin(player.angle)
  141.         local rayDirY = math.sin(player.angle) - cameraX * math.cos(player.angle)
  142.  
  143.         local mapX, mapY = math.floor(player.x), math.floor(player.y)
  144.         local sideDistX, sideDistY
  145.         local deltaDistX, deltaDistY = math.abs(1 / rayDirX), math.abs(1 / rayDirY)
  146.         local perpWallDist
  147.         local stepX, stepY
  148.         local hit, side = 0, 0
  149.  
  150.         if rayDirX < 0 then stepX, sideDistX = -1, (player.x - mapX) * deltaDistX
  151.         else stepX, sideDistX = 1, (mapX + 1 - player.x) * deltaDistX end
  152.         if rayDirY < 0 then stepY, sideDistY = -1, (player.y - mapY) * deltaDistY
  153.         else stepY, sideDistY = 1, (mapY + 1 - player.y) * deltaDistY end
  154.  
  155.         while hit == 0 do
  156.             if sideDistX < sideDistY then
  157.                 sideDistX, mapX, side = sideDistX + deltaDistX, mapX + stepX, 0
  158.             else
  159.                 sideDistY, mapY, side = sideDistY + deltaDistY, mapY + stepY, 1
  160.             end
  161.             if map[mapY] and map[mapY][mapX] and map[mapY][mapX] > 0 then hit = 1 end
  162.         end
  163.  
  164.         if side == 0 then perpWallDist = (mapX - player.x + (1 - stepX) / 2) / rayDirX
  165.         else perpWallDist = (mapY - player.y + (1 - stepY) / 2) / rayDirY end
  166.  
  167.         local lineHeight = math.floor(height / perpWallDist)
  168.         local drawStart = math.max(1, -lineHeight / 2 + height / 2)
  169.         local drawEnd = math.min(height, lineHeight / 2 + height / 2)
  170.  
  171.         local color = side == 1 and 0xAAAAAA or 0xFFFFFF
  172.         for y = math.ceil(drawStart), math.floor(drawEnd) do
  173.             setPixel(x, y, color)
  174.         end
  175.     end
  176.  
  177.     -- Draw enemies
  178.     for _, enemy in ipairs(enemies) do
  179.         local enemyX, enemyY = enemy.x, enemy.y
  180.         local distX, distY = enemyX - player.x, enemyY - player.y
  181.         local distance = math.sqrt(distX * distX + distY * distY)
  182.         local enemyAngle = math.atan2(distY, distX) - player.angle
  183.         local screenX = math.floor((width / 2) * (1 + math.tan(enemyAngle)))
  184.         local enemyHeight = math.floor(height / distance)
  185.         local drawStartY = math.max(1, height / 2 - enemyHeight / 2)
  186.         local drawEndY = math.min(height, height / 2 + enemyHeight / 2)
  187.  
  188.         for y = drawStartY, drawEndY do
  189.             setPixel(screenX, y, 0x00FF00)
  190.         end
  191.     end
  192.  
  193.     -- Draw bullets
  194.     for _, bullet in ipairs(bullets) do
  195.         local bulletX, bulletY = bullet.x, bullet.y
  196.         local distX, distY = bulletX - player.x, bulletY - player.y
  197.         local distance = math.sqrt(distX * distX + distY * distY)
  198.         local bulletAngle = math.atan2(distY, distX) - player.angle
  199.         local screenX = math.floor((width / 2) * (1 + math.tan(bulletAngle)))
  200.         local bulletHeight = math.floor(height / distance)
  201.         local drawStartY = math.max(1, height / 2 - bulletHeight / 2)
  202.         local drawEndY = math.min(height, height / 2 + bulletHeight / 2)
  203.  
  204.         for y = drawStartY, drawEndY do
  205.             setPixel(screenX, y, 0xFF0000)
  206.         end
  207.     end
  208.  
  209.     -- Draw enemy bullets
  210.     for _, bullet in ipairs(enemyBullets) do
  211.         local bulletX, bulletY = bullet.x, bullet.y
  212.         local distX, distY = bulletX - player.x, bulletY - player.y
  213.         local distance = math.sqrt(distX * distX + distY * distY)
  214.         local bulletAngle = math.atan2(distY, distX) - player.angle
  215.         local screenX = math.floor((width / 2) * (1 + math.tan(bulletAngle)))
  216.         local bulletHeight = math.floor(height / distance)
  217.         local drawStartY = math.max(1, height / 2 - bulletHeight / 2)
  218.         local drawEndY = math.min(height, height / 2 + bulletHeight / 2)
  219.  
  220.         for y = drawStartY, drawEndY do
  221.             setPixel(screenX, y, 0xFFFF00)
  222.         end
  223.     end
  224.  
  225.     swapBuffers()
  226. end
  227.  
  228. local function updateBullets()
  229.     for i = #bullets, 1, -1 do
  230.         local bullet = bullets[i]
  231.         bullet.x = bullet.x + math.cos(bullet.angle) * 0.5
  232.         bullet.y = bullet.y + math.sin(bullet.angle) * 0.5
  233.  
  234.         -- Check for collisions with walls
  235.         local mapX, mapY = math.floor(bullet.x), math.floor(bullet.y)
  236.         if map[mapY] and map[mapY][mapX] and map[mapY][mapX] > 0 then
  237.             table.remove(bullets, i)
  238.         else
  239.             -- Check for collisions with enemies
  240.             for j = #enemies, 1, -1 do
  241.                 local enemy = enemies[j]
  242.                 if math.abs(bullet.x - enemy.x) < 0.5 and math.abs(bullet.y - enemy.y) < 0.5 then
  243.                     table.remove(enemies, j)
  244.                     table.remove(bullets, i)
  245.                     break
  246.                 end
  247.             end
  248.         end
  249.  
  250.         -- Remove bullets that are out of bounds
  251.         if bullet.x < 1 or bullet.x > #map[1] or bullet.y < 1 or bullet.y > #map then
  252.             table.remove(bullets, i)
  253.         end
  254.     end
  255. end
  256.  
  257. local function updateEnemyBullets()
  258.     for i = #enemyBullets, 1, -1 do
  259.         local bullet = enemyBullets[i]
  260.         bullet.x = bullet.x + math.cos(bullet.angle) * 0.5
  261.         bullet.y = bullet.y + math.sin(bullet.angle) * 0.5
  262.  
  263.         if math.abs(bullet.x - player.x) < 0.5 and math.abs(bullet.y - player.y) < 0.5 then
  264.             print("You died!")
  265.             return true
  266.         end
  267.  
  268.         -- Remove bullets that are out of bounds
  269.         if bullet.x < 1 or bullet.x > #map[1] or bullet.y < 1 or bullet.y > #map then
  270.             table.remove(enemyBullets, i)
  271.         end
  272.     end
  273.     return false
  274. end
  275.  
  276. local function fireBullet()
  277.     if #bullets < 20 then
  278.         table.insert(bullets, {x = player.x, y = player.y, angle = player.angle})
  279.     end
  280. end
  281.  
  282. local function update()
  283.     local moveSpeed = 0.05
  284.     local rotSpeed = 0.03
  285.     local keys = {}
  286.     local spawnTimer = 0
  287.     local spawnInterval = 5  -- Spawn an enemy every 5 seconds on average
  288.  
  289.     while true do
  290.         local e = {event.pull(0.05)} -- Poll events with a small timeout
  291.         if e[1] == "key_down" then
  292.             keys[e[4]] = true
  293.         elseif e[1] == "key_up" then
  294.             keys[e[4]] = nil
  295.         end
  296.  
  297.         if keys[keyboard.keys.w] then
  298.             player.x = player.x + math.cos(player.angle) * moveSpeed
  299.             player.y = player.y + math.sin(player.angle) * moveSpeed
  300.         end
  301.         if keys[keyboard.keys.s] then
  302.             player.x = player.x - math.cos(player.angle) * moveSpeed
  303.             player.y = player.y - math.sin(player.angle) * moveSpeed
  304.         end
  305.         if keys[keyboard.keys.a] then
  306.             player.angle = player.angle - rotSpeed
  307.         end
  308.         if keys[keyboard.keys.d] then
  309.             player.angle = player.angle + rotSpeed
  310.         end
  311.         if keys[keyboard.keys.space] then
  312.             fireBullet()
  313.         end
  314.         if keys[keyboard.keys.q] then
  315.             return
  316.         end
  317.  
  318.         -- Enemy spawning
  319.         spawnTimer = spawnTimer + 0.05
  320.         if spawnTimer >= spawnInterval then
  321.             if math.random() < 0.2 then  -- 20% chance to spawn an enemy
  322.                 spawnEnemy()
  323.             end
  324.             spawnTimer = 0
  325.         end
  326.  
  327.         updateBullets()
  328.  
  329.         if updateEnemyBullets() then
  330.             return
  331.         end
  332.  
  333.         -- Update enemies
  334.         for _, enemy in ipairs(enemies) do
  335.             local dx = player.x - enemy.x
  336.             local dy = player.y - enemy.y
  337.             local distance = math.sqrt(dx * dx + dy * dy)
  338.  
  339.             if distance > 0.5 then
  340.                 enemy.x = enemy.x + dx / distance * moveSpeed / 2
  341.                 enemy.y = enemy.y + dy / distance * moveSpeed / 2
  342.             else
  343.                 table.insert(enemyBullets, {x = enemy.x, y = enemy.y, angle = math.atan2(dy, dx)})
  344.             end
  345.         end
  346.  
  347.         draw()
  348.     end
  349. end
  350.  
  351. gpu.setResolution(width, height)
  352. draw()
  353. update()
  354.  
Tags: lua
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement