Практикум — королевская битва на Roblox

Roblox

Продолжение маршрута после обби: цикл лобби → отсчёт → бой → победитель, оружие с Raycast на клиенте для визуала и повторной проверкой на сервере. API — workspace:Raycast, Luau и task.*.


Что вы освоите

Тема Навык
Игровой цикл раундов Lobby / Intermission / Combat / Winner
Минимум игроков MIN_PLAYERS, ожидание в while
Таблица участников competitors фиксируется на старт раунда
Конфиг оружия ModuleScript Settings в Tool
Raycast Клиент стреляет лучом; сервер сверяет угол и дистанцию
Headshot Множитель урона по Head
Локальная репликация Replicate RemoteEvent — трассер и звук

Структура проекта

ServerScriptService
├── ServerHandler
│   ├── Data
│   ├── GameRunner
│   └── Weapons
ReplicatedStorage
├── Remotes
│   ├── Hit        (RemoteEvent — заявка о попадании)
│   └── Replicate  (RemoteEvent — VFX для всех)
├── Tools
│   └── Blaster    (Tool + ModuleScript Settings + LocalScript ToolHandler)
Workspace
└── Effects        (папка для временных Part трассеров)
StarterGui
└── RoundHUD       (фаза, таймер)

Модуль GameRunner

Data для BR — те же Coins / Wins / Kills, что в обби; ключ DataStore смените, чтобы не смешивать тестовые данные.


Конфиг оружия

Tool/Settings (ModuleScript):

Поле Смысл
rateOfFire Выстрелов в минуту; пауза 60 / rateOfFire
range Длина луча в студах
fireMode AUTO — цикл при зажатой кнопке

Клиент — ToolHandler и Raycast

Replicate.OnClientEvent на всех клиентах создаёт короткий Part-трассер в workspace.Effects и удаляет через Debris.


Сервер — verifyHit и урон

Клиент присылает hit, origin, direction, relCFrame. Сервер не доверяет hit слепо:

Подключение:

Hit.OnServerEvent:Connect(function(player, tool, hit, direction, origin, relCFrame)
    local settings = require(tool:WaitForChild("Settings"))
    if not Weapons.verifyHit(player, tool, hit, direction, origin, relCFrame, settings) then
        return
    end
    Weapons.applyDamage(player, hit, settings)
end)
Серверный Raycast

В продакшене часто делают второй workspace:Raycast на сервере из origin по direction и сравнивают цель с ответом клиента. Это дороже по CPU, но устойчивее к подмене hit.


Локальная репликация VFX

Что Где
Трассер, дым, звук выстрела Клиент стрелка + Replicate для остальных
TakeDamage Только сервер
UI попадания FireClient жертве после applyDamage

Подробнее о репликации — Разработка на Roblox.


HUD раунда

RoundStatus.OnClientEvent обновляет TextLabel:

RoundStatus.OnClientEvent:Connect(function(phase: string, seconds: number)
    if phase == "Intermission" then
        label.Text = "Старт через " .. seconds
    elseif phase == "Combat" then
        label.Text = "Бой!"
    elseif phase == "Winner" then
        label.Text = "Победитель определён"
    end
end)

Тестирование

Сценарий Ожидание
1 игрок Раунд ждёт MIN_PLAYERS
2 клиента Урон только через сервер; убийство засчитывается
Выход mid-round competitors не ломает подсчёт живых
Headshot Урон x headshotMultiplier только при hit.Name == "Head"

Чек-лист

  • GameRunner проходит полный цикл Waiting → Combat → Winner
  • Settings в Tool, Debounce на Tool
  • Клиент использует RaycastParams, не устаревший FindPartOnRay
  • verifyHit отсекает неверный угол и дистанцию
  • Урон и Kills только на сервере
  • VFX через Replicate, без локального TakeDamage

См. также