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


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

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

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

local cameraHeight = 1.5
local forwardOffset = 0

local maxPitch = math.rad(89)
local smoothness = 0.15

local firstPersonFOV = 70
local thirdPersonFOV = 60

local walkBobSpeed = 8
local walkBobAmount = 0.018
local runBobSpeed = 12
local runBobAmount = 0.035
local sideBobAmount = 0.012

local thirdPersonDistance = 8
local thirdPersonHeight = 2

local firstPerson = true

local sensitivity = UserInputService.TouchEnabled
	and sensitivityMobile
	or sensitivityPC

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

local draggingTouch = false
local lastTouchPosition = Vector2.zero

local hiddenObjects = {}

local crosshairGui
local crosshair

local function hideObject(object)
	if not object or not object.Parent then
		return
	end

	if object:IsA("BasePart") then
		if hiddenObjects[object] == nil then
			hiddenObjects[object] = object.LocalTransparencyModifier
		end

		object.LocalTransparencyModifier = 1

	elseif object:IsA("Decal") or object:IsA("Texture") then
		if hiddenObjects[object] == nil then
			hiddenObjects[object] = object.Transparency
		end

		object.Transparency = 1
	end
end

local function restoreHiddenObjects()
	for object, oldValue in pairs(hiddenObjects) do
		if object and object.Parent then
			if object:IsA("BasePart") then
				object.LocalTransparencyModifier = oldValue
			elseif object:IsA("Decal") or object:IsA("Texture") then
				object.Transparency = oldValue
			end
		end
	end

	hiddenObjects = {}
end

local function hideFirstPersonObjects(character)
	restoreHiddenObjects()

	local head = character:FindFirstChild("Head")

	if head then
		hideObject(head)

		for _, object in ipairs(head:GetDescendants()) do
			if object:IsA("Decal") or object:IsA("Texture") then
				hideObject(object)
			end
		end
	end

	for _, object in ipairs(character:GetChildren()) do
		if object:IsA("Accessory") then
			for _, descendant in ipairs(object:GetDescendants()) do
				if descendant:IsA("BasePart")
					or descendant:IsA("Decal")
					or descendant:IsA("Texture") then

					hideObject(descendant)
				end
			end
		end
	end
end

local function createCrosshair()
	local playerGui = player:WaitForChild("PlayerGui")

	local oldGui = playerGui:FindFirstChild("CameraCrosshair")

	if oldGui then
		oldGui:Destroy()
	end

	crosshairGui = Instance.new("ScreenGui")
	crosshairGui.Name = "CameraCrosshair"
	crosshairGui.ResetOnSpawn = false
	crosshairGui.IgnoreGuiInset = true
	crosshairGui.Parent = playerGui

	crosshair = Instance.new("TextLabel")
	crosshair.Name = "Crosshair"
	crosshair.AnchorPoint = Vector2.new(0.5, 0.5)
	crosshair.Position = UDim2.fromScale(0.5, 0.5)
	crosshair.Size = UDim2.fromOffset(24, 24)
	crosshair.BackgroundTransparency = 1
	crosshair.Text = "+"
	crosshair.TextColor3 = Color3.new(1, 1, 1)
	crosshair.TextSize = 18
	crosshair.Font = Enum.Font.GothamBold
	crosshair.Visible = firstPerson
	crosshair.Parent = crosshairGui
end

local function updateCrosshair()
	if crosshair then
		crosshair.Visible = firstPerson
	end
end

local function toggleView()
	local character = player.Character

	if not character then
		return
	end

	firstPerson = not firstPerson

	if firstPerson then
		hideFirstPersonObjects(character)
		camera.FieldOfView = firstPersonFOV
	else
		restoreHiddenObjects()
		camera.FieldOfView = thirdPersonFOV
	end

	updateCrosshair()
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) * smoothness
	currentPitch += (targetPitch - currentPitch) * smoothness

	local rotation =
		CFrame.Angles(0, currentYaw, 0)
		* CFrame.Angles(currentPitch, 0, 0)

	if firstPerson then
		local bob = CFrame.identity

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

			local isRunning = humanoid.WalkSpeed > 16

			local speed = isRunning
				and runBobSpeed
				or walkBobSpeed

			local amount = isRunning
				and runBobAmount
				or walkBobAmount

			local time = os.clock() * speed

			local x =
				math.cos(time * 0.5)
				* sideBobAmount

			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 cameraPosition =
			hrp.Position
			+ Vector3.new(0, cameraHeight, 0)
			+ hrp.CFrame.LookVector * forwardOffset

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

		camera.FieldOfView = firstPersonFOV

		local lookDirection = rotation.LookVector

		local flatDirection = Vector3.new(
			lookDirection.X,
			0,
			lookDirection.Z
		)

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

	else
		local cameraDirection = rotation.LookVector

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

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

		camera.FieldOfView = thirdPersonFOV
	end

	updateCrosshair()
end

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

	local playerGui = player:WaitForChild("PlayerGui")

	local oldGui = playerGui:FindFirstChild("MobileViewToggle")

	if oldGui then
		oldGui: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)
	character:WaitForChild("HumanoidRootPart")

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

	firstPerson = true

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

	UserInputService.MouseIconEnabled = false

	hideFirstPersonObjects(character)
	createCrosshair()
	createMobileButton()

	UserInputService.MouseBehavior =
		Enum.MouseBehavior.LockCurrentPosition

	character.ChildAdded:Connect(function(child)
		if firstPerson and child:IsA("Accessory") then
			task.wait()

			if character.Parent then
				hideFirstPersonObjects(character)
			end
		end
	end)
end

UserInputService.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,
			-maxPitch,
			maxPitch
		)

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

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

		local delta =
			position
			- lastTouchPosition

		lastTouchPosition = position

		targetYaw -=
			delta.X
			* sensitivity
			* 0.005

		targetPitch -=
			delta.Y
			* sensitivity
			* 0.005

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

UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed then
		return
	end

	if input.UserInputType == Enum.UserInputType.MouseButton2 then
		if UserInputService.MouseBehavior
			== Enum.MouseBehavior.LockCurrentPosition then

			UserInputService.MouseBehavior =
				Enum.MouseBehavior.Default
		else
			UserInputService.MouseBehavior =
				Enum.MouseBehavior.LockCurrentPosition
		end

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

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

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

UserInputService.InputEnded:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.Touch then
		draggingTouch = false
	end
end)

RunService:BindToRenderStep(
	"CustomCamera",
	Enum.RenderPriority.Camera.Value + 1,
	updateCamera
)

RunService.RenderStepped:Connect(function()
	UserInputService.MouseIconEnabled = false
end)

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

player.CharacterAdded:Connect(setupCharacter)

player.AncestryChanged:Connect(function()
	if not player.Parent then
		restoreHiddenObjects()
		UserInputService.MouseBehavior =
			Enum.MouseBehavior.Default
	end
end)