Roblox · Тайкун · урок 6

Game Pass: двойной доход

Пропуск за Robux: у купившего каждая конфета приносит вдвое больше. Покупка — через окно Roblox, проверка — на сервере.

Структура

Синим — что добавляем на этом уроке.

StarterGui
└─ PassGui (ScreenGui)
   ├─ OpenCloseButton (TextButton) — «Open Passes»
   │  └─ OpenCloseLocal (LocalScript)
   └─ PassFrame (Frame) — Visible выкл.
      └─ CandyMultiplier (ImageButton) — иконка пропуска
         └─ PassPurchaseLocal (LocalScript)
ServerScriptService
└─ PassPurchaseServer (Script)
ServerStorage
└─ Conveyors → CandyDropper
   └─ CandyDropperScript (Script) — обновлён

Шаги

  1. create.roblox.com → твоя игра → Monetization → Passes → Create a Pass: название, описание, иконка.
  2. Пропуск → Sales → Item for Sale, цена в Robux (разработчику — 70 %). Скопируй ID пропуска.
  3. ID вставь в PASS_ID в обоих скриптах.
  4. Pass покупается один раз; Developer Product — сколько угодно раз.
  5. В Studio покупка тестовая, Robux не списываются.

Скрипты

OpenCloseLocal

Где: StarterGui → PassGui → OpenCloseButton · LocalScript
Зачем: Открывает и закрывает окно пропусков.

-- кнопка «Open Passes»
local button = script.Parent
-- окно пропусков
local frame = button.Parent:WaitForChild("PassFrame")

-- нажали
button.Activated:Connect(function()
    -- было скрыто — показываем, и наоборот
    frame.Visible = not frame.Visible
    -- окно открыто
    if frame.Visible then
        -- кнопка закроет
        button.Text = "Close Passes"
    -- окно закрыто
    else
        -- кнопка откроет
        button.Text = "Open Passes"
    -- конец проверки
    end
-- конец обработчика
end)

PassPurchaseLocal

Где: StarterGui → PassGui → PassFrame → CandyMultiplier · LocalScript
Зачем: Показывает окно покупки пропуска.

-- сервис покупок
local MpS = game:GetService("MarketplaceService")
-- кнопка пропуска
local button = script.Parent
-- этот игрок
local player = game.Players.LocalPlayer
-- вставь ID своего пропуска
local PASS_ID = 0

-- нажали на пропуск
button.Activated:Connect(function()
    -- окно покупки Roblox; результат узнает сервер
    MpS:PromptGamePassPurchase(player, PASS_ID)
-- конец обработчика
end)

PassPurchaseServer

Где: ServerScriptService · Script
Зачем: Флажок HasPass: при входе — если пропуск куплен раньше, после покупки — сразу.

-- сервис покупок
local MpS = game:GetService("MarketplaceService")
-- вставь тот же ID пропуска
local PASS_ID = 0

-- проверяет, куплен ли пропуск раньше
local function CheckPass(player)
    -- защищённый вызов: сеть может подвести
    local success, owns = pcall(function()
        -- есть ли пропуск у игрока
        return MpS:UserOwnsGamePassAsync(player.UserId, PASS_ID)
    -- конец защищённого вызова
    end)
    -- проверка прошла и пропуск есть
    if success and owns then
        -- включаем бонус
        player.HasPass.Value = true
    -- сервис недоступен
    elseif not success then
        -- причина — в Output
        warn(owns)
    -- конец проверки
    end
-- конец функции
end

-- игрок зашёл
game.Players.PlayerAdded:Connect(function(player)
    -- флажок «пропуск куплен»
    local hasPass = Instance.new("BoolValue", player)
    -- называем HasPass
    hasPass.Name = "HasPass"
    -- покупал раньше — бонус сразу
    CheckPass(player)
-- конец обработчика
end)

-- окно покупки закрылось
MpS.PromptGamePassPurchaseFinished:Connect(function(player, passId, purchased)
    -- игрок действительно купил этот пропуск
    if purchased and passId == PASS_ID then
        -- бонус с этой секунды
        player.HasPass.Value = true
    -- конец проверки
    end
-- конец обработчика
end)

CandyDropperScript

Где: ServerStorage → Conveyors → CandyDropper · Script
Зачем: У владельца с пропуском цена конфеты ×2.

-- модель конвейера
local candyDropper = script.Parent
-- производство: CandyDropper → Owned_Items → IndustryModel
local tycoon = candyDropper.Parent.Parent
-- папка для упавших предметов
local droppedFolder = tycoon.Dropped_Items
-- касса производства
local gainValue = tycoon.Values.Gain
-- точка, где появляется предмет
local spawnPart = candyDropper.SpawnPart
-- корзина в конце ленты
local catcher = candyDropper:WaitForChild("Catcher")
-- серверное хранилище
local SS = game:GetService("ServerStorage")
-- образец предмета
local candy = SS.ItemsToDrop:WaitForChild("Candy")
-- удаление по таймеру
local Debris = game:GetService("Debris")
-- секунд между предметами
local rate = script.Rate
-- надбавка к цене каждого предмета
local gainBonus = script.GainBonus

-- ×2, если у владельца куплен пропуск
local function PassMultiplier()
    -- владелец — узнаём в момент оплаты, он мог смениться
    local owner = tycoon.Values.Owner.Value
    -- владелец есть и пропуск у него куплен
    if owner and owner:FindFirstChild("HasPass") and owner.HasPass.Value then
        -- двойной доход
        return 2
    -- конец проверки
    end
    -- обычный доход
    return 1
-- конец функции
end

-- каждые Rate секунд (меняется улучшением)
while task.wait(rate.Value) do
    -- копируем предмет
    local candyClone = candy:Clone()
    -- ставим над лентой
    candyClone.Position = spawnPart.Position
    -- кладём в мир
    candyClone.Parent = droppedFolder
    -- упал мимо ленты — сам исчезнет через 30 с
    Debris:AddItem(candyClone, 30)
    -- за этот предмет ещё не платили
    local paid = false
    -- следим за касаниями предмета
    candyClone.Touched:Connect(function(otherPart)
        -- предмет в корзине, оплаты ещё не было
        if otherPart == catcher and not paid then
            -- платим один раз
            paid = true
            -- цена предмета — в кассу
            gainValue.Value += candyClone.Gain.Value * PassMultiplier() + gainBonus.Value
            -- пауза 1 секунда
            task.wait(1)
            -- удаляем предмет
            candyClone:Destroy()
        -- конец проверки
        end
    -- конец обработчика касания
    end)
-- следующий предмет
end

Проверка

Запусти Play (или Run) и убедись: