Roblox · Королевская битва · урок 4
Большую карту долго бегать — вертолёт: E/Q — вверх/вниз, W/S — вперёд/назад, A/D — поворот, пробел — выйти. Лопасти крутятся мотором HingeConstraint.
Синим — что добавляем на этом уроке.
Workspace └─ Helicopter (Model) — все детали Anchored выкл., приварены к Body ├─ Body (Part) — корпус (PrimaryPart) ├─ VehicleSeat (VehicleSeat) — приварен к Body, смотрит вперёд ├─ MainBlades (Part) — Attachment → HingeConstraint (Motor) → Body ├─ BackBlades (Part) — так же, ось вбок └─ HelicopterServer (Script) StarterPlayer → StarterCharacterScripts └─ HelicopterLocal (LocalScript)
Где: Workspace → Helicopter · Script
Зачем: Пилот, силы, лопасти.
-- игроки
local Players = game:GetService("Players")
-- модель Helicopter
local heli = script.Parent
-- кресло пилота
local seat = heli:WaitForChild("VehicleSeat")
-- моторы лопастей
local blades = {heli:WaitForChild("MainBlades"):WaitForChild("HingeConstraint"), heli:WaitForChild("BackBlades"):WaitForChild("HingeConstraint")}
-- скорость вращения лопастей
local BLADE_SPEED = 25
-- точка, к которой приложены силы
local attachment = Instance.new("Attachment")
-- имя
attachment.Name = "FlyAttachment"
-- в кресло
attachment.Parent = seat
-- держит скорость вертолёта
local move = Instance.new("LinearVelocity")
-- имя — его ищет HelicopterLocal
move.Name = "Move"
-- за кресло
move.Attachment0 = attachment
-- сильнее гравитации и веса
move.MaxForce = 10000000
-- висит на месте
move.VectorVelocity = Vector3.zero
-- пока пилота нет — выключено
move.Enabled = false
-- в кресло
move.Parent = seat
-- держит поворот: не кувыркается
local turn = Instance.new("AlignOrientation")
-- имя — его ищет HelicopterLocal
turn.Name = "Turn"
-- к заданному направлению
turn.Mode = Enum.OrientationAlignmentMode.OneAttachment
-- за кресло
turn.Attachment0 = attachment
-- сильно
turn.MaxTorque = 10000000
-- поворачивает плавно
turn.Responsiveness = 15
-- пока пилота нет — выключено
turn.Enabled = false
-- в кресло
turn.Parent = seat
-- сел или встал
seat:GetPropertyChangedSignal("Occupant"):Connect(function()
-- кто сидит
local humanoid = seat.Occupant
-- игрок
local player = humanoid and Players:GetPlayerFromCharacter(humanoid.Parent)
-- пилот сел
if player then
-- куда смотрит вертолёт
local _, yaw = seat.CFrame:ToOrientation()
-- держим ровно в эту сторону
turn.CFrame = CFrame.Angles(0, yaw, 0)
-- висим
move.VectorVelocity = Vector3.zero
-- силы включены
move.Enabled = true
-- поворот включён
turn.Enabled = true
-- лопасти крутятся
for _, hinge in ipairs(blades) do hinge.AngularVelocity = BLADE_SPEED end
-- физику вертолёта считает компьютер пилота — без задержек
seat:SetNetworkOwner(player)
-- пилот вышел
else
-- силы выключены — вертолёт падает и садится
move.Enabled = false
-- поворот выключен
turn.Enabled = false
-- лопасти останавливаются
for _, hinge in ipairs(blades) do hinge.AngularVelocity = 0 end
-- физику снова считает сервер
seat:SetNetworkOwner(nil)
-- конец проверки
end
-- конец функции
end)Где: StarterPlayer → StarterCharacterScripts · LocalScript
Зачем: Управление.
-- привязка клавиш к действиям
local CAS = game:GetService("ContextActionService")
-- каждый кадр
local RunService = game:GetService("RunService")
-- игроки
local Players = game:GetService("Players")
-- этот игрок
local player = Players.LocalPlayer
-- Humanoid персонажа
local humanoid = script.Parent:WaitForChild("Humanoid")
-- скорость вперёд-назад
local SPEED = 45
-- скорость вверх-вниз
local UP_SPEED = 18
-- поворот, радиан в секунду
local TURN_SPEED = 1.5
-- действие → клавиша
local ACTIONS = {
-- вверх, вниз
HeliUp = Enum.KeyCode.E, HeliDown = Enum.KeyCode.Q,
-- вперёд, назад
HeliForward = Enum.KeyCode.W, HeliBack = Enum.KeyCode.S,
-- поворот
HeliLeft = Enum.KeyCode.A, HeliRight = Enum.KeyCode.D,
-- конец таблицы
}
-- какие действия сейчас зажаты
local held = {}
-- кресло вертолёта, если сидим
local seat = nil
-- куда повёрнут вертолёт
local yaw = 0
-- дальность камеры до посадки
local oldZoom = player.CameraMaxZoomDistance
-- нажали или отпустили клавишу действия
local function OnAction(name, state)
-- зажата?
held[name] = state == Enum.UserInputState.Begin
-- клавиша больше никуда не идёт
return Enum.ContextActionResult.Sink
-- конец функции
end
-- включить или выключить управление
local function Bind(on)
-- каждое действие
for name, key in pairs(ACTIONS) do
-- привязать / отвязать (false — без кнопки на телефоне)
if on then CAS:BindAction(name, OnAction, false, key) else CAS:UnbindAction(name) end
-- конец перебора
end
-- ничего не зажато
table.clear(held)
-- конец функции
end
-- 1, -1 или 0 по двум клавишам
local function Axis(plus, minus)
-- обе зажаты — 0
return (held[plus] and 1 or 0) - (held[minus] and 1 or 0)
-- конец функции
end
-- сел или встал
humanoid.Seated:Connect(function(active, seatPart)
-- сел в вертолёт
if active and seatPart and seatPart:IsA("VehicleSeat") and seatPart.Parent.Name == "Helicopter" then
-- запоминаем
seat = seatPart
-- куда смотрит
local _, y = seat.CFrame:ToOrientation()
-- начальный поворот
yaw = y
-- запоминаем камеру
oldZoom = player.CameraMaxZoomDistance
-- камеру можно отдалить — видно вертолёт
player.CameraMaxZoomDistance = 60
-- управление
Bind(true)
-- вышел (пробел) или погиб
elseif seat then
-- не в вертолёте
seat = nil
-- камера как была
player.CameraMaxZoomDistance = oldZoom
-- клавиши свободны
Bind(false)
-- конец проверки
end
-- конец функции
end)
-- каждый кадр
RunService.RenderStepped:Connect(function(dt)
-- не летим
if not seat then return end
-- скорость (создаёт HelicopterServer)
local move = seat:FindFirstChild("Move")
-- поворот
local turn = seat:FindFirstChild("Turn")
-- вертолёт без скрипта
if not move or not turn then return end
-- D — вправо, A — влево
yaw -= Axis("HeliRight", "HeliLeft") * TURN_SPEED * dt
-- направление вертолёта
local facing = CFrame.Angles(0, yaw, 0)
-- поворачиваем
turn.CFrame = facing
-- вперёд-назад и вверх-вниз
move.VectorVelocity = facing.LookVector * Axis("HeliForward", "HeliBack") * SPEED + Vector3.new(0, Axis("HeliUp", "HeliDown") * UP_SPEED, 0)
-- конец функции
end)Запусти Play (или Run) и убедись: