Roblox · Аркада · урок 1

Аркада: арена и камера сверху

Аркада — короткие быстрые раунды, очки и рекорды. Сегодня — арена, камера сверху и персонаж, который всегда смотрит на курсор.

Структура

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

Workspace
├─ Arena (Folder)
│  ├─ Floor (Part) — пол 120 × 120
│  └─ Wall (Part) — четыре стены по краям
└─ SpawnLocation (SpawnLocation) — в центре
StarterPlayer → StarterPlayerScripts
└─ CameraLocal (LocalScript)
StarterPlayer → StarterCharacterScripts
└─ AimLocal (LocalScript)

Шаги

  1. Первая аркада — Computer Space (1971). Черты жанра: короткие уровни, очки за действия, рекорды, нарастающая сложность.
  2. Арена: пол «Floor» 120 × 120 и четыре стены «Wall» по краям, все Anchored, — в папке Workspace → «Arena». SpawnLocation в центре.
  3. CameraLocal (StarterPlayerScripts): камера Scriptable каждый кадр висит над персонажем. BindToRenderStep с приоритетом Camera + 1 — после стандартной камеры, чтобы она не перебивала.
  4. Камера чуть сдвинута назад (BACK = 25): строго сверху Roblox не понимает, где «вперёд», и W работала бы странно.
  5. AimLocal: персонаж поворачивается к точке под курсором (CFrame.lookAt по полу). AutoRotate выключен — иначе Humanoid сам поворачивает его по ходу движения.
  6. В Алгоритмике персонаж был кораблём на VectorForce: улетал от столкновений и не работал на телефоне. Корабль можно оставить как внешний вид — StarterCharacter (Безопасное лобби в «Королевской битве»).

Скрипты

CameraLocal

Где: StarterPlayer → StarterPlayerScripts · LocalScript
Зачем: Камера сверху.

-- каждый кадр
local RunService = game:GetService("RunService")
-- игроки
local Players = game:GetService("Players")
-- этот игрок
local player = Players.LocalPlayer
-- камера
local camera = workspace.CurrentCamera
-- высота камеры
local HEIGHT = 60
-- сдвиг назад — видно немного в перспективе, а «вперёд» = вверх экрана
local BACK = 25

-- после стандартной камеры
RunService:BindToRenderStep("TopCamera", Enum.RenderPriority.Camera.Value + 1, function()
    -- центр персонажа
    local root = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
    -- персонажа ещё нет
    if not root then return end
    -- камерой управляет скрипт
    camera.CameraType = Enum.CameraType.Scriptable
    -- сверху смотрим на игрока
    camera.CFrame = CFrame.lookAt(root.Position + Vector3.new(0, HEIGHT, BACK), root.Position)
-- конец функции
end)

AimLocal

Где: StarterPlayer → StarterCharacterScripts · LocalScript
Зачем: Взгляд на курсор.

-- каждый кадр
local RunService = game:GetService("RunService")
-- есть ли мышь
local UIS = game:GetService("UserInputService")
-- игроки
local Players = game:GetService("Players")
-- персонаж
local character = script.Parent
-- Humanoid
local humanoid = character:WaitForChild("Humanoid")
-- центр
local root = character:WaitForChild("HumanoidRootPart")
-- курсор
local mouse = Players.LocalPlayer:GetMouse()
-- курсор не цепляется за самого себя
mouse.TargetFilter = character
-- телефон без мыши
local touchOnly = UIS.TouchEnabled and not UIS.MouseEnabled
-- с мышью поворачиваем сами, на телефоне — куда идёт
humanoid.AutoRotate = touchOnly

-- каждый кадр
RunService.RenderStepped:Connect(function()
    -- телефон или погиб
    if touchOnly or humanoid.Health <= 0 then return end
    -- точка под курсором
    local hit = mouse.Hit.Position
    -- смотрим на курсор, не наклоняясь
    root.CFrame = CFrame.lookAt(root.Position, Vector3.new(hit.X, root.Position.Y, hit.Z))
-- конец функции
end)

Проверка

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