Drone DJI RC v3 - Gemini IA
Key RequiredUniversal

Drone DJI RC v3 - Gemini IA

Universal Scriptpmiguel10766pmiguel10766 204 views 17 executesUpdated Oct 5, 2026
5.0/ 5(1 votes)
10100% Positive
Lua Script•770 lines (26404 chars)
-- // 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!")

Features & Information

Um script avançado em Luau com um drone 3D totalmente funcional, otimizado para telemóvel e PC. - Controles táteis (joysticks virtuais) para altura, rotação e movimento. - Vários modos de voo: Manual, Descolagem, Regressar a Casa (RTH), Seguir e Aterragem. - Câmara FPV com HUD, telemetria em tempo real (altitude, velocidade, distância, bateria) e zoom. - Efeitos e extras: Luzes LED personalizáveis, Visão Térmica, Largar Bombas com explosão e Autodestruição.

Community Comments (0)

No comments yet for this script.

More Scripts for Universal Scripts