mirror of
https://github.com/IgorTimofeev/MineOS.git
synced 2025-12-20 19:19:21 +01:00
793 lines
46 KiB
Lua
Executable File
793 lines
46 KiB
Lua
Executable File
local text = require("Text")
|
||
local number = require("Number")
|
||
local color = require("Color")
|
||
local image = require("Image")
|
||
local screen = require("Screen")
|
||
local GUI = require("GUI")
|
||
local event = require("Event")
|
||
local filesystem = require("Filesystem")
|
||
|
||
---------------------------------------------------- Управление -----------------------------------------------------------------
|
||
|
||
local inputX = 0
|
||
local inputY = 0
|
||
local inputYaw = 0
|
||
local holdingFire = 0
|
||
|
||
---------------------------------------------------- Переменные ------------------------------------------------------------------
|
||
local startRenderClock = os.clock()
|
||
local endRenderClock = os.clock()
|
||
local frameCount = 0
|
||
local fps = 0
|
||
local lastFPSCheck = os.clock()
|
||
---------------------------------------------------- Константы ------------------------------------------------------------------
|
||
|
||
local rayEngine = {}
|
||
|
||
rayEngine.debugInformationEnabled = true
|
||
rayEngine.minimapEnabled = true
|
||
rayEngine.compassEnabled = false
|
||
rayEngine.watchEnabled = false
|
||
rayEngine.drawFieldOfViewOnMinimap = false
|
||
rayEngine.chatShowTime = 4
|
||
rayEngine.chatHistory = {}
|
||
rayEngine.sprites = {}
|
||
---------------------------------------------- Расчетные функции ------------------------------------------------------------------
|
||
|
||
-- Позиция горизонта, относительно которой рисуется мир
|
||
function rayEngine.calculateHorizonPosition()
|
||
rayEngine.horizonPosition = math.floor(screen.getHeight() / 2)
|
||
end
|
||
|
||
-- Размер панели чата и лимита его истории
|
||
function rayEngine.calculateChatSize()
|
||
rayEngine.chatPanelWidth, rayEngine.chatPanelHeight = math.floor(screen.getWidth() * 0.4), math.floor(screen.getHeight() * 0.4)
|
||
rayEngine.chatHistoryLimit = rayEngine.chatPanelHeight
|
||
end
|
||
|
||
-- Шаг, с которым будет изменяться угол рейкаста
|
||
function rayEngine.calculateRaycastStep()
|
||
rayEngine.raycastStep = rayEngine.player.fieldOfView / screen.getWidth()
|
||
end
|
||
|
||
-- Позиция оружия на экране и всех его вспомогательных текстур
|
||
function rayEngine.calculateWeaponPosition()
|
||
rayEngine.currentWeapon.xWeapon = screen.getWidth() - rayEngine.currentWeapon.weaponTexture[1] + 1
|
||
rayEngine.currentWeapon.yWeapon = screen.getHeight() - rayEngine.currentWeapon.weaponTexture[2] + 1
|
||
rayEngine.currentWeapon.xFire = rayEngine.currentWeapon.xWeapon + rayEngine.weapons[rayEngine.currentWeapon.ID].firePosition.x
|
||
rayEngine.currentWeapon.yFire = rayEngine.currentWeapon.yWeapon + rayEngine.weapons[rayEngine.currentWeapon.ID].firePosition.y
|
||
rayEngine.currentWeapon.xCrosshair = math.floor(screen.getWidth() / 2 - rayEngine.currentWeapon.crosshairTexture[1] / 2)
|
||
rayEngine.currentWeapon.yCrosshair = math.floor(screen.getHeight() / 2 - rayEngine.currentWeapon.crosshairTexture[2] / 2)
|
||
end
|
||
|
||
-- Грубо говоря, это расстояние от камеры до виртуального экрана, на котором рисуется весь наш мир, влияет на размер блоков
|
||
function rayEngine.calculateDistanceToProjectionPlane()
|
||
rayEngine.distanceToProjectionPlane = (screen.getWidth() / 2) / math.tan(math.rad((rayEngine.player.fieldOfView / 2)))
|
||
end
|
||
|
||
-- Быстрый перерасчет всего, что нужно
|
||
function rayEngine.calculateAllParameters()
|
||
rayEngine.calculateHorizonPosition()
|
||
rayEngine.calculateChatSize()
|
||
rayEngine.calculateRaycastStep()
|
||
rayEngine.calculateDistanceToProjectionPlane()
|
||
if rayEngine.currentWeapon then rayEngine.calculateWeaponPosition() end
|
||
end
|
||
|
||
---------------------------------------------- Вспомогательные функции ------------------------------------------------------------------
|
||
|
||
local function constrainAngle(value)
|
||
value = value % 360
|
||
return value
|
||
end
|
||
|
||
|
||
local function constrain180(value)
|
||
value = (value + 180) % 360 - 180
|
||
return value
|
||
end
|
||
|
||
local function getSkyColorByTime()
|
||
return rayEngine.world.colors.sky[rayEngine.world.dayNightCycle.currentTime > 0 and math.ceil(rayEngine.world.dayNightCycle.currentTime / rayEngine.world.dayNightCycle.length * #rayEngine.world.colors.sky) or 1]
|
||
end
|
||
|
||
local function getBrightnessByTime()
|
||
return rayEngine.properties.shadingTransparencyMap[rayEngine.world.dayNightCycle.currentTime > 0 and math.ceil(rayEngine.world.dayNightCycle.currentTime / rayEngine.world.dayNightCycle.length * #rayEngine.properties.shadingTransparencyMap) or 1]
|
||
end
|
||
|
||
local function getTileColor(basecolor, distance)
|
||
local limitedDistance = math.floor(distance * rayEngine.properties.shadingCascades / rayEngine.properties.shadingDistance)
|
||
local transparency = rayEngine.currentShadingTransparencyMapValue - limitedDistance / rayEngine.properties.shadingCascades
|
||
transparency = (transparency >= rayEngine.properties.shadingTransparencyMap[1] and transparency <= 1) and transparency or rayEngine.properties.shadingTransparencyMap[1]
|
||
return color.blend(basecolor, 0x000000, transparency)
|
||
end
|
||
|
||
function rayEngine.refreshTimeDependentColors()
|
||
rayEngine.world.colors.sky.current = getSkyColorByTime()
|
||
rayEngine.currentShadingTransparencyMapValue = getBrightnessByTime()
|
||
rayEngine.world.colors.groundByTime = color.blend(rayEngine.world.colors.ground, 0x000000, rayEngine.currentShadingTransparencyMapValue)
|
||
end
|
||
|
||
local function doDayNightCycle()
|
||
if rayEngine.world.dayNightCycle.enabled then
|
||
local computerUptime = computer.uptime()
|
||
if (computerUptime - rayEngine.world.dayNightCycle.lastComputerUptime) >= rayEngine.world.dayNightCycle.speed then
|
||
rayEngine.world.dayNightCycle.currentTime = rayEngine.world.dayNightCycle.currentTime + rayEngine.world.dayNightCycle.speed
|
||
if rayEngine.world.dayNightCycle.currentTime > rayEngine.world.dayNightCycle.length then rayEngine.world.dayNightCycle.currentTime = 0 end
|
||
rayEngine.world.dayNightCycle.lastComputerUptime = computerUptime
|
||
|
||
rayEngine.refreshTimeDependentColors()
|
||
end
|
||
end
|
||
end
|
||
|
||
local function convertWorldCoordsToMapCoords(x, y)
|
||
return number.round(x / rayEngine.properties.tileWidth), number.round(y / rayEngine.properties.tileWidth)
|
||
end
|
||
|
||
local function getBlockCoordsByLook(distance)
|
||
local radRotation = math.rad(rayEngine.player.rotation)
|
||
return convertWorldCoordsToMapCoords(rayEngine.player.position.x + distance * math.sin(radRotation) * rayEngine.properties.tileWidth, rayEngine.player.position.y + distance * math.cos(radRotation) * rayEngine.properties.tileWidth)
|
||
end
|
||
|
||
---------------------------------------------------- Работа с файлами ------------------------------------------------------------------
|
||
|
||
-- Загрузка параметров движка
|
||
function rayEngine.loadEngineProperties(pathToRayEnginePropertiesFile)
|
||
rayEngine.properties = filesystem.readTable(pathToRayEnginePropertiesFile)
|
||
end
|
||
|
||
-- Загрузка конифгурации оружия
|
||
function rayEngine.loadWeapons(pathToWeaponsFolder)
|
||
rayEngine.weaponsFolder = pathToWeaponsFolder
|
||
rayEngine.weapons = filesystem.readTable(rayEngine.weaponsFolder .. "Weapons.cfg")
|
||
rayEngine.changeWeapon(1)
|
||
end
|
||
|
||
-- Загрузка конкретного мира
|
||
function rayEngine.loadWorld(pathToWorldFolder)
|
||
rayEngine.world = filesystem.readTable(pathToWorldFolder .. "/World.cfg")
|
||
rayEngine.map = filesystem.readTable(pathToWorldFolder .. "/Map.cfg")
|
||
rayEngine.player = filesystem.readTable(pathToWorldFolder .. "/Player.cfg")
|
||
rayEngine.blocks = filesystem.readTable(pathToWorldFolder .. "/Blocks.cfg")
|
||
rayEngine.entities = filesystem.readTable(pathToWorldFolder .. "/Entities.cfg")
|
||
-- Дополняем карту ее размерами
|
||
rayEngine.map.width = #rayEngine.map[1]
|
||
rayEngine.map.height = #rayEngine.map
|
||
-- Создаём карту блоков для коллизий
|
||
rayEngine.hitBlocks = {}
|
||
for i = 1,rayEngine.map.width do
|
||
line={}
|
||
rayEngine.hitBlocks[i] = {}
|
||
for j =1,rayEngine.map.height do
|
||
rayEngine.hitBlocks[i][j] = {}
|
||
end
|
||
end
|
||
|
||
for i =1,#rayEngine.entities do
|
||
for dx = -1,1 do
|
||
for dy = -1,1 do
|
||
mapX = math.floor((rayEngine.entities[i].x + rayEngine.entities[i].w * dx) / rayEngine.properties.tileWidth)
|
||
mapY = math.floor((rayEngine.entities[i].y+rayEngine.entities[i].w * dy) / rayEngine.properties.tileWidth)
|
||
|
||
if rayEngine.hitBlocks[mapX] and rayEngine.hitBlocks[mapX][mapY] then
|
||
cellCount = #rayEngine.hitBlocks[mapX][mapY]
|
||
|
||
rayEngine.hitBlocks[mapX][mapY][cellCount + 1] = i
|
||
end
|
||
end
|
||
end
|
||
end
|
||
-- Ебашим правильную позицию игрока, основанную на этой ХУЙНЕ, которую ГЛЕБ так ЛЮБИТ
|
||
rayEngine.player.position.x = rayEngine.properties.tileWidth * rayEngine.player.position.x - rayEngine.properties.tileWidth / 2
|
||
rayEngine.player.position.y = rayEngine.properties.tileWidth * rayEngine.player.position.y - rayEngine.properties.tileWidth / 2
|
||
-- Рассчитываем цвета, зависимые от времени - небо, землю, стены
|
||
rayEngine.refreshTimeDependentColors()
|
||
-- Обнуляем текущее время, если превышен лимит, а то мало ли какой пидорас начнет править конфиги мира
|
||
rayEngine.world.dayNightCycle.currentTime = rayEngine.world.dayNightCycle.currentTime > rayEngine.world.dayNightCycle.length and 0 or rayEngine.world.dayNightCycle.currentTime
|
||
-- Осуществляем базовое получение аптайма пекарни
|
||
rayEngine.world.dayNightCycle.lastComputerUptime = computer.uptime()
|
||
-- Рассчитываем необходимые параметры движка
|
||
rayEngine.calculateAllParameters()
|
||
|
||
-- rayEngine.wallsTexture = image.load("/heart.pic")
|
||
-- rayEngine.wallsTexture = image.transform(rayEngine.wallsTexture, rayEngine.properties.tileWidth, rayEngine.properties.tileWidth / 2)
|
||
end
|
||
|
||
---------------------------------------------------- Функции, связанные с игроком ------------------------------------------------------------------
|
||
|
||
function rayEngine.changeWeapon(weaponID)
|
||
if rayEngine.weapons[weaponID] then
|
||
rayEngine.currentWeapon = {
|
||
ID = weaponID,
|
||
damage = rayEngine.weapons[weaponID].damage,
|
||
weaponTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].weaponTexture),
|
||
fireTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].fireTexture),
|
||
crosshairTexture = image.load(rayEngine.weaponsFolder .. rayEngine.weapons[weaponID].crosshairTexture),
|
||
fireTime = rayEngine.weapons[weaponID].fireTime,
|
||
isAuto = rayEngine.weapons[weaponID].isAuto,
|
||
needToFire = 0
|
||
}
|
||
rayEngine.calculateWeaponPosition()
|
||
else
|
||
rayEngine.currentWeapon = nil
|
||
end
|
||
end
|
||
|
||
function rayEngine.loadSprites(pathToSprites)
|
||
fileList = filesystem.readTable(pathToSprites .. "Sprites.cfg")
|
||
for i = 1,#fileList do
|
||
rayEngine.sprites[i] = image.load(pathToSprites .. fileList[i])
|
||
|
||
end
|
||
end
|
||
|
||
function rayEngine.move(distanceForward, distanceRight)
|
||
local forwardRotation = math.rad(rayEngine.player.rotation)
|
||
local rightRotation = math.rad(rayEngine.player.rotation + 90)
|
||
local xNew = rayEngine.player.position.x + distanceForward * math.sin(forwardRotation) + distanceRight * math.sin(rightRotation)
|
||
local yNew = rayEngine.player.position.y + distanceForward * math.cos(forwardRotation) + distanceRight * math.cos(rightRotation)
|
||
|
||
local xWorld, yWorld = convertWorldCoordsToMapCoords(xNew, yNew)
|
||
if rayEngine.map[yWorld][xWorld] == nil then
|
||
rayEngine.player.position.x, rayEngine.player.position.y = xNew, yNew
|
||
end
|
||
end
|
||
|
||
function rayEngine.rotate(angle)
|
||
rayEngine.player.rotation = constrainAngle(rayEngine.player.rotation + angle)
|
||
end
|
||
|
||
----------------- Начинаем поворачиааться ------------------------
|
||
function rayEngine.turnRight()
|
||
inputYaw = 1
|
||
--rayEngine.rotate(rayEngine.player.rotationSpeed)
|
||
end
|
||
|
||
function rayEngine.turnLeft()
|
||
inputYaw = -1
|
||
--rayEngine.rotate(-rayEngine.player.rotationSpeed)
|
||
end
|
||
|
||
----------------------- Начинаем идти -------------------------
|
||
function rayEngine.moveForward()
|
||
inputY = 1
|
||
--rayEngine.move(rayEngine.player.moveSpeed, 0)
|
||
end
|
||
|
||
function rayEngine.moveBackward()
|
||
inputY = -1
|
||
--rayEngine.move(-rayEngine.player.moveSpeed, 0)
|
||
end
|
||
|
||
function rayEngine.moveLeft()
|
||
inputX = -1
|
||
--rayEngine.move(0, -rayEngine.player.moveSpeed)
|
||
end
|
||
|
||
function rayEngine.moveRight()
|
||
inputX = 1
|
||
--rayEngine.move(0, rayEngine.player.moveSpeed)
|
||
end
|
||
|
||
--------------- Стоп --------------------------------------
|
||
|
||
|
||
function rayEngine.stopYaw()
|
||
inputYaw = 0
|
||
end
|
||
|
||
function rayEngine.stopY()
|
||
inputY = 0
|
||
end
|
||
|
||
function rayEngine.stopX()
|
||
inputX = 0
|
||
end
|
||
|
||
function rayEngine.jump()
|
||
if not rayEngine.player.jumpTimer then
|
||
local function onJumpFinished()
|
||
rayEngine.horizonPosition = rayEngine.horizonPosition - rayEngine.player.jumpHeight;
|
||
rayEngine.horizonPosition = rayEngine.horizonPosition - rayEngine.player.jumpHeight;
|
||
rayEngine.player.jumpTimer = nil
|
||
end
|
||
|
||
rayEngine.player.jumpTimer = event.timer(1, onJumpFinished)
|
||
rayEngine.horizonPosition = rayEngine.horizonPosition + rayEngine.player.jumpHeight
|
||
rayEngine.horizonPosition = rayEngine.horizonPosition + rayEngine.player.jumpHeight
|
||
end
|
||
end
|
||
|
||
function rayEngine.crouch()
|
||
rayEngine.player.isCrouched = not rayEngine.player.isCrouched
|
||
local heightAdder = rayEngine.player.isCrouched and -rayEngine.player.crouchHeight or rayEngine.player.crouchHeight
|
||
rayEngine.horizonPosition = rayEngine.horizonPosition + heightAdder
|
||
rayEngine.horizonPosition = rayEngine.horizonPosition + heightAdder
|
||
end
|
||
|
||
function rayEngine.destroy(distance)
|
||
local xBlock, yBlock = getBlockCoordsByLook(distance)
|
||
if rayEngine.map[yBlock] and rayEngine.map[yBlock][xBlock] and rayEngine.blocks[rayEngine.map[yBlock][xBlock]] and rayEngine.blocks[rayEngine.map[yBlock][xBlock]].canBeDestroyed then rayEngine.map[yBlock][xBlock] = nil end
|
||
end
|
||
|
||
function rayEngine.place(distance, blockColor)
|
||
local xBlock, yBlock = getBlockCoordsByLook(distance)
|
||
if rayEngine.map[yBlock] and rayEngine.map[yBlock][xBlock] == nil then rayEngine.map[yBlock][xBlock] = blockColor end
|
||
end
|
||
|
||
---------------------------------------------------- Функции интерфейса ------------------------------------------------------------------
|
||
|
||
function rayEngine.drawDebugInformation(x, y, width, transparency, ...)
|
||
local lines = {...}
|
||
screen.drawRectangle(x, y, width, #lines, 0x000000, 0x000000, " ", transparency); x = x + 1
|
||
for line = 1, #lines do screen.drawText(x, y, 0xEEEEEE, lines[line]); y = y + 1 end
|
||
end
|
||
|
||
local function drawFieldOfViewAngle(x, y, distance, color)
|
||
local fieldOfViewHalf = rayEngine.player.fieldOfView / 2
|
||
local firstAngle, secondAngle = math.rad(-(rayEngine.player.rotation - fieldOfViewHalf)), math.rad(-(rayEngine.player.rotation + fieldOfViewHalf))
|
||
local xFirst, yFirst = math.floor(x + math.sin(firstAngle) * distance), math.floor(y + math.cos(firstAngle) * distance)
|
||
local xSecond, ySecond = math.floor(x + math.sin(secondAngle) * distance), math.floor(y + math.cos(secondAngle) * distance)
|
||
screen.drawSemiPixelLine(x, y, xFirst, yFirst, color)
|
||
screen.drawSemiPixelLine(x, y, xSecond, ySecond, color)
|
||
end
|
||
|
||
function rayEngine.drawMap(x, y, width, height, transparency)
|
||
local xHalf, yHalf = math.floor(width / 2), math.floor(height / 2)
|
||
local xMap, yMap = convertWorldCoordsToMapCoords(rayEngine.player.position.x, rayEngine.player.position.y)
|
||
|
||
screen.drawRectangle(x, y, width, yHalf, 0x000000, 0x000000, " ", transparency)
|
||
|
||
local xPos, yPos = x, y * 2 - 1
|
||
for i = yMap - yHalf + 1, yMap + yHalf do
|
||
for j = xMap + xHalf + 1, xMap - xHalf + 2, -1 do
|
||
if rayEngine.map[i] and rayEngine.map[i][j] then
|
||
screen.semiPixelSet(xPos, yPos, rayEngine.blocks[rayEngine.map[i][j]].color)
|
||
end
|
||
|
||
if rayEngine.hitBlocks[i + 1] and rayEngine.hitBlocks[i+1][j+1] then
|
||
entities = rayEngine.hitBlocks[i + 1][j + 1]
|
||
for entityID= 1,#entities do
|
||
entity = rayEngine.entities[entityID]
|
||
scale = rayEngine.properties.tileWidth
|
||
screen.semiPixelSet(entity.x//scale - xMap + x, entity.y*2//scale - yMap + y, 0x00FFFF)
|
||
end
|
||
end
|
||
xPos = xPos + 1
|
||
end
|
||
xPos = x; yPos = yPos + 1
|
||
end
|
||
|
||
local xPlayer, yPlayer = x + xHalf, y + yHalf
|
||
--Поле зрения
|
||
if rayEngine.drawFieldOfViewOnMinimap then drawFieldOfViewAngle(xPlayer, yPlayer, 5, 0xCCFFBF) end
|
||
--Игрок
|
||
screen.semiPixelSet(xPlayer, yPlayer, 0x66FF40)
|
||
end
|
||
|
||
function rayEngine.intro()
|
||
local logo = image.fromString("17060000FF 0000FF 0000FF 0000FF 007EFF▄007EFF▄007EFF▄007EFF▀007EFF▀007EFF▀007EFF▀007EFF▀007EFF▀007EFF▀007EFF▄007EFF▄007EFF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 007EFF▄007EFF▀007EFF▀0000FF 0000FF 0000FF 0000FF 0053FF▄0053FF▀0053FF▀0053FF▀0053FF▄0000FF 0000FF 0000FF 0000FF 007EFF▀007EFF▀007EFF▄0000FF 0000FF 0000FF 007EFF▀007EFF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 530000 0000FF 0078FF▀0000FF 537800▀0078FF▀0078FF▀0078FF▀0078FF▀0078FF▀0078FF▀7E7800▀0078FF▀0000FF 0078FF▀0000FF 0000FF 007EFF▀007EFF▀007EFF▄007EFF▄007EFF▄0000FF 0000FF 0053FF▀0053FF▀0053FF▀0000FF 0000FF 007EFF▄007EFF▄007EFF▄007EFF▀007EFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 007EFF▀007EFF▀007EFF▀007EFF▀007EFF▀007EFF▀007EFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 007EFFP007EFFo007EFFw007EFFe007EFFr007EFFe007EFFd0000FF 007EFFb007EFFy0000FF 007EFFR007EFFa007EFFy007EFFE007EFFn007EFFg007EFFi007EFFn007EFFe007EFF™0000FF 0000FF ")
|
||
local x, y = math.floor(screen.getWidth() / 2 - logo[1] / 2), math.floor(screen.getHeight() / 2 - logo[2] / 2)
|
||
local function draw(transparency)
|
||
screen.clear(0xF0F0F0);
|
||
screen.drawImage(x, y, logo)
|
||
screen.drawRectangle(1, 1, screen.getWidth(), screen.getHeight(), 0x000000, 0x000000, " ", transparency)
|
||
screen.update()
|
||
event.sleep(0)
|
||
end
|
||
for i = 0, 100, 20 do draw(i) end
|
||
event.sleep(1.5)
|
||
for i = 100, 0, -20 do draw(i) end
|
||
end
|
||
|
||
function rayEngine.compass(x, y)
|
||
if not rayEngine.compassImage then rayEngine.compassImage = image.fromString("1C190000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 553600▄373100▄543600▄373600▄543600▄373100▄540000 375400▄673700▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0055FF▄675400▄553700▄375500▄550000 375500▄540000 375400▄540000 373600▄310000 675500▄677E00▄375300▄365400▄373600▄540000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 555400▄553700▄540000 543700▄540000 375300▄533100▄310B00▄310000 310000 360000 543100▄375300▄553100▄533600▄543200▄313600▄372A00▄373100▄0054FF▄0054FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 540000 543200▄540000 545300▄540600▄063100▄310000 315400▄365400▄373100▄313600▄530000 0000FF 0000FF 535400▄535400▄540000 365300▄533100▄065300▄310000 530600▄0054FF▄0000FF 0000FF 0000FF 0000FF 0000FF 530000 365300▄543600▄310600▄312A00▄2A5300▄365300▄543600▄540000 365300▄315300▄530000 0000FF 0000FF 535400▄540000 540000 313600▄363100▄540000 313600▄315300▄062A00▄543100▄0000FF 0000FF 0000FF 0000FF 315300▄533600▄312A00▄2A3100▄315300▄533600▄315400▄540000 535400▄540000 530000 533100▄0000FF 0000FF 540000 540000 315400▄540000 543100▄530000 543100▄313600▄2A0000 2A2900▄540000 0000FF 0000FF 0000FF 533100▄315400▄530000 062A00▄533100▄315300▄535400▄533100▄540000 315400▄543100▄530000 0000FF 0000FF 540000 535400▄315300▄535400▄363100▄535400▄530000 530000 312A00▄2A5300▄0054FF▀0000FF 0000FF 0000FF 312A00▄530000 553600▄2A5500▄2A0000 312A00▄533600▄545300▄315400▄535400▄540000 540000 0053FF▄0053FF▄540000 530000 535400▄535400▄545300▄530000 363100▄312A00▄313600▄545300▄0000FF 0000FF 0000FF 0000FF 530000 535400▄540000 545300▄555400▄315500▄315400▄533100▄543100▄530000 533100▄530000 535400▄535500▄533100▄535400▄315300▄533100▄533600▄315300▄530000 542A00▄312800▄0029FF▀0000FF 0000FF 0000FF 0000FF 530000 545500▄540000 555300▄535400▄530000 542A00▄545300▄365400▄530000 543600▄2A5400▄547E00▄550000 545300▄533600▄540000 530000 530000 542A00▄2A0000▄0029FF▀0000FF 0000FF 0000FF 0000FF 0000FF 530000 535400▄540000 540000 540000 545300▄530000 540000 2A5500▄545300▄292A00▄290000 292A00▄290000 295400▄292A00▄292A00▄290000 542A00▄543600▄285400▄0054FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 530000 533100▄540000 530000 535400▄0053FF▀0053FF▀542800▄542800▄532800▄2A2900▄542900▄532900▄542900▄542900▄532900▄542800▄2A2900▄2A2800▄532900▄552800▄542800▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 2A5300▄530000 535400▄540000 530000 532A00▀2A5300▄2A5500▄0029FF▀0028FF▀0028FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0028FF▀0028FF▀0028FF▀295300▄535500▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 535400▄545300▄530000 545300▄530000 2A0000 2A5300▄545300▄532A00▄542900▄532900▄2A2900▄2A2900▄2A2800▄2A2800▄2A2800▄2A2900▄2A2900▄532900▄532900▄2A2900▄542A00▄545300▄0054FF▄0054FF▄0000FF 0000FF 0000FF 545300▄530000 530000 545300▄2A5300▄532A00▄542900▄290000 295400▄297F00▄548100▄548100▄558100▄558100▄558100▄558100▄538100▄2A8100▄007E00▄295400▄2A2900▄295400▄2A2900▄290000 542A00▄557E00▄0000FF 0000FF 530000 2A0000 545300▄530000 532900▄285400▄2A8000▄7F8100▄810000 810000 810000 810000 810000 810000 812A00N810000 810000 810000 810000 810000 808100▄548100▄545500▄295300▄282900▄542900▄0000FF 0000FF 2A0000 2A0000 545300▄2A2900▄298000▄810000 810000 815500381550018155005810000 810000 810000 810000 810000 810000 810000 810000 81550048155005810000 810000 810000 558100▄2A5300▄282900▄0029FF▄0000FF 532A00▄2A0000 545300▄547E00▄810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 7F8000▄290000 292800▄0000FF 2A0000 2A0000 2A5300▄7E5300▄810000 812A00W810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 812A00E810000 807E00▄2A2900▄292800▄0000FF 2A0000 2A2900▄2A0000 2A0000 552A00▄810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 810000 815500▄542900▄280000 0028FF▀530000 2A0000 2A0000 290000 2A2900▄545300▄552A00▄815500▄810000 815500281550028155005810000 810000 810000 810000 810000 810000 810000 815500181550038155005817F00▄552900▄292800▄280000 282A00▄0000FF 530000 2A0000 540000 2A5300▄282A00▄290000 532900▄542A00▄542800▄552900▄7F5300▄815500▄817F00▄817F00▄810000 812A00S810000 817F00▄815500▄815500▄555400▄532900▄292800▄280000 282A00▄282A00▄530000 0000FF 532A00▄2A0000 530000 530000 2A5300▄290000 282900▄002900▄280000 280000 280000 290000 292A00▄2A2900▄542900▄532900▄2A0000 295300▄282900▄280000 280000 280000 282900▄295300▄295300▄2A5300▄552A00▄0000FF 530000 295300▄535400▄540000 535400▄540000 535400▄2A5500▄282900▄280000▄280000 280000▄290000▄2A2800▄2A2900▄552A00▄7E0000▄2A0000▄280000▄280000 280000▄280000▄002AFF▀002AFF▀002AFF▀002AFF▀0000FF 0000FF 532900▄532800▄0029FF▀0029FF▀0029FF▀0029FF▀0029FF▀0029FF▀0000FF 2A9800▄285500▄547E00▄7E5400▄7F5300▄7E2900▄7E2900▄552A00▄542A00▄2A5300▄282A00▄2A7E00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF ") end
|
||
screen.drawImage(x, y, rayEngine.compassImage)
|
||
|
||
x, y = x + 15, y + 17
|
||
local distance = 3.4
|
||
local northAngle = -rayEngine.player.rotation
|
||
local xScaleFactor = 2.2
|
||
local southPoint, northPoint = {}, {}
|
||
local northAngleRad = math.rad(northAngle)
|
||
northPoint.x, northPoint.y = number.round(x + math.sin(northAngleRad) * distance * xScaleFactor), number.round(y - math.cos(northAngleRad) * distance)
|
||
northAngleRad = math.rad(northAngle + 180)
|
||
southPoint.x, southPoint.y = number.round(x + math.sin(northAngleRad) * distance * xScaleFactor), number.round(y - math.cos(northAngleRad) * distance)
|
||
|
||
y = y * 2
|
||
screen.drawSemiPixelLine(x, y, northPoint.x, northPoint.y * 2, 0xFF5555)
|
||
screen.drawSemiPixelLine(x, y, southPoint.x, southPoint.y * 2, 0xFFFFFF)
|
||
screen.semiPixelSet(x, y, 0x000000)
|
||
end
|
||
|
||
function rayEngine.watch(x, y)
|
||
if not rayEngine.watchImage then rayEngine.watchImage = image.fromString("20190000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0053FF▄552900▄673100▄7E2A00▄7E3100▄7E2A00▄7E3100▄672A00▄7E2A00▄672900▄7F3100▄7E2A00▄0053FF▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 313600▄290000 290600▄062900▄290000 062900▄290000 062900▄290000 290600▄062900▄2A2900▄2A0600▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 313600▄012900▄2A2900▄290000 012900▄290000 290000 012A00▄290000 290000 312900▄293100▄310600▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 310000 292800▄062A00▄290000 290100▄062900▄290000 290000 2C2900▄290600▄293100▄2A2900▄292800▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0054FF▄557F00▄012800▄290000 290000 292800▄290000 012900▄292800▄290600▄290000 292800▄290000 012800▄807E00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF AB8100▄7F8000▄283100▄280000 015400▄318100▄005300▄065500▄315500▄282A00▄296700▄015500▄290000 002900▄677E00▄81AA00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 807F00▄7F8000▄677E00▄812900▄672800▄542800▄2A0000▄2A0000▄815400▄ACAA00▄555400▄283100▄2A0000 312900▄672800▄7F5300▄7F0000 7F0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 007EFF▄817E00▄7E2900▄2A0000▄805300▄54AA00▄003100▄2A0000 310600▄532900▄312800▄532900▄360100▄552900▄672800▄7E2A00▄315500▄678000▄555300▄540000▄805400▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0081FF▄802900▄280100▄280000 285400▄310600▄532900▄290000 290000 290000 290000 29D700129D7002290000 290000 290000 282900▄062900▄2A2900▄550600▄556700▄285500▄542800▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0080FF▄557E00▄28AA00▄005500▄552900▄290000 290000 290000 29D700129D7001290000 290000 290000 290000 290000 290000 290000 29D7001290000 290000 290000 290000 672900▄318000▄297F00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 543100▄002800▄553100▄7E2800▄290000 29D700129D7000290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 29D7002290000 290000 7E2900▄7E6700▄282900▄808100▄0000FF 0000FF 0000FF 0000FF 805500▄280000▄290000 310600▄290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 555400▄535400▄533100▄D58000▄0080FF▄0000FF 552900▀550000 54AB00▄558100▄290000 290000 29D7009290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 29D7003290000 315400▄548100▄067E00▄557F00▄806700▄ACAB00▄0055FF▀545500▄AB3100▄815400▄290100▄290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 545300▄AB5500▄815300▄558000▄558000▄0000FF 0000FF 538100▄002800▄290600▄290000 290000 290000 29D7008290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 29D7004290000 290000 530000 000000 286700▄0080FF▀0000FF 0000FF 0000FF 0000FF 292A00▄000100▄530000 285400▄290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 290000 296700▄063100▄280000 818000▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 550000 810000▄532800▄015300▄280000 292800▄290000 29D7007290000 290000 290000 290000 290000 290000 290000 290000 290000 29D7005290000 290100▄292A00▄065300▄7F0000▄802900▄81C900▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 549900▄002900▄292800▄312800▄290600▄283100▄290600▄292800▄290000 290000 290000 29D7006290000 290000 292800▄292800▄290000 285300▄2A0600▄362800▄280000 285500▄0081FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 7EAA00▄317E00▄005300▄547E00▄7F2900▄290000▄292A00▄063100▄283100▄295500▄286200▄285500▄012A00▄292A00▄310600▄540000▄807E00▄005500▄015500▄530000 0081FF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 7E8100▄7E8000▄557F00▄317E00▄2A3600▄283100▄005400▄2A5300▄817E00▄AA7E00▄545300▄005300▄005400▄283100▄537E00▄548100▄7F0000 7E8000▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 819800▄807F00▄280000 002900▄312900▄7E2800▄292800▄532800▄552900▄280000 550100▄542800▄282900▄000100▄7E0000 AA9800▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 555300▄012800▄290000 062900▄290000 062900▄290000 062900▄290000 290000 290000 290600▄280000 007EFF▀0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 313600▄062900▄312900▄290000 012900▄293100▄290000 062900▄312900▄290600▄312900▄2A0000 2A2900▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 315400▄290600▄310000 062900▄290000 293100▄062900▄290000 293100▄290000 293100▄062900▄312A00▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0054FF▀285500▄285500▄015500▄285500▄285500▄015500▄295500▄015500▄285500▄015500▄285500▄065500▄0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF ") end
|
||
|
||
screen.drawImage(x, y, rayEngine.watchImage)
|
||
x, y = x + 15, y + 12
|
||
|
||
local realTimeInSeconds = rayEngine.world.dayNightCycle.currentTime * 86400 / rayEngine.world.dayNightCycle.length
|
||
local hours = realTimeInSeconds / 3600
|
||
local _, minutes = math.modf(hours)
|
||
local hourAngle = math.rad(hours * 360 / 12)
|
||
local minuteAngle = math.rad(minutes * 360)
|
||
local hourArrowLength, minuteArrowLength = 2.8, 4.5
|
||
local xMinute, yMinute = number.round(x + math.sin(minuteAngle) * minuteArrowLength * 2), number.round(y - math.cos(minuteAngle) * minuteArrowLength)
|
||
local xHour, yHour = number.round(x + math.sin(hourAngle) * hourArrowLength * 2), number.round(y - math.cos(hourAngle) * hourArrowLength)
|
||
|
||
y = y * 2
|
||
screen.drawSemiPixelLine(x, y, xMinute, yMinute * 2, 0xEEEEEE)
|
||
screen.drawSemiPixelLine(x, y, xHour, yHour * 2, 0xEEEEEE)
|
||
end
|
||
|
||
local function addItemToChatHistory(text, color)
|
||
text = text.wrap({text}, rayEngine.chatPanelWidth - 2)
|
||
table.insert(rayEngine.chatHistory, {color = color, text = text})
|
||
if #rayEngine.chatHistory > rayEngine.chatHistoryLimit then table.remove(rayEngine.chatHistory, 1) end
|
||
end
|
||
|
||
function rayEngine.chat(transparency)
|
||
local x, y = 1, screen.getHeight() - rayEngine.chatPanelHeight - 3
|
||
screen.drawRectangle(x, y, rayEngine.chatPanelWidth, rayEngine.chatPanelHeight, 0x000000, 0xFFFFFF, " ", transparency or 0.5)
|
||
screen.setDrawLimit(x, y, x + rayEngine.chatPanelWidth - 1, y + rayEngine.chatPanelHeight - 1)
|
||
local yMessage = y + rayEngine.chatPanelHeight - 1
|
||
x = x + 1
|
||
|
||
for message = #rayEngine.chatHistory, 1, -1 do
|
||
for line = #rayEngine.chatHistory[message].text, 1, -1 do
|
||
screen.drawText(x, yMessage, rayEngine.chatHistory[message].color or 0xFFFFFF, rayEngine.chatHistory[message].text[line])
|
||
yMessage = yMessage - 1
|
||
if yMessage < y then screen.resetDrawLimit(); return end
|
||
end
|
||
end
|
||
|
||
screen.resetDrawLimit()
|
||
end
|
||
|
||
function rayEngine.commandLine(transparency)
|
||
transparency = transparency or 50
|
||
local inputPanelHeight = 3
|
||
local x, y = 1, screen.getHeight() - inputPanelHeight + 1
|
||
--Врубаем чат и рисуем все, включая его
|
||
rayEngine.chatEnabled = true
|
||
rayEngine.update()
|
||
|
||
--Ввод данных
|
||
local input = GUI.input(x, y, screen.getWidth(), 3, 0xFFFFFF, 0x3C3C3C, 0x666666, 0xFFFFFF, 0x3C3C3C, "")
|
||
input.eventHandler({draw = function() input:draw() end}, input, "touch", input.x, input.y)
|
||
|
||
local words = {}; for word in string.gmatch(input.text, "[^%s]+") do table.insert(words, unicode.lower(word)) end
|
||
if #words > 0 then
|
||
if unicode.sub(words[1], 1, 1) == "/" then
|
||
words[1] = unicode.sub(words[1], 2, -1)
|
||
if words[1] == "time" then
|
||
if words[2] == "set" and words[3] and tonumber(words[3]) then
|
||
local newTime = tonumber(words[3])
|
||
if newTime < 0 or newTime > rayEngine.world.dayNightCycle.length then
|
||
addItemToChatHistory("Время не может быть отрицательным и превышать длину суток (" .. rayEngine.world.dayNightCycle.length .. " секю)", 0xFF8888)
|
||
else
|
||
rayEngine.world.dayNightCycle.currentTime = math.floor(newTime)
|
||
addItemToChatHistory("Время успешно изменено на: " .. newTime, 0xFFDB40)
|
||
end
|
||
elseif words[2] == "get" then
|
||
addItemToChatHistory("Текущее время: " .. rayEngine.world.dayNightCycle.currentTime, 0xFFDB40)
|
||
addItemToChatHistory("Длина суток: " .. rayEngine.world.dayNightCycle.length, 0xFFDB40)
|
||
elseif words[2] == "lock" then
|
||
rayEngine.world.dayNightCycle.enabled = not rayEngine.world.dayNightCycle.enabled
|
||
addItemToChatHistory("Состояние цикла дня и ночи: " .. tostring(rayEngine.world.dayNightCycle.enabled), 0xFFDB40)
|
||
end
|
||
elseif words[1] == "setrenderquality" and tonumber(words[2]) then
|
||
rayEngine.properties.raycastQuality = tonumber(words[2])
|
||
addItemToChatHistory("Качество рендера изменено на: " .. tonumber(words[2]), 0xFFDB40)
|
||
elseif words[1] == "setdrawdistance" and tonumber(words[2]) then
|
||
rayEngine.properties.drawDistance = tonumber(words[2])
|
||
addItemToChatHistory("Дистанция прорисовки изменена на: " .. tonumber(words[2]), 0xFFDB40)
|
||
elseif words[1] == "setshadingcascades" and tonumber(words[2]) then
|
||
rayEngine.properties.shadingCascades = tonumber(words[2])
|
||
addItemToChatHistory("Количество цветов для отрисовки блока изменено на: " .. tonumber(words[2]), 0xFFDB40)
|
||
elseif words[1] == "setshadingdistance" and tonumber(words[2]) then
|
||
rayEngine.properties.shadingDistance = tonumber(words[2])
|
||
addItemToChatHistory("Дистация затенения блоков изменена на: " .. tonumber(words[2]), 0xFFDB40)
|
||
elseif words[1] == "help" then
|
||
addItemToChatHistory("Доступные команды:", 0xFFDB40)
|
||
addItemToChatHistory("/time get", 0xFFFFBF)
|
||
addItemToChatHistory("/time set <value>", 0xFFFFBF)
|
||
addItemToChatHistory("/time lock", 0xFFFFBF)
|
||
addItemToChatHistory(" ", 0xFFFFFF)
|
||
addItemToChatHistory("/setRenderQuality <value>", 0xFFFFBF)
|
||
addItemToChatHistory("/setDrawDistance <value>", 0xFFFFBF)
|
||
addItemToChatHistory("/setShadingCascades <value>", 0xFFFFBF)
|
||
addItemToChatHistory("/setShadingDistance <value>", 0xFFFFBF)
|
||
else
|
||
addItemToChatHistory("Неизвестная команда. Введите /help для получения списка команд", 0xFF8888)
|
||
end
|
||
else
|
||
addItemToChatHistory("> " .. input.text, 0xFFFFFF)
|
||
end
|
||
end
|
||
|
||
--Активируем таймер
|
||
if rayEngine.chatTimer then event.cancel(rayEngine.chatTimer) end
|
||
rayEngine.chatEnabled = true
|
||
rayEngine.chatTimer = event.timer(rayEngine.chatShowTime, function() rayEngine.chatEnabled = false; rayEngine.chatTimer = nil; update() end)
|
||
end
|
||
|
||
function rayEngine.toggleMinimap()
|
||
rayEngine.minimapEnabled = not rayEngine.minimapEnabled
|
||
end
|
||
|
||
function rayEngine.toggleDebugInformation()
|
||
rayEngine.debugInformationEnabled = not rayEngine.debugInformationEnabled
|
||
end
|
||
|
||
function rayEngine.toggleCompass()
|
||
rayEngine.compassEnabled = not rayEngine.compassEnabled
|
||
if not rayEngine.compassEnabled then rayEngine.compassImage = nil end
|
||
end
|
||
|
||
function rayEngine.toggleWatch()
|
||
rayEngine.watchEnabled = not rayEngine.watchEnabled
|
||
if not rayEngine.watchEnabled then rayEngine.watchImage = nil end
|
||
end
|
||
|
||
function rayEngine.drawWeapon()
|
||
--Пока рисуем, вычитаем время стрельбы
|
||
if rayEngine.currentWeapon.needToFire > 1 then
|
||
screen.drawImage(rayEngine.currentWeapon.xFire, rayEngine.currentWeapon.yFire, rayEngine.currentWeapon.fireTexture)
|
||
end
|
||
rayEngine.currentWeapon.needToFire = rayEngine.currentWeapon.needToFire - 1
|
||
--Рисуем картинку оружия поверх вспышки, а затем и прицел
|
||
screen.drawImage(rayEngine.currentWeapon.xWeapon, rayEngine.currentWeapon.yWeapon, rayEngine.currentWeapon.weaponTexture)
|
||
screen.drawImage(rayEngine.currentWeapon.xCrosshair, rayEngine.currentWeapon.yCrosshair, rayEngine.currentWeapon.crosshairTexture)
|
||
end
|
||
|
||
function rayEngine.drawStats()
|
||
local width = math.floor(screen.getWidth() * 0.3)
|
||
local height = 5
|
||
local x, y = screen.getWidth() - width - 1, 2
|
||
screen.drawRectangle(x, y, width, height, 0x000000, 0xFFFFFF, " ", 0.5)
|
||
|
||
GUI.progressBar(x + 1, y + 4, width - 2, 1, 0x000000, 0xFF5555, rayEngine.player.health.current, rayEngine.player.health.maximum, true)
|
||
end
|
||
|
||
---------------------------------------------------- Функции отрисовки мира ------------------------------------------------------------------
|
||
|
||
rayEngine.caughtEntities = {}
|
||
|
||
--Свистнул функцию с StackOverflow. Заменяет оператор in из питона
|
||
local function has_value (tab, val)
|
||
for index, value in ipairs(tab) do
|
||
if value == val then
|
||
return true
|
||
end
|
||
end
|
||
|
||
return false
|
||
end
|
||
|
||
|
||
function rayEngine.getEntitiesAt(x,y)
|
||
mapX = math.floor(x / rayEngine.properties.tileWidth)
|
||
mapY = math.floor(y / rayEngine.properties.tileWidth)
|
||
if rayEngine.hitBlocks[mapX] and rayEngine.hitBlocks[mapX][mapY] then
|
||
return rayEngine.hitBlocks[mapX][mapY]
|
||
else
|
||
return {}
|
||
end
|
||
end
|
||
|
||
local function raycast(angle,maxRange)
|
||
rayEngine.caughtEntities = {}
|
||
angle = math.rad(angle)
|
||
local raySteps = 0
|
||
local angleSinDistance, angleCosDistance, currentDistance, xWorld, yWorld, xMap, yMap, tile = math.sin(angle) * rayEngine.properties.raycastQuality, math.cos(angle) * rayEngine.properties.raycastQuality, 0, rayEngine.player.position.x, rayEngine.player.position.y
|
||
|
||
while true do
|
||
if currentDistance <= maxRange then
|
||
xMap, yMap = math.floor(xWorld / rayEngine.properties.tileWidth), math.floor(yWorld / rayEngine.properties.tileWidth)
|
||
if rayEngine.map[yMap] and rayEngine.map[yMap][xMap] then
|
||
return currentDistance, rayEngine.map[yMap][xMap]
|
||
end
|
||
|
||
xWorld, yWorld = xWorld + angleSinDistance, yWorld + angleCosDistance
|
||
currentDistance = currentDistance + rayEngine.properties.raycastQuality
|
||
raySteps = raySteps + 1
|
||
if raySteps % 1 == 0 then
|
||
local entityList = rayEngine.getEntitiesAt(xWorld,yWorld)
|
||
|
||
if entityList then
|
||
for i = 1,#entityList do
|
||
if not has_value(rayEngine.caughtEntities,entityList[i]) then
|
||
table.insert(rayEngine.caughtEntities, entityList[i])
|
||
end
|
||
end
|
||
end
|
||
end
|
||
else
|
||
return nil
|
||
end
|
||
end
|
||
end
|
||
|
||
function calcDistance(x1,y1,x2,y2)
|
||
relativeX = (x2-x1)
|
||
relativeY = (y2-y1)
|
||
distance = math.sqrt(relativeX*relativeX + relativeY*relativeY)
|
||
return distance
|
||
end
|
||
|
||
function rayEngine.drawSpriteColumn(x,y,rayAngle,scrX,sprName)
|
||
|
||
sprImage = rayEngine.sprites[sprName]
|
||
relativeX = (rayEngine.player.position.x - x)
|
||
relativeY = (rayEngine.player.position.y - y)
|
||
distance = math.sqrt(relativeX*relativeX + relativeY*relativeY)
|
||
|
||
|
||
iwidth,iheight = image.getSize(sprImage)
|
||
|
||
angleTheta = math.deg(math.atan(-relativeX, -relativeY))
|
||
angleDelta = angleTheta - rayEngine.player.rotation
|
||
|
||
angleDelta = constrain180(angleDelta)
|
||
|
||
centerX = angleDelta / rayEngine.raycastStep + screen.getWidth() / 2
|
||
wingShift = iwidth / distance * rayEngine.distanceToProjectionPlane
|
||
startX = centerX - wingShift / 2
|
||
endX = centerX + wingShift / 2
|
||
|
||
|
||
height = iheight / distance * rayEngine.distanceToProjectionPlane
|
||
startY = rayEngine.horizonPosition - height / 2 + 1
|
||
|
||
picX = math.floor((scrX - endX) / wingShift * iwidth)
|
||
if scrX >= startX and scrX <= endX then
|
||
for iterY = 0, height do
|
||
coordY = math.floor(startY + iterY)
|
||
picY = math.floor(iterY/height * iheight)+1
|
||
b,f,a,s = image.get(sprImage,picX,picY)
|
||
if b and f and (a == 0) then
|
||
--print(centerX,wingShift,startX,endX,picX,endX,f, b) --раскомментируй на случай дебага
|
||
--print(rayEngine.player.rotation,angleTheta,angleDelta," ", startX)
|
||
screen.drawRectangle(scrX,coordY,1,1,b,f,s)
|
||
end
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
function rayEngine.drawWorld()
|
||
--Земля
|
||
screen.clear(rayEngine.world.colors.groundByTime)
|
||
--Небо
|
||
screen.drawRectangle(1, 1, screen.getWidth(), rayEngine.horizonPosition, rayEngine.world.colors.sky.current, 0x0, " ")
|
||
--Сцена
|
||
local startAngle, endAngle, startX, distanceToTile, tileID, height, startY, tileColor = rayEngine.player.rotation - rayEngine.player.fieldOfView / 2, rayEngine.player.rotation + rayEngine.player.fieldOfView / 2, 1
|
||
for angle = startAngle, endAngle, rayEngine.raycastStep do
|
||
distanceToTile, tileID = raycast(angle,rayEngine.properties.drawDistance)
|
||
|
||
|
||
|
||
if distanceToTile then
|
||
-- Получаем цвет стенки
|
||
tileColor = getTileColor(rayEngine.blocks[tileID].color, distanceToTile)
|
||
|
||
-- Поддержка "высококачественной" doubleHeight-графики
|
||
if rayEngine.properties.useSimpleRenderer then
|
||
height = rayEngine.properties.tileWidth / distanceToTile * rayEngine.distanceToProjectionPlane
|
||
startY = rayEngine.horizonPosition - height / 2 + 1
|
||
screen.drawRectangle(math.floor(startX), math.floor(startY), 1, math.floor(height), tileColor, 0x000000, " ")
|
||
else
|
||
height = rayEngine.properties.tileWidth / distanceToTile * rayEngine.distanceToProjectionPlane * 2
|
||
startY = rayEngine.horizonPosition * 2 - height / 2 + 1
|
||
screen.drawSemiPixelRectangle(math.floor(startX), math.floor(startY), 1, height, tileColor)
|
||
end
|
||
|
||
--ТИКСТУРКА)))00
|
||
-- local xTexture = startX % rayEngine.properties.tileWidth + 1
|
||
-- if xTexture >= 1 and xTexture <= screen.getWidth() then
|
||
-- local column = image.getColumn(rayEngine.wallsTexture, xTexture)
|
||
-- column = image.transform(column, 1, height)
|
||
-- screen.drawImage(math.floor(startX), math.floor(startY), column)
|
||
-- end
|
||
|
||
--Поверх рисуем спрайты
|
||
if rayEngine.caughtEntities then
|
||
for i = #rayEngine.caughtEntities,1,-1 do
|
||
local entityID = rayEngine.caughtEntities[i]
|
||
local entity = rayEngine.entities[entityID]
|
||
rayEngine.drawSpriteColumn(entity.x,entity.y,angle,startX,entity.sprite.image)
|
||
end
|
||
end
|
||
|
||
|
||
end
|
||
startX = startX + 1
|
||
end
|
||
end
|
||
|
||
function rayEngine.update()
|
||
|
||
|
||
|
||
local frameRenderClock = os.clock()
|
||
rayEngine.rotate(rayEngine.player.rotationSpeed * inputYaw)
|
||
rayEngine.move(rayEngine.player.moveSpeed * inputY, rayEngine.player.moveSpeed * inputX)
|
||
|
||
if holdingFire == 1 then rayEngine.fireAuto() end
|
||
|
||
rayEngine.drawWorld()
|
||
if rayEngine.currentWeapon then rayEngine.drawWeapon() end
|
||
if rayEngine.minimapEnabled then rayEngine.drawMap(3, 2, 24, 24, 0.5) end
|
||
-- rayEngine.drawStats()
|
||
local xTools, yTools = 3, screen.getHeight() - 25
|
||
if rayEngine.compassEnabled then rayEngine.compass(xTools, yTools); xTools = xTools + 30 end
|
||
if rayEngine.watchEnabled then rayEngine.watch(xTools, yTools) end
|
||
if rayEngine.chatEnabled then rayEngine.chat() end
|
||
doDayNightCycle()
|
||
|
||
raycast(rayEngine.player.rotation,rayEngine.properties.drawDistance)
|
||
|
||
if rayEngine.debugInformationEnabled then
|
||
rayEngine.drawDebugInformation(3, 2 + (rayEngine.minimapEnabled and 12 or 0), 24, 0.6,
|
||
"renderTime: " .. string.format("%.2f", ((os.clock() - frameRenderClock) + (endRenderClock-startRenderClock)) * 1000) .. " ms",
|
||
"FPS: " .. string.format("%.2f",fps),
|
||
"freeRAM: " .. string.format("%.2f", computer.freeMemory() / 1024) .. " KB",
|
||
"pos: " .. string.format("%.2f", rayEngine.player.position.x) .. " x " .. string.format("%.2f", rayEngine.player.position.y),
|
||
"collision check blocks: " .. string.format("%i", #rayEngine.hitBlocks) .. "x" .. string.format("%i", #rayEngine.hitBlocks[1]),
|
||
"entities: " .. string.format("%i", #rayEngine.entities),
|
||
"entities at: " .. string.format("%i", #rayEngine.caughtEntities),
|
||
"sprites: " .. string.format("%i", #rayEngine.sprites)
|
||
)
|
||
end
|
||
startRenderClock = os.clock()
|
||
|
||
screen.update()
|
||
frameCount = frameCount + 1
|
||
|
||
if (os.clock() - lastFPSCheck) > 1 then
|
||
fps = frameCount
|
||
frameCount = 0
|
||
lastFPSCheck = os.clock()
|
||
end
|
||
endRenderClock = os.clock()
|
||
end
|
||
|
||
----------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
function rayEngine.changeResolution(width, height)
|
||
screen.setResolution(width, height)
|
||
rayEngine.calculateAllParameters()
|
||
end
|
||
|
||
function rayEngine.fire()
|
||
--Если мы уже стреляем, то, естественно, выходим из функции
|
||
if rayEngine.currentWeapon.needToFire > 0 then return end
|
||
--Иначе стреляем
|
||
holdingFire = 1
|
||
rayEngine.currentWeapon.needToFire = rayEngine.currentWeapon.fireTime
|
||
rayEngine.stopYaw() --Останавливаю игрока, т.к. события touch и key_up - злейшие враги всего OpenComputers
|
||
|
||
end
|
||
|
||
function rayEngine.unfire()
|
||
holdingFire = 0
|
||
end
|
||
|
||
function rayEngine.fireAuto()
|
||
--Если мы уже стреляем, то, естественно, выходим из функции
|
||
if rayEngine.currentWeapon.needToFire > 0 then return end
|
||
--Тоже самое, если оружие - пистолет/полуавто винтовка
|
||
if rayEngine.currentWeapon.isAuto == 0 then return end
|
||
--Иначе стреляем
|
||
rayEngine.currentWeapon.needToFire = rayEngine.currentWeapon.fireTime
|
||
rayEngine.stopYaw() --Останавливаю игрока, т.к. события touch и key_up - злейшие враги всего OpenComputers
|
||
|
||
end
|
||
|
||
----------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
return rayEngine
|
||
|