Загрузка данных


local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local camera = workspace.CurrentCamera

-- SETTINGS
local sensitivityPC = 0.8
local sensitivityMobile = 1.5
local firstPersonKey = Enum.KeyCode.F

local headHeight = 1.2
local forwardOffset = 1.2

local maxAngle = math.rad(89)
local smooth = 0.15

local firstPersonFOV = 70
local thirdPersonFOV = 60

local firstPerson = true

local currentPitch = 0
local currentYaw = 0
local targetPitch = 0
local targetYaw = 0

local draggingTouch = false
local lastTouch = Vector2.zero

local thirdPersonDistance = 8
local thirdPersonHeight = 2

local sensitivity = UIS.TouchEnabled
	and sensitivityMobile
	or sensitivity

-- Храним исходную прозрачность объектов
local hiddenParts = {}

local function hideHeadAndAccessories(character)
	-- Сначала восстанавливаем всё, что было скрыто раньше
	for object, oldTransparency in pairs(hiddenParts) do
		if object and object.Parent then
			if object:IsA("BasePart") then
				object.LocalTransparencyModifier = oldTransparency
			elseif object:IsA("Decal") then
				object.LocalTransparencyModifier = oldTransparency
			end
		end
	end

	hiddenParts = {}

	local head = character:FindFirstChild("Head")

	if head then
		hiddenParts[head] = head.LocalTransparencyModifier
		head.LocalTransparencyModifier = 1

		local face = head:FindFirstChild("face")

		if face and face:IsA("Decal") then
			hiddenParts[face] = face.LocalTransparencyModifier
			face.LocalTransparencyModifier = 1
		end
	end

	for _, accessory in ipairs(character:GetChildren()) do
		if accessory:IsA("Accessory") then
			for _, object in ipairs(accessory:GetDescendants()) do
				if object:IsA("BasePart") then
					hiddenParts[object] =
						object.LocalTransparencyModifier

					object.LocalTransparencyModifier = 1
				elseif object:IsA("Decal") then
					hiddenParts[object] =
						object.LocalTransparencyModifier

					object.LocalTransparencyModifier = 1
				end
			end
		end
	end
end

local function showHeadAndAccessories()
	for object, oldTransparency in pairs(hiddenParts) do
		if object and object.Parent then
			if object:IsA("BasePart") then
				object.LocalTransparencyModifier =
					oldTransparency
			elseif object:IsA("Decal") then
				object.LocalTransparencyModifier =
					oldTransparency
			end
		end
	end

	hiddenParts = {}
end

local function toggleView()
	local character = player.Character

	if not character then
		return
	end

	firstPerson = not firstPerson

	local humanoid =
		character:FindFirstChildOfClass("Humanoid")

	if firstPerson then
		if humanoid then
			humanoid.AutoRotate = false
		end

		hideHeadAndAccessories(character)
		camera.FieldOfView = firstPersonFOV
	else
		if humanoid then
			humanoid.AutoRotate = true
		end

		showHeadAndAccessories()
		camera.FieldOfView = thirdPersonFOV
	end
end

local function updateCamera()
	local character = player.Character

	if not character then
		return
	end

	local hrp = character:FindFirstChild("HumanoidRootPart")
	local humanoid = character:FindFirstChildOfClass("Humanoid")

	if not hrp or not humanoid then
		return
	end

	currentYaw += (targetYaw - currentYaw) * smooth
	currentPitch += (targetPitch - currentPitch) * smooth

	local yawRotation = CFrame.Angles(0, currentYaw, 0)
	local pitchRotation = CFrame.Angles(currentPitch, 0, 0)

	local rotation = yawRotation * pitchRotation

	if firstPerson then

		-- Не даём стандартной Roblox-камере
		-- конфликтовать с нашей камерой
		humanoid.AutoRotate = false

		-- Персонаж смотрит туда же, куда камера
		local look = rotation.LookVector

		local flatLook = Vector3.new(
			look.X,
			0,
			look.Z
		)

		if flatLook.Magnitude > 0.001 then
			hrp.CFrame = CFrame.lookAt(
				hrp.Position,
				hrp.Position + flatLook.Unit
			)
		end

		local bob = CFrame.new()

		if humanoid.MoveDirection.Magnitude > 0.05
			and humanoid.FloorMaterial ~= Enum.Material.Air then

			local running = humanoid.WalkSpeed > 16

			local speed = running and 12 or 8
			local amount = running and 0.035 or 0.018

			local time = os.clock() * speed

			local x = math.cos(time * 0.5) * 0.012
			local y = math.abs(math.sin(time)) * amount
			local roll = math.sin(time * 0.5) * 0.006

			bob =
				CFrame.new(x, y, 0)
				* CFrame.Angles(0, 0, roll)
		end

		-- Позиция камеры рассчитывается
		-- уже после поворота персонажа
		local position =
			hrp.Position
			+ Vector3.new(0, headHeight, 0)
			+ hrp.CFrame.LookVector * forwardOffset

		camera.CFrame =
			CFrame.new(position)
			* rotation
			* bob

		camera.FieldOfView = firstPersonFOV

	else

		humanoid.AutoRotate = true

		local direction = rotation.LookVector

		local position =
			hrp.Position
			- direction * thirdPersonDistance
			+ Vector3.new(0, thirdPersonHeight, 0)

		camera.CFrame = CFrame.lookAt(
			position,
			hrp.Position + Vector3.new(0, 1.5, 0)
		)

		camera.FieldOfView = thirdPersonFOV
	end
end

local function createMobileButton()
	if not UIS.TouchEnabled then
		return
	end

	local playerGui = player:WaitForChild("PlayerGui")

	local old = playerGui:FindFirstChild("MobileViewToggle")

	if old then
		old:Destroy()
	end

	local gui = Instance.new("ScreenGui")
	gui.Name = "MobileViewToggle"
	gui.ResetOnSpawn = false
	gui.Parent = playerGui

	local button = Instance.new("TextButton")
	button.Name = "ToggleButton"
	button.Size = UDim2.fromOffset(30, 30)
	button.Position = UDim2.fromOffset(20, 20)
	button.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
	button.BackgroundTransparency = 0.3
	button.BorderSizePixel = 0
	button.Text = "1"
	button.TextColor3 = Color3.new(1, 1, 1)
	button.TextScaled = true
	button.Parent = gui

	local corner = Instance.new("UICorner")
	corner.CornerRadius = UDim.new(0, 10)
	corner.Parent = button

	button.MouseButton1Click:Connect(function()
		toggleView()
		button.Text = firstPerson and "1" or "3"
	end)
end

local function setupCharacter(character)

	-- Если был старый персонаж,
	-- возвращаем ему прозрачность
	showHeadAndAccessories()

	character:WaitForChild("Head")
	character:WaitForChild("HumanoidRootPart")

	currentPitch = 0
	currentYaw = 0
	targetPitch = 0
	targetYaw = 0

	firstPerson = true

	camera.CameraType = Enum.CameraType.Scriptable
	camera.FieldOfView = firstPersonFOV

	UIS.MouseIconEnabled = false
	UIS.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition

	local humanoid =
		character:FindFirstChildOfClass("Humanoid")

	if humanoid then
		humanoid.AutoRotate = false
	end

	hideHeadAndAccessories(character)
	createMobileButton()
end

UIS.InputChanged:Connect(function(input, gameProcessed)

	if gameProcessed then
		return
	end

	if input.UserInputType == Enum.UserInputType.MouseMovement then

		local delta = input.Delta

		targetYaw -= delta.X * sensitivity * 0.005
		targetPitch -= delta.Y * sensitivity * 0.005

		targetPitch = math.clamp(
			targetPitch,
			-maxAngle,
			maxAngle
		)

	elseif input.UserInputType == Enum.UserInputType.Touch
		and draggingTouch then

		local position = Vector2.new(
			input.Position.X,
			input.Position.Y
		)

		local delta = position - lastTouch

		lastTouch = position

		targetYaw -= delta.X * sensitivity * 0.005
		targetPitch -= delta.Y * sensitivity * 0.005

		targetPitch = math.clamp(
			targetPitch,
			-maxAngle,
			maxAngle
		)
	end
end)

UIS.InputBegan:Connect(function(input, gameProcessed)

	if gameProcessed then
		return
	end

	if input.UserInputType == Enum.UserInputType.MouseButton2 then

		if UIS.MouseBehavior
			== Enum.MouseBehavior.LockCurrentPosition then

			UIS.MouseBehavior =
				Enum.MouseBehavior.Default

		else

			UIS.MouseBehavior =
				Enum.MouseBehavior.LockCurrentPosition
		end

	elseif input.UserInputType == Enum.UserInputType.Touch then

		draggingTouch = true

		lastTouch = Vector2.new(
			input.Position.X,
			input.Position.Y
		)

	elseif input.KeyCode == firstPersonKey then
		toggleView()
	end
end)

UIS.InputEnded:Connect(function(input)

	if input.UserInputType == Enum.UserInputType.Touch then
		draggingTouch = false
	end
end)

RunService:BindToRenderStep(
	"CustomCamera",
	Enum.RenderPriority.Camera.Value + 1,
	function()
		UIS.MouseIconEnabled = false
		updateCamera()
	end
)

if player.Character then
	setupCharacter(player.Character)
end

player.CharacterAdded:Connect(function(character)
	setupCharacter(character)
end)

player.AncestryChanged:Connect(function()

	if not player.Parent then
		showHeadAndAccessories()
		UIS.MouseBehavior = Enum.MouseBehavior.Default
	end

end)