Как сделать адаптацию лучей к наклонным поверхностям

Tectrex

Известный
Автор темы
126
135
Версия MoonLoader
.026-beta
Не так давно я работал над избеганием объектов с помощью лучей и столкнулся с проблемой: лучи могут столкнуться с холмами или дорогами под наклоном. Я пробовал испустить еще один луч и отразить его от нормали, чтобы получить отраженный направляющий луч. Затем, я попытался изменить угол наклона лучей на угол наклона направляющего луча, который был отражен от нормали, но получилось уебищно.
1708954647214.png

Этот способ хуево работает, ищу тут варианты решения, а если вы филантроп от мира кодинга, то можете еще и готовый код написать.

Lua:
local VK_S = 0x53
local VK_A = 0x41
local VK_D = 0x44

local font = renderCreateFont("Arial", 8, 8)

local DrivingAssistant = {}
DrivingAssistant.__index = DrivingAssistant

function DrivingAssistant.new()
    local self = setmetatable({}, DrivingAssistant)
    self.drivingEnabled = false
    self.lastTurnDirection = nil
    self.userInputMultiplier = 5
    return self
end

function DrivingAssistant:toggleDriving()
    self.drivingEnabled = not self.drivingEnabled
    local message = self.drivingEnabled and 'Ассистент двух колес включен.' or 'Ассистент двух колес выключен.'
    sampAddChatMessage(message, -1)
end

function DrivingAssistant:processDriving()
    if not isCharInAnyCar(PLAYER_PED) then
        sampAddChatMessage('Вы должны сесть на байк.', -1)
        return
    end

    local playerCoords, playerHeading = getPlayerCoordsAndHeading()
    local radOffset, offsetZ = math.rad(-playerHeading), playerCoords[3]
    local offsetX, offsetY = getOffsetCoords(playerCoords, radOffset)

    local obstacleInfo, allLinesOccupied = self:detectObstacles(playerCoords, playerHeading, radOffset, offsetZ, offsetX, offsetY)
    self:handleObstacles(obstacleInfo, allLinesOccupied)
end

function DrivingAssistant:detectObstacles(playerCoords, playerHeading, radOffset, offsetZ, offsetX, offsetY)
    local obstacleInfo = {
        detected = {left = false, right = false, front = false, center = false},
        specific = {}
    }

    local pitch = getCarPitch(getCarCharIsUsing(PLAYER_PED))
    local radPitch = math.rad(pitch)
    local allLinesOccupied = true

    for i = -4, 4 do
        local radian = math.rad(-playerHeading + 2 * i)
        local sinRadian, cosRadian = math.sin(radian), math.cos(radian)
        local multiplier = self:getMultiplier(i)
        local targetX, targetY, targetZ = self:getTargetCoords(offsetX, offsetY, offsetZ, sinRadian, cosRadian, radPitch, multiplier)
        local obstacle = isObstacleInFront(offsetX, offsetY, offsetZ, targetX, targetY, targetZ)
        
        if i ~= 0 then
            allLinesOccupied = allLinesOccupied and obstacle
        end
        
        local color = obstacle and 0xFFFF0000 or 0xFFFFFFFF
        
        renderLine3D(offsetX, offsetY, offsetZ, targetX, targetY, targetZ, 2, color)
        self:processObstacleDetection(obstacleInfo, obstacle, i)

        local textPosX, textPosY = getScreenCoordsFrom3D(targetX, targetY, targetZ)
        if textPosX and textPosY then
            renderFontDrawText(font, tostring(i), textPosX, textPosY, color)
        end
    end

    return obstacleInfo, allLinesOccupied
end

function DrivingAssistant:getMultiplier(index)
    local speedVector = { getCarSpeedVector(getCarCharIsUsing(PLAYER_PED), true) }
    local speed = math.sqrt(speedVector[1]^2 + speedVector[2]^2 + speedVector[3]^2)
    local speedFactor = 1 + speed / 10
    if index == 0 then
        return 0.5 * speedFactor
    else
        local baseMultiplier = (self.userInputMultiplier - 0.2 * math.abs(index)) * speedFactor
        return baseMultiplier
    end
end

function DrivingAssistant:getTargetCoords(offsetX, offsetY, offsetZ, sinRadian, cosRadian, radPitch, multiplier)
    local targetX = offsetX + multiplier * sinRadian
    local targetY = offsetY + multiplier * cosRadian
    local targetZ = offsetZ + multiplier * math.sin(radPitch)
    return targetX, targetY, targetZ
end

function DrivingAssistant:processObstacleDetection(obstacleInfo, obstacle, index)
    if obstacle then
        addOneOffSound(0.0, 0.0, 0.0, 1139)
        printStringNow("DETECTED", 100)
        obstacleInfo.detected.center = obstacleInfo.detected.center or index == 0
        obstacleInfo.detected.right = obstacleInfo.detected.right or (index > 0)
        obstacleInfo.detected.left = obstacleInfo.detected.left or (index < 0)
        obstacleInfo.detected.front = obstacleInfo.detected.front or (index ~= 0)
        obstacleInfo.specific[index] = true
    end
end

function DrivingAssistant:handleObstacles(obstacleInfo, allLinesOccupied)
    if obstacleInfo.detected.center then
        lua_thread.create(function()
            setVirtualKeyDown(VK_S, true)
            wait(1000)
            setVirtualKeyDown(VK_S, false)
        end)
    end

    if allLinesOccupied then
        if self.lastTurnDirection == 'right' then
            lua_thread.create(function()
                setVirtualKeyDown(VK_D, true)
                wait(250)
                setVirtualKeyDown(VK_D, false)
            end)
        elseif self.lastTurnDirection == 'left' then
            lua_thread.create(function()
                setVirtualKeyDown(VK_A, true)
                wait(250)
                setVirtualKeyDown(VK_A, false)
            end)
        else
            print("Неизвестно")
        end
    elseif obstacleInfo.detected.front then
        local leftCount = 0
        local rightCount = 0
        for i = -4, 4 do
            if i ~= 0 and obstacleInfo.specific[i] then
                if i < 0 then
                    leftCount = leftCount + 1
                elseif i > 0 then
                    rightCount = rightCount + 1
                end
            end
        end 

        if leftCount > rightCount then
            self.lastTurnDirection = 'right'
            lua_thread.create(function()
                setVirtualKeyDown(VK_D, true)
                wait(250)
                setVirtualKeyDown(VK_D, false)
            end)
        elseif rightCount > leftCount then
            self.lastTurnDirection = 'left'
            lua_thread.create(function()
                setVirtualKeyDown(VK_A, true)
                wait(250)
                setVirtualKeyDown(VK_A, false)
            end)
        end
    end
end

function getPlayerCoordsAndHeading()
    return { getCharCoordinates(PLAYER_PED) }, getCharHeading(PLAYER_PED)
end

function getOffsetCoords(playerCoords, radOffset)
    assert(type(playerCoords[1]) == "number" and type(playerCoords[2]) == "number", "?")

    local offsetX, offsetY
    if isCharInAnyCar(PLAYER_PED) then
        offsetX, offsetY = playerCoords[1] + 0.6 * math.sin(radOffset), playerCoords[2] + 0.6 * math.cos(radOffset)
    else
        offsetX, offsetY = playerCoords[1], playerCoords[2]
    end
    return offsetX, offsetY
end

function isObstacleInFront(x, y, z, targetX, targetY, targetZ)
    return processLineOfSight(x, y, z, targetX, targetY, targetZ, true, true, true, true, true, false, false, false)
end

function getScreenCoordsFrom3D(x, y, z)
    local result, screenX, screenY = convert3DCoordsToScreenEx(x, y, z)
    if result then
        return screenX, screenY
    end
end

function renderLine3D(x1, y1, z1, x2, y2, z2, width, color)
    local res1, screenX1, screenY1 = convert3DCoordsToScreenEx(x1, y1, z1)
    local res2, screenX2, screenY2 = convert3DCoordsToScreenEx(x2, y2, z2)

    if res1 and res2 and ({convert3DCoordsToScreenEx(x1, y1, z1)})[4] > 0 and isPointOnScreen(x2, y2, z2, 1.0) then
        renderDrawLine(screenX1, screenY1, screenX2, screenY2, width, color)
    end
end

function main()
    local assistant = DrivingAssistant.new()
    local VK_F5 = 0x74
    local F5L = false

    while not isSampAvailable() do wait(0) end

    sampRegisterChatCommand('helpmedrive', function()
        assistant:toggleDriving()
    end)

    sampRegisterChatCommand('setmultiplier', function(param)
        local value = tonumber(param)
        if value then
            assistant.userInputMultiplier = value
            sampAddChatMessage("Множитель дистанции установлен на: " .. value, -1)
        else
            sampAddChatMessage("Ошибка: Неверное значение множителя.", -1)
        end
    end)

    while true do
        wait(0)
        local F5T = isKeyDown(VK_F5)

        if F5T and not F5L then
            assistant:toggleDriving()
        end

        F5L = F5T

        if assistant.drivingEnabled then
            local status, err = pcall(function() assistant:processDriving() end)
            if not status then
                print("ERROR: " .. err, -1)
            end
        end
    end
end

Все еще не решено
 
Последнее редактирование: