Hãy viết cho tôi một script thiết lập hệ thống hỗ trợ khóa Camera (Camera Lock-On System) chuyên nghiệp bằng ngôn ngữ Luau dành cho game Roblox trên Mobile (chạy trên Executor Delta). Hiện tại đoạn code mẫu dưới đây đang gặp lỗi: "Không chịu cập nhật và xoay Camera về phía phần đối tượng mục tiêu khi người chơi đang ở góc nhìn thứ nhất (First-Person)". YÊU CẦU ĐIỀU CHỈNH CHI TIẾT: 1. Khắc phục lỗi xoay Camera ở góc nhìn thứ nhất trên Mobile: - Trong vòng lặp RenderStepped của code hiện tại đang dùng cách tính toán góc tuyệt đối để gán vào Camera.CFrame. Cách này sẽ bị hệ thống quản lý góc nhìn bằng cảm ứng (Touch) của Roblox Mobile ghi đè (override) ngay lập tức, khiến camera bị khựng hoặc đứng im không xoay. - GIẢI PHÁP: Hãy thay thế đoạn xử lý cập nhật vị trí camera đó bằng cách sử dụng `CFrame.lookAt(Camera.CFrame.Position, targetPos)` hoặc tính toán góc xoay tương đối để ép buộc `Camera.CFrame` phải hướng thẳng vào phần ĐẦU (Head) của mục tiêu một cách mượt mà từng khung hình mà không bị cơ chế của game khóa lại. 2. Tính năng tự động hủy theo dõi mục tiêu (Unlock Target): - Nếu người chơi chủ động dùng tay vuốt mạnh màn hình cảm ứng để xoay sang hướng khác, khiến phần ĐẦU (Head) của đối tượng mục tiêu hiện tại vượt ra khỏi phạm vi bán kính vòng tròn giới hạn 35 pixels, script phải LẬP TỨC hủy theo dõi (Unlock) đối tượng đó để tránh tình trạng ghìm giữ camera hoặc giật ngược màn hình gây khó chịu. 3. Giữ nguyên và tối ưu các tính năng sẵn có: - Vòng tròn giới hạn phạm vi màu xanh lá cây (Green), bán kính cố định 35 pixels ở tâm màn hình sử dụng Drawing API. - Hàm kiểm tra tia quét vật cản (Line-of-Sight Check) sử dụng `workspace:Raycast` hoạt động chính xác để tránh khóa vào mục tiêu bị tường che khuất. - Duy nhất một nút bấm Toggle (AIM: ON/OFF) nhỏ gọn, hỗ trợ Kéo/Thả (Draggable) mượt mờ bằng cảm ứng trên điện thoại (Parent vào PlayerGui). Khi tắt hệ thống hỗ trợ, toàn bộ logic quét và vòng tròn Drawing phải dừng hoàn toàn để tiết kiệm pin và tránh nóng máy. Dưới đây là toàn bộ đoạn code cần điều chỉnh, hãy tối ưu lại thuật toán cập nhật Camera và trả về đoạn code hoàn chỉnh: -- Đợi game tải xong hoàn toàn dữ liệu người chơi if not game:IsLoaded() then game.Loaded:Wait() end local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local LocalPlayer = Players.LocalPlayer local Camera = workspace.CurrentCamera -- Đợi PlayerGui sẵn sàng local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") local AimbotEnabled = true local FOV_RADIUS = 35 local TARGET_PART = "Head" -- Khởi tạo vòng tròn FOV local FOVCircle = Drawing.new("Circle") FOVCircle.Thickness = 1.5 FOVCircle.Color = Color3.fromRGB(0, 255, 0) FOVCircle.Filled = false FOVCircle.Radius = FOV_RADIUS FOVCircle.Visible = true -- Hàm tìm mục tiêu local function getClosestPlayer() local closestPlayer = nil local shortestDistance = math.huge local screenCenter = Vector2.new(Camera.ViewportSize.X / 2, Camera.ViewportSize.Y / 2) for _, player in ipairs(Players:GetPlayers()) do if player ~= LocalPlayer and player.Character and player.Character:FindFirstChild(TARGET_PART) and player.Character:FindFirstChildOfClass("Humanoid") then local humanoid = player.Character:FindFirstChildOfClass("Humanoid") if humanoid.Health > 0 then local targetPart = player.Character[TARGET_PART] local raycastParams = RaycastParams.new() raycastParams.FilterType = Enum.RaycastFilterType.Exclude raycastParams.FilterDescendantsInstances = {LocalPlayer.Character, player.Character} local origin = Camera.CFrame.Position local direction = targetPart.Position - origin local raycastResult = workspace:Raycast(origin, direction, raycastParams) if not raycastResult then local screenPos, onScreen = Camera:WorldToViewportPoint(targetPart.Position) if onScreen then local targetPos2D = Vector2.new(screenPos.X, screenPos.Y) local distanceToCenter = (targetPos2D - screenCenter).Magnitude if distanceToCenter <= FOV_RADIUS and distanceToCenter < shortestDistance then closestPlayer = player shortestDistance = distanceToCenter end end end end end end return closestPlayer end -- Vòng lặp cập nhật hệ thống local aimConnection local function startAimbot() aimConnection = RunService.RenderStepped:Connect(function() local screenCenter = Vector2.new(Camera.ViewportSize.X / 2, Camera.ViewportSize.Y / 2) FOVCircle.Position = screenCenter if not AimbotEnabled then return end local targetPlayer = getClosestPlayer() if targetPlayer and targetPlayer.Character and targetPlayer.Character:FindFirstChild(TARGET_PART) then local targetPos = targetPlayer.Character[TARGET_PART].Position local direction = (targetPos - Camera.CFrame.Position).Unit local targetYaw = math.atan2(-direction.X, -direction.Z) local targetPitch = math.asin(direction.Y) -- Xoay camera ép buộc cho góc nhìn thứ nhất trên Mobile Camera.CFrame = CFrame.new(Camera.CFrame.Position) * CFrame.Angles(0, targetYaw, 0) * CFrame.Angles(targetPitch, 0, 0) end end) end local function stopAimbot() if aimConnection then aimConnection:Disconnect() aimConnection = nil end FOVCircle.Visible = false end startAimbot() -- TẠO GUI - ĐÃ SỬA ĐỂ HIỆN THỊ TRÊN DELTA if PlayerGui:FindFirstChild("MobileAimbotGui") then PlayerGui.MobileAimbotGui:Destroy() end local ScreenGui = Instance.new("ScreenGui") local ToggleButton = Instance.new("TextButton") local UICorner = Instance.new("UICorner") ScreenGui.Name = "MobileAimbotGui" ScreenGui.Parent = PlayerGui ScreenGui.ResetOnSpawn = false ToggleButton.Name = "ToggleButton" ToggleButton.Parent = ScreenGui ToggleButton.BackgroundColor3 = Color3.fromRGB(0, 200, 100) ToggleButton.Position = UDim2.new(0.15, 0, 0.25, 0) ToggleButton.Size = UDim2.new(0, 75, 0, 35) ToggleButton.Font = Enum.Font.SourceSansBold ToggleButton.Text = "TRACK: ON" ToggleButton.TextColor3 = Color3.fromRGB(255, 255, 255) ToggleButton.TextSize = 14.0 ToggleButton.Active = true UICorner.CornerRadius = UDim.new(0, 8) UICorner.Parent = ToggleButton local dragging, dragInput, dragStart, startPos local function update(input) local delta = input.Position - dragStart ToggleButton.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y) end ToggleButton.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then dragging = true dragStart = input.Position startPos = ToggleButton.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) ToggleButton.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseMovement then dragInput = input end end) UserInputService.InputChanged:Connect(function(input) if input == dragInput and dragging then update(input) end end) ToggleButton.MouseButton1Click:Connect(function() AimbotEnabled = not AimbotEnabled if AimbotEnabled then ToggleButton.Text = "TRACK: ON" ToggleButton.BackgroundColor3 = Color3.fromRGB(0, 200, 100) FOVCircle.Visible = true if not aimConnection then startAimbot() end else ToggleButton.Text = "TRACK: OFF" ToggleButton.BackgroundColor3 = Color3.fromRGB(200, 50, 50) stopAimbot() end end)