fix(g16): урон только когда игрок РЕАЛЬНО в лаве (не над островком)

Раньше: фильтр по Y-капсулы не работал — игрок стоит на островке на
realPos.y=1.54 > порога 1.35, фильтр пропускал.

Стало: проверяем где игрок по X/Z. Если над островком (любой из 6) или
над финишной площадкой — пропускаем урон. Иначе — урон каждый кадр пока
Touched активно (RunService.Heartbeat). У damage есть i-frames ~0.5с
так что урон ~2/сек.

Также: переход с Touched-разово на Heartbeat-постоянно. Раньше Touched
срабатывал только при ВХОДЕ в лаву — если игрок стоит в лаве долго,
TouchEnded не вызывался, и урон шёл только раз. Теперь Touched/TouchEnded
выставляют inLava-флаг, Heartbeat считает урон каждый кадр.
This commit is contained in:
min 2026-06-09 20:09:07 +03:00
parent f0f739071a
commit 2979104931

View File

@ -1396,21 +1396,56 @@ end)`,
g16_lava: `-- === Скрипт лавы (Lua) === g16_lava: `-- === Скрипт лавы (Lua) ===
-- Игрок коснулся лавы урон. У damage есть защита (i-frames), -- Игрок коснулся лавы урон. У damage есть защита (i-frames),
-- так что урон не каждый кадр, а раз в ~0.5 секунды. -- так что урон не каждый кадр, а раз в ~0.5 секунды.
-- ВАЖНО: лава-зона может пересекаться с островками по AABB. Проверяем -- ВАЖНО: проверяем что игрок НЕ над островком (по X/Z),
-- что игрок РЕАЛЬНО внизу (стоит в лаве), а не на островке выше. -- иначе урон срабатывает на островке из-за пересечения AABB.
local RunService = game:GetService("RunService")
local part = script.Parent local part = script.Parent
local hitSound = Instance.new("Sound", part) local hitSound = Instance.new("Sound", part)
hitSound.SoundId = "hit"; hitSound.Volume = 0.7 hitSound.SoundId = "hit"; hitSound.Volume = 0.7
-- Координаты островков (из builder): { x, z }
local ISLES = {
{0, 5}, {3, 9}, {-2, 13}, {2, 17}, {-3, 21}, {1, 25},
}
local ISLE_HW = 1.4 -- половина ширины островка sx=2.4/2 + небольшой запас
local FINISH_X, FINISH_Z = -0.5, 29
local FINISH_HW, FINISH_HD = 3, 2.5
local function isOverSafeSpot()
local px = __rbxl_player_x()
local pz = __rbxl_player_z()
-- Островки
for _, isle in ipairs(ISLES) do
if math.abs(px - isle[1]) <= ISLE_HW
and math.abs(pz - isle[2]) <= ISLE_HW then
return true
end
end
-- Финишная площадка
if math.abs(px - FINISH_X) <= FINISH_HW
and math.abs(pz - FINISH_Z) <= FINISH_HD then
return true
end
return false
end
-- Проверяем каждый кадр пока игрок касается лавы наносим урон если он
-- НЕ над безопасным местом. Touched нам не нужен лучше Heartbeat-проверка.
local inLava = false
part.Touched:Connect(function(hit) part.Touched:Connect(function(hit)
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid") local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
if not h then return end if not h then return end
-- Игрок на безопасной высоте (на островке/финише) не урон. inLava = true
-- Лава-зона на y=1, верх y=1.3. Островки на y=1.2 верх y=1.5. end)
-- Игрок СТОИТ на островке когда его _pos.y - halfH (= нижняя точка part.TouchEnded:Connect(function(hit)
-- капсулы) ~= верх островка. Стоит на лаве когда нижняя точка ниже 1.3. local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
local py = __rbxl_player_y() if not h then return end
if py >= 1.35 then return end -- стоит на островке/финише пропускаем inLava = false
end)
RunService.Heartbeat:Connect(function()
if not inLava then return end
if isOverSafeSpot() then return end -- стоит над островком/финишем
__rbxl_damage_player(20) __rbxl_damage_player(20)
hitSound:Play() hitSound:Play()
end)`, end)`,