Roblox · Сбор-а-тон · урок 4

Описание и поиск

Клик по картинке открывает описание предмета, а строка поиска оставляет в журнале только подходящие.

Структура

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

StarterGui
└─ ListGui (ScreenGui)
   ├─ ListFrame (Frame)
   │  └─ SearchBox (TextBox) — PlaceholderText «Поиск…»
   ├─ DescriptionFrame (Frame) — Visible выкл.
   │  ├─ Title (TextLabel)
   │  ├─ Body (TextLabel) — TextWrapped вкл.
   │  └─ CloseButton (TextButton)
   └─ ListLocal (LocalScript) — дополнили

Шаги

  1. В ListFrame — TextBox «SearchBox»: Text пустой, PlaceholderText «Поиск…», ClearTextOnFocus выкл.
  2. В ListGui — Frame «DescriptionFrame» (Visible выкл.): TextLabel «Title», TextLabel «Body» (TextWrapped вкл.), «CloseButton».
  3. Описание берётся из StringValue «Description» внутри предмета. Пока предмет не найден — вместо описания загадка.
  4. Поиск: string.find с четвёртым аргументом true — ищем просто текст. Без него «.» или «(» в запросе ломают поиск.
  5. Функция Lower делает строчными и русские буквы — обычный string.lower меняет только латиницу. Поиск «КЛЮЧ» найдёт «Старый ключ».

Скрипты

ListLocal

Где: StarterGui → ListGui · LocalScript
Зачем: Журнал с описанием и поиском.

-- игроки
local Players = game:GetService("Players")
-- этот игрок
local player = Players.LocalPlayer
-- все предметы
local items = workspace:WaitForChild("Items")
-- что игрок уже нашёл
local found = player:WaitForChild("Found")
-- ListGui
local gui = script.Parent
-- кнопка журнала
local listButton = gui:WaitForChild("ListButton")
-- журнал
local listFrame = gui:WaitForChild("ListFrame")
-- список с прокруткой
local scrolling = listFrame:WaitForChild("ScrollingList")
-- шаблон карточки
local sample = scrolling:WaitForChild("Sample")
-- «Найдено: 2 / 6»
local progress = listFrame:WaitForChild("Progress")
-- поиск
local searchBox = listFrame:WaitForChild("SearchBox")
-- окно описания
local description = gui:WaitForChild("DescriptionFrame")
-- цвет сложности
local COLORS = {Easy = Color3.fromRGB(80, 220, 100), Medium = Color3.fromRGB(255, 150, 40), Hard = Color3.fromRGB(240, 60, 60)}
-- лёгкие — первыми
local ORDER = {Easy = 1, Medium = 2, Hard = 3}
-- найденная карточка
local FOUND_COLOR = Color3.fromRGB(150, 230, 120)
-- ещё не найденная
local HIDDEN_COLOR = Color3.fromRGB(60, 60, 75)
-- имя предмета → карточка
local cards = {}

-- перекрасить карточки и обновить счёт
local function Refresh()
    -- сколько найдено
    local count = 0
    -- каждая карточка
    for name, card in pairs(cards) do
        -- найден ли предмет
        local isFound = found:FindFirstChild(name) ~= nil
        -- цвет
        card.BackgroundColor3 = isFound and FOUND_COLOR or HIDDEN_COLOR
        -- считаем
        if isFound then count += 1 end
    -- конец перебора
    end
    -- счёт
    progress.Text = "Найдено: " .. count .. " / " .. #items:GetChildren()
-- конец функции
end

-- строчные буквы, включая русские
local function Lower(text)
    -- буквы результата
    local out = {}
    -- каждая буква по номеру
    for _, code in utf8.codes(text) do
        -- А…Я
        if code >= 1040 and code <= 1071 then
            -- → а…я
            code += 32
        -- Ё
        elseif code == 1025 then
            -- → ё
            code = 1105
        -- конец проверки
        end
        -- в результат
        table.insert(out, utf8.char(code))
    -- конец перебора
    end
    -- латиница — обычным lower
    return string.lower(table.concat(out))
-- конец функции
end

-- окно описания предмета
local function ShowDescription(item)
    -- StringValue с описанием
    local text = item:FindFirstChild("Description")
    -- название
    description.Title.Text = item.Name
    -- предмет найден
    if found:FindFirstChild(item.Name) then
        -- описание
        description.Body.Text = text and text.Value or ""
    -- ещё нет
    else
        -- загадка
        description.Body.Text = "Найди этот предмет, чтобы прочитать о нём."
    -- конец проверки
    end
    -- показываем
    description.Visible = true
-- конец функции
end

-- карточка на каждый предмет
for _, item in ipairs(items:GetChildren()) do
    -- копия шаблона
    local card = sample:Clone()
    -- имя
    card.Name = item.Name
    -- подпись
    card.ItemName.Text = item.Name
    -- картинка предмета
    local decal = item:FindFirstChildOfClass("Decal")
    -- на кнопку
    card.ItemImage.Image = decal and decal.Texture or ""
    -- фон — цвет предмета
    if item:IsA("BasePart") then card.ItemImage.BackgroundColor3 = item.Color end
    -- сложность
    local difficulty = item:FindFirstChild("Difficulty")
    -- Easy, если не указана
    local level = difficulty and difficulty.Value or "Easy"
    -- полоска цвета сложности
    card.Difficulty.BackgroundColor3 = COLORS[level] or COLORS.Easy
    -- порядок в списке
    card.LayoutOrder = ORDER[level] or 1
    -- шаблон был скрыт
    card.Visible = true
    -- в список
    card.Parent = scrolling
    -- запоминаем
    cards[item.Name] = card
    -- клик — описание
    card.ItemImage.MouseButton1Click:Connect(function() ShowDescription(item) end)
-- конец перебора
end

-- нашёл новый — обновляем
found.ChildAdded:Connect(Refresh)
-- сразу при входе
Refresh()
-- кнопка журнала
listButton.MouseButton1Click:Connect(function()
    -- открыть / закрыть
    listFrame.Visible = not listFrame.Visible
-- конец функции
end)
-- закрыть описание
description.CloseButton.MouseButton1Click:Connect(function()
    -- прячем
    description.Visible = false
-- конец функции
end)
-- ввели текст в поиск
searchBox:GetPropertyChangedSignal("Text"):Connect(function()
    -- что ищем
    local query = Lower(searchBox.Text)
    -- каждая карточка
    for name, card in pairs(cards) do
        -- plain = true: точки и скобки — просто символы
        card.Visible = query == "" or string.find(Lower(name), query, 1, true) ~= nil
    -- конец перебора
    end
-- конец функции
end)

Проверка

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