Roblox · Гонки · урок 3

Чекпоинты на трассе

Рамки-чекпоинты по трассе: проезжать их нужно строго по порядку, пройденная рамка зеленеет только у тебя. После падения с трассы появляешься у последнего пройденного чекпоинта.

Структура

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

Workspace
└─ Checkpoints (Folder)
   ├─ 1 (Model) — имя — только номер; PrimaryPart = Trigger
   │  ├─ Trigger (Part) — рамка: Anchored, CanCollide выкл., полупрозрачная
   │  └─ Pillar1, Pillar2, … (Part) — украшения (столбы, арка) — по желанию
   └─ 2, 3, … (Model) — такие же, по порядку вдоль трассы
ReplicatedStorage
└─ CheckpointEvent (RemoteEvent)
ServerScriptService
└─ CheckpointsServer (Script)
StarterPlayer
└─ StarterPlayerScripts
   └─ CheckpointsLocal (LocalScript)

Шаги

  1. Workspace → «+» → Folder «Checkpoints».
  2. В Checkpoints «+» → Model, назови 1 (только цифра). В неё «+» → Part «Trigger» — рамка поперёк дороги: широкая, высокая, тонкая; Anchored — вкл., CanCollide — выкл., Transparency ≈ 0.6 — видно, но трассу не загораживает.
  3. Украшения (столбы, арку, флажки) клади в ту же модель — скрипт смотрит только на Trigger. Выдели модель → PrimaryPart → Trigger.
  4. Скопируй модель целиком (Ctrl+D), назови 2 и поставь дальше по трассе. Номера строго по порядку. Ставь чекпоинты на поворотах — так трассу не срежут. Последний чекпоинт — на финише.
  5. ReplicatedStorage → «+» → RemoteEvent «CheckpointEvent».
  6. ServerScriptService → «+» → Script «CheckpointsServer»; StarterPlayer → StarterPlayerScripts → «+» → LocalScript «CheckpointsLocal» — тексты из «Скриптов».
  7. Как работает: у каждого игрока свой счётчик Index. Проехал рамку с номером Index + 1 — счётчик растёт, сервер сообщает только тебе, и рамка зеленеет у тебя. Касание засчитывается и персонажу, и машине, за рулём которой он сидит.

Скрипты

CheckpointsServer

Где: ServerScriptService · Script
Зачем: Считает пройденные чекпоинты каждого игрока по порядку и возрождает у последнего.

-- папка с чекпоинтами-моделями 1, 2, 3…
local checkpoints = workspace:WaitForChild("Checkpoints")
-- событие сервер → игрок
local checkpointEvent = game.ReplicatedStorage:WaitForChild("CheckpointEvent")

-- игрок зашёл
game.Players.PlayerAdded:Connect(function(player)
    -- номер последнего пройденного чекпоинта
    local index = Instance.new("IntValue")
    -- имя
    index.Name = "Index"
    -- ещё ничего не прошёл
    index.Value = 0
    -- храним в игроке
    index.Parent = player
    -- персонаж появился (в начале и после смерти)
    player.CharacterAdded:Connect(function(character)
        -- последний пройденный чекпоинт
        local last = checkpoints:FindFirstChild(tostring(index.Value))
        -- уже что-то прошёл
        if last then
            -- ждём, пока персонаж загрузится
            character:WaitForChild("HumanoidRootPart")
            -- ставим у последнего чекпоинта
            character:PivotTo(last.Trigger.CFrame + Vector3.new(0, 3, 0))
        -- конец проверки
        end
    -- конец обработчика
    end)
-- конец обработчика
end)

-- чей персонаж или чья машина коснулась
local function GetPlayer(otherPart)
    -- модель, в которой деталь
    local model = otherPart:FindFirstAncestorOfClass("Model")
    -- просто деталь
    if not model then return nil end
    -- это персонаж?
    local player = game.Players:GetPlayerFromCharacter(model)
    -- да
    if player then return player end
    -- это машина?
    local seat = model:FindFirstChildOfClass("VehicleSeat")
    -- за рулём кто-то есть
    if seat and seat.Occupant then
        -- водитель
        return game.Players:GetPlayerFromCharacter(seat.Occupant.Parent)
    -- конец проверки
    end
    -- не игрок
    return nil
-- конец функции
end

-- каждый чекпоинт
for _, checkpoint in pairs(checkpoints:GetChildren()) do
    -- рамка, сквозь которую проезжают
    local trigger = checkpoint:WaitForChild("Trigger")
    -- рамки что-то коснулось
    trigger.Touched:Connect(function(otherPart)
        -- кто это
        local player = GetPlayer(otherPart)
        -- не игрок — пропускаем
        if not player then return end
        -- его счётчик
        local index = player:FindFirstChild("Index")
        -- ещё не создан
        if not index then return end
        -- это следующий по порядку — пропустить нельзя
        if tonumber(checkpoint.Name) == index.Value + 1 then
            -- засчитываем
            index.Value += 1
            -- сообщаем игроку — у него рамка станет зелёной
            checkpointEvent:FireClient(player, trigger)
        -- конец проверки
        end
    -- конец обработчика
    end)
-- конец перебора
end

CheckpointsLocal

Где: StarterPlayer → StarterPlayerScripts · LocalScript
Зачем: Красит пройденную рамку в зелёный — только у себя.

-- событие от сервера
local checkpointEvent = game.ReplicatedStorage:WaitForChild("CheckpointEvent")

-- сервер засчитал чекпоинт
checkpointEvent.OnClientEvent:Connect(function(trigger)
    -- рамка зелёная — только у этого игрока
    trigger.BrickColor = BrickColor.new("Bright green")
-- конец обработчика
end)

Проверка

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