diff --git a/src/community/docsGamesBuildersLua.js b/src/community/docsGamesBuildersLua.js index f9d9692..ce3cff1 100644 --- a/src/community/docsGamesBuildersLua.js +++ b/src/community/docsGamesBuildersLua.js @@ -139,19 +139,8 @@ local RunService = game:GetService("RunService") local player = Players.LocalPlayer local won = false --- Подсказка по центру (на 3 секунды) -local hintGui = Instance.new("ScreenGui", player.PlayerGui) -hintGui.Name = "Hint" -local hint = Instance.new("TextLabel", hintGui) -hint.Size = UDim2.new(0, 480, 0, 60) -hint.Position = UDim2.new(0.5, -240, 0.3, 0) -hint.BackgroundColor3 = Color3.fromRGB(0, 0, 0) -hint.BackgroundTransparency = 0.4 -hint.TextColor3 = Color3.fromRGB(255, 255, 255) -hint.TextScaled = true -hint.Font = Enum.Font.SourceSansBold -hint.Text = "Допрыгай до зелёной площадки!" -task.delay(3, function() hintGui:Destroy() end) +-- Подсказка по центру (паритет с JS game.ui.showText) +__rbxl_show_text("Допрыгай до зелёной площадки!", 3) -- Звуки local loseSound = Instance.new("Sound", workspace) @@ -170,17 +159,7 @@ RunService.Heartbeat:Connect(function() if hrp and hrp.Position.Y < -3 then player:LoadCharacter() loseSound:Play() - local fallGui = Instance.new("ScreenGui", player.PlayerGui) - local fallLabel = Instance.new("TextLabel", fallGui) - fallLabel.Size = UDim2.new(0, 400, 0, 60) - fallLabel.Position = UDim2.new(0.5, -200, 0.35, 0) - fallLabel.BackgroundColor3 = Color3.fromRGB(120, 0, 0) - fallLabel.BackgroundTransparency = 0.3 - fallLabel.TextColor3 = Color3.fromRGB(255, 255, 255) - fallLabel.TextScaled = true - fallLabel.Font = Enum.Font.SourceSansBold - fallLabel.Text = "Упал! Пробуй снова." - task.delay(1.5, function() fallGui:Destroy() end) + __rbxl_show_text("Упал! Пробуй снова.", 1.5) end end) @@ -190,16 +169,10 @@ finishEvent.Event:Connect(function() if won then return end won = true winSound:Play() - local winGui = Instance.new("ScreenGui", player.PlayerGui) - local winLabel = Instance.new("TextLabel", winGui) - winLabel.Size = UDim2.new(0, 540, 0, 80) - winLabel.Position = UDim2.new(0.5, -270, 0.4, 0) - winLabel.BackgroundColor3 = Color3.fromRGB(0, 120, 0) - winLabel.BackgroundTransparency = 0.2 - winLabel.TextColor3 = Color3.fromRGB(255, 255, 0) - winLabel.TextScaled = true - winLabel.Font = Enum.Font.SourceSansBold - winLabel.Text = "Победа! Ты дошёл до финиша!" + __rbxl_show_text("Победа! Ты дошёл до финиша!", 5) + -- Конфетти над игроком (как JS game.scene.spawnParticles) + local pos = __rbxl_player_pos() + __rbxl_spawn_particles("confetti", pos.x, pos.y + 3, pos.z, 3, 3) end)`, g2_finish: `-- === Скрипт финиш-зоны (Lua) === -- Висит на невидимой зоне над зелёной площадкой. diff --git a/src/editor/engine/GameRuntime.js b/src/editor/engine/GameRuntime.js index 9a24221..90cca57 100644 --- a/src/editor/engine/GameRuntime.js +++ b/src/editor/engine/GameRuntime.js @@ -296,6 +296,23 @@ export class GameRuntime { this._ensureRbxlHud(); this._rbxlHud.showWin(payload.text || 'WIN!'); } catch (_) {} + } else if (cmd === 'ui.showText') { + // Lua-helper __rbxl_show_text: красивый центрированный + // текст без рамки (паритет с JS game.ui.showText). + try { + this._ensureRbxlHud(); + this._rbxlHud.showMessage(payload.text || ''); + const dur = Number(payload.duration) || 2; + const t = payload.text || ''; + setTimeout(() => { + try { + if (this._rbxlHud._lastMessage === t) { + this._rbxlHud.hideMessage(); + } + } catch (_) {} + }, dur * 1000); + try { this._rbxlHud._lastMessage = t; } catch (_) {} + } catch (_) {} } else if (cmd === 'leaderstatSet') { // Roblox leaderstats: IntValue.Value меняется → HUD. try { diff --git a/src/editor/engine/lua/RobloxShim.js b/src/editor/engine/lua/RobloxShim.js index e3127e9..c5e6e12 100644 --- a/src/editor/engine/lua/RobloxShim.js +++ b/src/editor/engine/lua/RobloxShim.js @@ -1807,6 +1807,31 @@ export function registerRobloxShim(lua, opts) { global.set('__log', (level, text) => { send('log', { level: String(level || 'info'), text: String(text || '') }); }); + // === Хелперы паритета с JS game.ui / game.scene === + // Красивый центрированный текст без рамки (как game.ui.showText). + global.set('__rbxl_show_text', (text, duration, color) => { + send('ui.showText', { + text: String(text || ''), + duration: Number(duration) || 2, + color: color || '#ffffff', + }); + }); + // Эффекты частиц (confetti, sparks и т.п.) — как game.scene.spawnParticles. + global.set('__rbxl_spawn_particles', (kind, x, y, z, duration, count) => { + send('scene.particles', { + kind: String(kind || 'confetti'), + pos: { x: +x, y: +y, z: +z }, + duration: Number(duration) || 2, + count: Number(count) || 1, + }); + }); + // Позиция игрока для удобства (для confetti над головой и т.п.) + global.set('__rbxl_player_pos', () => { + try { + const p = hrp._position || { X: 0, Y: 0, Z: 0 }; + return { x: p.X, y: p.Y, z: p.Z }; + } catch (_) { return { x: 0, y: 0, z: 0 }; } + }); // Достаём ссылку на Lua-функцию один раз; вызовы безопасны (не doStringSync) const luaResumeCo = lua.global.get('__rbxl_resume_co');