
KeylessUniversal

-- // Delta Executor - Drone com Comando Estilo DJI RC (v3 com Térmico e Bombas)
-- Só toque (telemóvel): joystick esquerdo = altura/girar | joystick direito = mover
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local Lighting = game:GetService("Lighting")
-- Se executares o script outra vez, limpa a versão anterior
local env = (getgenv and getgenv()) or _G
if env.__DroneCleanup then pcall(env.__DroneCleanup) end
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local rootPart = character:WaitForChild("HumanoidRootPart")
local camera = Workspace.CurrentCamera
if Workspace:FindFirstChild("RealisticDroneModel") then Workspace.RealisticDroneModel:Destroy() end
if player.PlayerGui:FindFirstChild("DJIRCControlGui") then player.PlayerGui.DJIRCControlGui:Destroy() end
-- Configuração
local SPEED, VSPEED, YAW_SPEED = 40, 25, 2.2
local DEFAULT_FOV = 70
-- Estado
local conns = {}
local flying, mode = false, "manual" -- manual | takeoff | rth | follow | land
local battery = 100
local yaw = 0
local curVel = Vector3.zero
local curTiltF, curTiltS = 0, 0
local rotorSpeed, rotorAngle = 0, 0
local cameraAttached, recording, recTime = false, false, 0
local fov = DEFAULT_FOV
local stickL, stickR = Vector2.zero, Vector2.zero
local rotors = {}
-- Efeitos extra
local thermalOn = false
local colorCorrection = Instance.new("ColorCorrectionEffect")
local function getHumanoid()
return character and character:FindFirstChildOfClass("Humanoid")
end
---------------------------------------------------------------------
-- 1. Modelo do drone
---------------------------------------------------------------------
local droneModel = Instance.new("Model")
droneModel.Name = "RealisticDroneModel"
droneModel.Parent = Workspace
local dronePart = Instance.new("Part")
dronePart.Name = "DroneCore"
dronePart.Size = Vector3.new(2, 0.6, 2.5)
dronePart.Material = Enum.Material.SmoothPlastic
dronePart.Color = Color3.fromRGB(55, 60, 65)
dronePart.CanCollide = false
dronePart.Parent = droneModel
droneModel.PrimaryPart = dronePart
-- Raycast para descobrir o chão
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {droneModel, character}
local function groundY(pos)
local r = Workspace:Raycast(pos + Vector3.new(0, 1, 0), Vector3.new(0, -1000, 0), rayParams)
return r and r.Position.Y or nil
end
-- Posição inicial: no chão, à frente do jogador
local look = rootPart.CFrame.LookVector
local startPos = rootPart.Position + look * 4
local startGround = groundY(startPos + Vector3.new(0, 5, 0))
yaw = math.atan2(-look.X, -look.Z)
dronePart.CFrame = CFrame.new(startPos.X, (startGround or (rootPart.Position.Y - 2.5)) + 0.9, startPos.Z)
* CFrame.Angles(0, yaw, 0)
local function weldTo(p0, p1)
local w = Instance.new("Weld")
w.Part0 = p0
w.Part1 = p1
w.C0 = p0.CFrame:ToObjectSpace(p1.CFrame)
w.Parent = p0
return w
end
local function addPart(size, offset, color, material, shape)
local p = Instance.new("Part")
p.Size = size
p.CFrame = dronePart.CFrame * offset
p.Color = color
p.Material = material or Enum.Material.SmoothPlastic
if shape then p.Shape = shape end
p.CanCollide = false
p.Massless = true
p.Parent = droneModel
return p, weldTo(dronePart, p)
end
-- Câmara gimbal e sensores
addPart(Vector3.new(0.6, 0.5, 0.6), CFrame.new(0, -0.4, -1.2), Color3.fromRGB(20, 20, 20), Enum.Material.Metal)
addPart(Vector3.new(0.4, 0.4, 0.3), CFrame.new(0, -0.4, -1.45), Color3.fromRGB(0, 170, 255), Enum.Material.Glass)
addPart(Vector3.new(1.2, 0.3, 0.4), CFrame.new(0, 0.1, -1.25), Color3.fromRGB(35, 35, 35))
-- Luz do drone
local lightColors = {
Color3.fromRGB(0, 255, 255),
Color3.fromRGB(0, 255, 120),
Color3.fromRGB(255, 60, 60),
Color3.fromRGB(180, 80, 255),
Color3.fromRGB(255, 255, 255),
}
local lightIdx = 1
local lightOn = true
local lightPart = addPart(Vector3.new(0.4, 0.1, 0.4), CFrame.new(0, 0.35, 1.3), lightColors[1], Enum.Material.Neon)
local light = Instance.new("PointLight")
light.Color = lightColors[1]
light.Range = 15
light.Brightness = 4
light.Parent = lightPart
-- Braços, motores e hélices
for _, sx in ipairs({-1, 1}) do
for _, sz in ipairs({-1, 1}) do
local corner = Vector3.new(sx * 1.7, 0, sz * 1.7)
addPart(Vector3.new(0.3, 0.15, corner.Magnitude), CFrame.lookAt(corner / 2, corner),
Color3.fromRGB(70, 75, 80))
addPart(Vector3.new(0.4, 0.6, 0.6),
CFrame.new(corner + Vector3.new(0, 0.2, 0)) * CFrame.Angles(0, 0, math.rad(90)),
Color3.fromRGB(30, 30, 30), Enum.Material.Metal, Enum.PartType.Cylinder)
local blade, bw = addPart(Vector3.new(2.2, 0.05, 0.25),
CFrame.new(corner + Vector3.new(0, 0.45, 0)) * CFrame.Angles(0, math.rad(45), 0),
Color3.fromRGB(240, 130, 0), Enum.Material.Neon)
table.insert(rotors, {weld = bw, base = bw.C0, dir = (sx * sz > 0) and 1 or -1})
end
end
local bv = Instance.new("BodyVelocity")
bv.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
bv.Velocity = Vector3.zero
bv.Parent = dronePart
local bg = Instance.new("BodyGyro")
bg.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
bg.CFrame = dronePart.CFrame
bg.Parent = dronePart
---------------------------------------------------------------------
-- 2. Interface (Comando com mais espaço para os novos botões)
---------------------------------------------------------------------
local function make(class, props, parent)
local o = Instance.new(class)
for k, v in pairs(props) do o[k] = v end
o.Parent = parent
return o
end
local function roundify(o, r)
make("UICorner", {CornerRadius = UDim.new(0, r)}, o)
end
local screenGui = make("ScreenGui", {
Name = "DJIRCControlGui",
ResetOnSpawn = false,
IgnoreGuiInset = true,
}, player:WaitForChild("PlayerGui"))
-- Corpo do comando (ligeiramente mais alto para caber tudo)
local rcFrame = make("Frame", {
Size = UDim2.new(0, 300, 0, 244),
Position = UDim2.new(0, 10, 0, 50),
BackgroundColor3 = Color3.fromRGB(45, 48, 55),
BorderSizePixel = 0,
}, screenGui)
roundify(rcFrame, 14)
local topBar = make("Frame", {
Size = UDim2.new(1, 0, 0, 28),
BackgroundColor3 = Color3.fromRGB(35, 38, 44),
BorderSizePixel = 0,
}, rcFrame)
roundify(topBar, 14)
local ledStatus = make("TextLabel", {
Size = UDim2.new(1, -34, 1, 0),
BackgroundTransparency = 1,
Text = "🔋 100% [ DJI RC - LINKED ]",
TextColor3 = Color3.fromRGB(0, 255, 120),
TextSize = 11,
Font = Enum.Font.Code,
}, topBar)
local btnClose = make("TextButton", {
Size = UDim2.new(0, 24, 0, 24),
Position = UDim2.new(1, -28, 0, 2),
BackgroundColor3 = Color3.fromRGB(120, 30, 30),
TextColor3 = Color3.new(1, 1, 1),
Text = "X",
TextSize = 10,
Font = Enum.Font.GothamBold,
}, topBar)
roundify(btnClose, 4)
-- Ecrã do comando (telemetria)
local screenDisplay = make("Frame", {
Size = UDim2.new(1, -20, 0, 66),
Position = UDim2.new(0, 10, 0, 34),
BackgroundColor3 = Color3.fromRGB(15, 15, 20),
BorderSizePixel = 0,
}, rcFrame)
roundify(screenDisplay, 8)
local screenLabel = make("TextLabel", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
Text = "🏔️ DRONE 4K\n[ Pronto para descolar ]",
TextColor3 = Color3.fromRGB(200, 220, 255),
TextSize = 12,
Font = Enum.Font.GothamBold,
}, screenDisplay)
-- Botões Grid
local btnContainer = make("Frame", {
Size = UDim2.new(1, -16, 0, 132),
Position = UDim2.new(0, 8, 0, 106),
BackgroundTransparency = 1,
}, rcFrame)
make("UIGridLayout", {
CellSize = UDim2.new(0, 66, 0, 28),
CellPadding = UDim2.new(0, 5, 0, 4),
SortOrder = Enum.SortOrder.LayoutOrder,
}, btnContainer)
local btns, btnColors = {}, {}
local GRAY = Color3.fromRGB(80, 85, 95)
local function createRcBtn(name, text, off, on, order)
local b = make("TextButton", {
BackgroundColor3 = off,
TextColor3 = Color3.new(1, 1, 1),
Text = text,
TextSize = 10,
Font = Enum.Font.GothamBold,
LayoutOrder = order,
}, btnContainer)
roundify(b, 6)
btns[name] = b
btnColors[b] = {off = off, on = on or off}
return b
end
local function setBtn(b, isOn)
b.BackgroundColor3 = isOn and btnColors[b].on or btnColors[b].off
end
createRcBtn("fly", "🚀 Voar", Color3.fromRGB(0, 110, 200), Color3.fromRGB(0, 180, 90), 1)
createRcBtn("cam", "👁️ Câmara", Color3.fromRGB(40, 140, 70), Color3.fromRGB(200, 90, 0), 2)
createRcBtn("rth", "🏠 Casa", Color3.fromRGB(0, 120, 130), Color3.fromRGB(0, 200, 210), 3)
createRcBtn("follow", "🎯 Seguir", Color3.fromRGB(110, 60, 170), Color3.fromRGB(170, 90, 240), 4)
createRcBtn("zin", "➕ Zoom", GRAY, nil, 5)
createRcBtn("zout", "➖ Zoom", GRAY, nil, 6)
createRcBtn("photo", "📸 Foto", GRAY, nil, 7)
createRcBtn("rec", "🔴 REC", Color3.fromRGB(120, 40, 40), Color3.fromRGB(220, 30, 30), 8)
createRcBtn("light", "💡 Luz", Color3.fromRGB(150, 120, 0), Color3.fromRGB(230, 190, 0), 9)
createRcBtn("color", "🎨 Cor", GRAY, nil, 10)
createRcBtn("thermal", "🌡️ Térmico", Color3.fromRGB(40, 40, 80), Color3.fromRGB(255, 100, 0), 11)
createRcBtn("drop", "📦 Largar", Color3.fromRGB(130, 70, 0), Color3.fromRGB(200, 110, 0), 12)
createRcBtn("pull", "📍 Puxar", Color3.fromRGB(180, 110, 0), nil, 13)
createRcBtn("boom", "💥 Explodir", Color3.fromRGB(180, 40, 40), nil, 14)
setBtn(btns.light, true)
-- HUD de visão em primeira pessoa
local hudGui = make("Frame", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
Visible = false,
}, screenGui)
make("TextLabel", {
Size = UDim2.new(0, 40, 0, 40),
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.new(0.5, 0, 0.5, 0),
BackgroundTransparency = 1,
Text = "+",
TextColor3 = Color3.fromRGB(0, 255, 100),
TextSize = 35,
Font = Enum.Font.Code,
}, hudGui)
local hudRec = make("TextLabel", {
Size = UDim2.new(0, 220, 0, 28),
AnchorPoint = Vector2.new(0.5, 0),
Position = UDim2.new(0.5, 0, 0, 50),
BackgroundColor3 = Color3.new(0, 0, 0),
BackgroundTransparency = 0.4,
TextColor3 = Color3.fromRGB(0, 255, 100),
Text = "[ ⏺ STANDBY ]",
TextSize = 12,
Font = Enum.Font.Code,
}, hudGui)
roundify(hudRec, 6)
local hudTelemetry = make("TextLabel", {
Size = UDim2.new(0, 260, 0, 40),
AnchorPoint = Vector2.new(0.5, 1),
Position = UDim2.new(0.5, 0, 1, -12),
BackgroundColor3 = Color3.new(0, 0, 0),
BackgroundTransparency = 0.4,
TextColor3 = Color3.fromRGB(0, 255, 100),
Text = "",
TextSize = 11,
Font = Enum.Font.Code,
}, hudGui)
roundify(hudTelemetry, 6)
-- Flash de foto e aviso
local flash = make("Frame", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 1,
BorderSizePixel = 0,
ZIndex = 10,
}, screenGui)
local toastLabel = make("TextLabel", {
Size = UDim2.new(0, 220, 0, 30),
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.new(0.5, 0, 0.7, 0),
BackgroundColor3 = Color3.new(0, 0, 0),
BackgroundTransparency = 0.3,
TextColor3 = Color3.new(1, 1, 1),
Text = "",
TextSize = 13,
Font = Enum.Font.GothamBold,
Visible = false,
ZIndex = 11,
}, screenGui)
roundify(toastLabel, 8)
local toastId = 0
local function toast(msg)
toastId += 1
local id = toastId
toastLabel.Text = msg
toastLabel.Visible = true
task.delay(1.8, function()
if id == toastId and toastLabel.Parent then toastLabel.Visible = false end
end)
end
-- Joysticks táteis
local function makeStick(pos, caption, callback)
local base = make("Frame", {
Size = UDim2.new(0, 100, 0, 100),
AnchorPoint = Vector2.new(0.5, 0.5),
Position = pos,
BackgroundColor3 = Color3.fromRGB(20, 20, 25),
BackgroundTransparency = 0.5,
BorderSizePixel = 0,
Active = true,
}, screenGui)
roundify(base, 50)
make("TextLabel", {
Size = UDim2.new(1, 0, 0, 14),
Position = UDim2.new(0, 0, 0, -16),
BackgroundTransparency = 1,
Text = caption,
TextColor3 = Color3.new(1, 1, 1),
TextSize = 10,
Font = Enum.Font.GothamBold,
}, base)
local knob = make("Frame", {
Size = UDim2.new(0, 40, 0, 40),
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.new(0.5, 0, 0.5, 0),
BackgroundColor3 = Color3.fromRGB(230, 230, 235),
BackgroundTransparency = 0.2,
BorderSizePixel = 0,
}, base)
roundify(knob, 20)
local active
local function update(p)
local center = base.AbsolutePosition + base.AbsoluteSize / 2
local maxR = base.AbsoluteSize.X / 2 - 8
local delta = Vector2.new(p.X, p.Y) - center
if delta.Magnitude > maxR then delta = delta.Unit * maxR end
knob.Position = UDim2.new(0.5, delta.X, 0.5, delta.Y)
callback(Vector2.new(delta.X / maxR, -delta.Y / maxR))
end
local function reset()
active = nil
knob.Position = UDim2.new(0.5, 0, 0.5, 0)
callback(Vector2.zero)
end
base.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch
or input.UserInputType == Enum.UserInputType.MouseButton1 then
active = input
update(input.Position)
end
end)
table.insert(conns, UserInputService.InputChanged:Connect(function(input)
if not active then return end
if input == active
or (active.UserInputType == Enum.UserInputType.MouseButton1
and input.UserInputType == Enum.UserInputType.MouseMovement) then
update(input.Position)
end
end))
table.insert(conns, UserInputService.InputEnded:Connect(function(input)
if input == active then reset() end
end))
end
makeStick(UDim2.new(0, 80, 1, -65), "ALTURA / GIRAR", function(v) stickL = v end)
makeStick(UDim2.new(1, -80, 1, -65), "MOVER", function(v) stickR = v end)
-- Arrastar o comando pela barra superior
do
local dragging, dragStart, startPos2
topBar.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
or input.UserInputType == Enum.UserInputType.Touch then
dragging = input
dragStart = input.Position
startPos2 = rcFrame.Position
end
end)
table.insert(conns, UserInputService.InputChanged:Connect(function(input)
if dragging and (input == dragging
or (dragging.UserInputType == Enum.UserInputType.MouseButton1
and input.UserInputType == Enum.UserInputType.MouseMovement)) then
local d = input.Position - dragStart
rcFrame.Position = UDim2.new(startPos2.X.Scale, startPos2.X.Offset + d.X,
startPos2.Y.Scale, startPos2.Y.Offset + d.Y)
end
end))
table.insert(conns, UserInputService.InputEnded:Connect(function(input)
if input == dragging then dragging = nil end
end))
end
---------------------------------------------------------------------
-- 3. Lógica
---------------------------------------------------------------------
local function cleanup()
for _, c in ipairs(conns) do pcall(function() c:Disconnect() end) end
table.clear(conns)
pcall(function()
camera.CameraType = Enum.CameraType.Custom
camera.FieldOfView = DEFAULT_FOV
local hum = getHumanoid()
if hum then camera.CameraSubject = hum end
end)
colorCorrection.Parent = nil
if droneModel then droneModel:Destroy() end
if screenGui then screenGui:Destroy() end
env.__DroneCleanup = nil
end
env.__DroneCleanup = cleanup
local function refreshFlyBtn()
btns.fly.Text = flying and "🛬 Pousar" or "🚀 Voar"
setBtn(btns.fly, flying)
end
local function setMode(m)
mode = m
setBtn(btns.rth, m == "rth")
setBtn(btns.follow, m == "follow")
end
local function homePos()
return rootPart.Position + rootPart.CFrame.LookVector * 5 + Vector3.new(0, 8, 0)
end
local function followPos()
return rootPart.Position - rootPart.CFrame.LookVector * 6 + Vector3.new(0, 5, 0)
end
local function faceDir(v, dt)
if v.Magnitude < 0.1 then return end
local target = math.atan2(-v.X, -v.Z)
local diff = (target - yaw + math.pi) % (2 * math.pi) - math.pi
yaw = yaw + diff * math.min(1, dt * 4)
end
local function takePhoto()
flash.BackgroundTransparency = 0.1
TweenService:Create(flash, TweenInfo.new(0.4), {BackgroundTransparency = 1}):Play()
toast("📸 Foto guardada")
end
-- Botões de Ação
btns.fly.MouseButton1Click:Connect(function()
if flying then
if mode ~= "land" then setMode("land") end
else
if battery < 5 then
toast("🔋 Bateria demasiado baixa")
return
end
flying = true
setMode("takeoff")
refreshFlyBtn()
end
end)
btns.cam.MouseButton1Click:Connect(function()
cameraAttached = not cameraAttached
hudGui.Visible = cameraAttached
setBtn(btns.cam, cameraAttached)
btns.cam.Text = cameraAttached and "👤 Jogador" or "👁️ Câmara"
if cameraAttached then
camera.CameraType = Enum.CameraType.Scriptable
else
camera.CameraType = Enum.CameraType.Custom
camera.FieldOfView = DEFAULT_FOV
local hum = getHumanoid()
if hum then camera.CameraSubject = hum end
end
end)
btns.rth.MouseButton1Click:Connect(function()
if not flying then toast("O drone está no chão") return end
setMode(mode == "rth" and "manual" or "rth")
end)
btns.follow.MouseButton1Click:Connect(function()
if not flying then toast("O drone está no chão") return end
setMode(mode == "follow" and "manual" or "follow")
end)
btns.zin.MouseButton1Click:Connect(function() fov = math.max(20, fov - 10) end)
btns.zout.MouseButton1Click:Connect(function() fov = math.min(100, fov + 10) end)
btns.photo.MouseButton1Click:Connect(takePhoto)
btns.rec.MouseButton1Click:Connect(function()
recording = not recording
if recording then recTime = 0 end
btns.rec.Text = recording and "⏹ Parar" or "🔴 REC"
setBtn(btns.rec, recording)
toast(recording and "🔴 A gravar" or "⏹ Gravação guardada")
end)
btns.light.MouseButton1Click:Connect(function()
lightOn = not lightOn
light.Enabled = lightOn
lightPart.Material = lightOn and Enum.Material.Neon or Enum.Material.SmoothPlastic
setBtn(btns.light, lightOn)
end)
btns.color.MouseButton1Click:Connect(function()
lightIdx = lightIdx % #lightColors + 1
lightPart.Color = lightColors[lightIdx]
light.Color = lightColors[lightIdx]
btns.color.BackgroundColor3 = lightColors[lightIdx]:Lerp(Color3.new(0, 0, 0), 0.5)
end)
-- Nova Função: Térmico
btns.thermal.MouseButton1Click:Connect(function()
thermalOn = not thermalOn
setBtn(btns.thermal, thermalOn)
if thermalOn then
colorCorrection.TintColor = Color3.fromRGB(255, 120, 50)
colorCorrection.Contrast = 0.5
colorCorrection.Brightness = 0.1
colorCorrection.Parent = Lighting
toast("🌡️ Visão térmica ativa")
else
colorCorrection.Parent = nil
toast("🌡️ Visão normal")
end
end)
-- Nova Função: Largar Bomba
btns.drop.MouseButton1Click:Connect(function()
if not flying then
toast("O drone precisa de estar a voar")
return
end
local bomb = Instance.new("Part")
bomb.Size = Vector3.new(0.8, 0.8, 0.8)
bomb.Position = dronePart.Position - Vector3.new(0, 1, 0)
bomb.Material = Enum.Material.Neon
bomb.Color = Color3.fromRGB(255, 50, 50)
bomb.Shape = Enum.PartType.Ball
bomb.Parent = Workspace
local touchedConn
touchedConn = bomb.Touched:Connect(function(hit)
if hit ~= dronePart and hit.Parent ~= droneModel then
touchedConn:Disconnect()
local exp = Instance.new("Explosion")
exp.Position = bomb.Position
exp.BlastRadius = 8
exp.BlastPressure = 10000
exp.Parent = Workspace
bomb:Destroy()
end
end)
toast("📦 Carga largada!")
end)
btns.pull.MouseButton1Click:Connect(function()
local target = rootPart.Position + rootPart.CFrame.LookVector * 4
local y
if flying then
y = target.Y + 4
else
local gy = groundY(target + Vector3.new(0, 5, 0))
y = (gy or (target.Y - 2.5)) + 0.9
end
dronePart.CFrame = CFrame.new(target.X, y, target.Z) * CFrame.Angles(0, yaw, 0)
curVel = Vector3.zero
end)
btns.boom.MouseButton1Click:Connect(function()
if dronePart and dronePart.Parent then
local explosion = Instance.new("Explosion")
explosion.Position = dronePart.Position
explosion.BlastRadius = 18
explosion.BlastPressure = 500000
explosion.Parent = Workspace
cleanup()
end
end)
btnClose.MouseButton1Click:Connect(cleanup)
table.insert(conns, player.CharacterAdded:Connect(function(c)
character = c
rootPart = c:WaitForChild("HumanoidRootPart")
rayParams.FilterDescendantsInstances = {droneModel, c}
end))
local function getInput()
return stickL.X, stickL.Y, stickR.X, stickR.Y
end
local modeNames = {
manual = "MANUAL", takeoff = "A DESCOLAR", rth = "REGRESSAR A CASA",
follow = "A SEGUIR-TE", land = "A ATERRAR",
}
local uiTimer = 0
-- Ciclo principal
table.insert(conns, RunService.RenderStepped:Connect(function(dt)
if not dronePart.Parent then cleanup() return end
local pos = dronePart.Position
local gy = groundY(pos)
local minY = gy and (gy + 0.9) or -math.huge
local yawIn, vertIn, strafeIn, fwdIn = getInput()
local inputMag = math.abs(yawIn) + math.abs(vertIn) + math.abs(strafeIn) + math.abs(fwdIn)
local vel = Vector3.zero
local tiltF, tiltS = 0, 0
if flying then
battery = math.max(0, battery - dt * (0.5 + curVel.Magnitude / 80))
if battery <= 0 and mode ~= "land" then
setMode("land")
toast("🔋 Bateria vazia, a aterrar")
end
if inputMag > 0.2 and battery > 0 and (mode == "rth" or mode == "follow" or mode == "land") then
setMode("manual")
end
if mode == "takeoff" then
vel = Vector3.new(0, 8, 0)
if pos.Y - (gy or (pos.Y - 3)) >= 3 then setMode("manual") end
elseif mode == "manual" then
yaw = yaw - yawIn * dt * YAW_SPEED
local horiz = CFrame.Angles(0, yaw, 0):VectorToWorldSpace(
Vector3.new(strafeIn * SPEED, 0, -fwdIn * SPEED))
vel = horiz + Vector3.new(0, vertIn * VSPEED, 0)
tiltF, tiltS = fwdIn, strafeIn
elseif mode == "rth" then
local d = homePos() - pos
local flat = Vector3.new(d.X, 0, d.Z)
if flat.Magnitude > 3 then
vel = flat.Unit * math.min(SPEED, flat.Magnitude * 3)
+ Vector3.new(0, math.clamp(d.Y * 2, -VSPEED, VSPEED), 0)
faceDir(flat, dt)
tiltF = 0.6
else
setMode("land")
end
elseif mode == "follow" then
local d = followPos() - pos
vel = d * 3
if vel.Magnitude > SPEED * 1.1 then vel = vel.Unit * SPEED * 1.1 end
local toPlayer = rootPart.Position - pos
faceDir(Vector3.new(toPlayer.X, 0, toPlayer.Z), dt)
elseif mode == "land" then
vel = Vector3.new(0, -8, 0)
if gy and pos.Y <= minY + 0.15 then
flying = false
setMode("manual")
refreshFlyBtn()
toast("🛬 Aterrou")
end
end
if pos.Y <= minY and vel.Y < 0 then
vel = Vector3.new(vel.X, 0, vel.Z)
end
else
battery = math.min(100, battery + dt * 3)
end
curVel = curVel:Lerp(vel, math.min(1, dt * 5))
curTiltF = curTiltF + (tiltF - curTiltF) * math.min(1, dt * 6)
curTiltS = curTiltS + (tiltS - curTiltS) * math.min(1, dt * 6)
bv.Velocity = curVel
bg.CFrame = CFrame.Angles(0, yaw, 0) * CFrame.Angles(-curTiltF * 0.3, 0, -curTiltS * 0.3)
local targetRotor = flying and (45 + curVel.Magnitude * 0.5) or 0
rotorSpeed = rotorSpeed + (targetRotor - rotorSpeed) * math.min(1, dt * 3)
rotorAngle = rotorAngle + rotorSpeed * dt
for _, r in ipairs(rotors) do
r.weld.C0 = r.base * CFrame.Angles(0, rotorAngle * r.dir, 0)
end
if cameraAttached then
local gp = dronePart.CFrame:PointToWorldSpace(Vector3.new(0, -0.2, -1.7))
camera.CFrame = CFrame.new(gp) * CFrame.Angles(0, yaw, 0)
camera.FieldOfView = fov
end
if recording then recTime += dt end
uiTimer += dt
if uiTimer >= 0.1 then
uiTimer = 0
local alt = gy and (pos.Y - gy) or pos.Y
local dist = (pos - rootPart.Position).Magnitude
local zoomX = DEFAULT_FOV / fov
local bat = math.floor(battery)
local telemetry = string.format("ALT %dm VEL %d DIST %dm\n🔋 %d%% 🔍 x%.1f",
math.floor(alt), math.floor(curVel.Magnitude), math.floor(dist), bat, zoomX)
local state = flying and modeNames[mode] or (battery < 100 and "A CARREGAR" or "NO CHÃO")
screenLabel.Text = "📡 " .. state .. "\n" .. telemetry
hudTelemetry.Text = telemetry
local bc = battery > 50 and Color3.fromRGB(0, 255, 120)
or battery > 20 and Color3.fromRGB(255, 200, 0)
or Color3.fromRGB(255, 60, 60)
ledStatus.TextColor3 = bc
ledStatus.Text = string.format("🔋 %d%% [ DJI RC - LINKED ]", bat)
if recording then
local blink = math.floor(recTime * 2) % 2 == 0
hudRec.Text = string.format("[ %s REC %02d:%02d ]", blink and "🔴" or "⚫",
math.floor(recTime / 60), math.floor(recTime % 60))
else
hudRec.Text = "[ ⏺ STANDBY ]"
end
end
end))
print("Drone DJI RC v3 (com Térmico e Bombas) carregado com sucesso!")No comments yet for this script.



