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


local sensitivity_pc = 0.8
local sensitivity_mobile = 1.5
local first_person_key = Enum.KeyCode.F

local camera_height = 1.5
local forward_offset = 0

local max_angl = math.rad(89)
local mouse_cursor = false
local smooth = 0.15

local first_person_fov = 90
local third_person_fov = 80

local walk_bob_speed = 8
local walk_bob_amount = 0.02
local run_bob_speed = 12
local run_bob_amount = 0.04
local side_bob_amount = 0.015

local third_person_distance = 8
local third_person_height = 2

local uis = game:GetService("UserInputService")
local runService = game:GetService("RunService")

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

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

local draggingTouch = false
local lastTouch = Vector2.new(0, 0)

local firstPerson = true

local sensitivity =
	uis.TouchEnabled
	and sensitivity_mobile
	or sensitivity_pc

local hiddenParts = {}

local crosshairGui
local crosshair


--------------------------------------------------
-- ЛОКАЛЬНО СКРЫТЬ ЧАСТЬ
--------------------------------------------------

local function hidePart(part)

	if not part or not part.Parent then
		return
	end

	if part:IsA("BasePart") then

		if hiddenParts[part] == nil then
			hiddenParts[part] =
				part.LocalTransparencyModifier
		end

		part.LocalTransparencyModifier = 1

	elseif part:IsA("Decal") then

		if hiddenParts[part] == nil then
			hiddenParts[part] =
				part.LocalTransparencyModifier
		end

		part.LocalTransparencyModifier = 1

	end

end


--------------------------------------------------
-- ГОЛОВА + АКСЕССУАРЫ
-- ТОЛЬКО ДЛЯ ЭТОГО ИГРОКА
--------------------------------------------------

local function hideFirstPersonBody(character)

	-- Сначала возвращаем старые скрытые объекты
	for object in pairs(hiddenParts) do

		if object and object.Parent then

			if object:IsA("BasePart")
				or object:IsA("Decal") then

				object.LocalTransparencyModifier = 0

			end

		end

	end

	hiddenParts = {}


	--------------------------------------------------
	-- ГОЛОВА
	--------------------------------------------------

	local head = character:FindFirstChild("Head")

	if head then

		hidePart(head)

		for _, object in ipairs(head:GetDescendants()) do

			if object:IsA("BasePart")
				or object:IsA("Decal") then

				hidePart(object)

			end

		end

	end


	--------------------------------------------------
	-- АКСЕССУАРЫ
	--------------------------------------------------

	for _, object in ipairs(character:GetChildren()) do

		if object:IsA("Accessory") then

			for _, accessoryPart in ipairs(
				object:GetDescendants()
			) do

				if accessoryPart:IsA("BasePart")
					or accessoryPart:IsA("Decal") then

					hidePart(accessoryPart)

				end

			end

		end

	end


	--------------------------------------------------
	-- ТОРС НЕ СКРЫВАЕМ
	--------------------------------------------------

	for _, torsoName in ipairs({
		"Torso",
		"UpperTorso",
		"LowerTorso"
	}) do

		local torso =
			character:FindFirstChild(torsoName)

		if torso and torso:IsA("BasePart") then
			torso.LocalTransparencyModifier = 0
		end

	end

end


--------------------------------------------------
-- ВЕРНУТЬ СКРЫТЫЕ ЧАСТИ
--------------------------------------------------

local function showHiddenParts()

	for object, oldValue in pairs(hiddenParts) do

		if object and object.Parent then

			if object:IsA("BasePart")
				or object:IsA("Decal") then

				object.LocalTransparencyModifier =
					oldValue

			end

		end

	end

	hiddenParts = {}

end


--------------------------------------------------
-- ТОРС ВСЕГДА ВИДИМ
--------------------------------------------------

local function showTorso(character)

	for _, torsoName in ipairs({
		"Torso",
		"UpperTorso",
		"LowerTorso"
	}) do

		local torso =
			character:FindFirstChild(torsoName)

		if torso and torso:IsA("BasePart") then

			torso.LocalTransparencyModifier = 0

		end

	end

end


--------------------------------------------------
-- ПРИЦЕЛ
--------------------------------------------------

local function createCrosshair()

	if crosshairGui then
		crosshairGui:Destroy()
	end

	crosshairGui =
		Instance.new("ScreenGui")

	crosshairGui.Name =
		"CameraCrosshair"

	crosshairGui.ResetOnSpawn =
		false

	crosshairGui.IgnoreGuiInset =
		true

	crosshairGui.Parent =
		player:WaitForChild("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 toggleViewMode()

	local character =
		player.Character

	if not character then
		return
	end

	firstPerson =
		not firstPerson


	if firstPerson then

		hideFirstPersonBody(character)
		showTorso(character)

		camera.FieldOfView =
			first_person_fov

	else

		showHiddenParts()
		showTorso(character)

		camera.FieldOfView =
			third_person_fov

	end


	if crosshair then
		crosshair.Visible =
			firstPerson
	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


	-- Торс постоянно видим
	showTorso(character)


	currentYaw =
		currentYaw
		+ (targetYaw - currentYaw)
		* smooth

	currentPitch =
		currentPitch
		+ (targetPitch - currentPitch)
		* smooth


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


	--------------------------------------------------
	-- ПЕРВОЕ ЛИЦО
	--------------------------------------------------

	if firstPerson then

		humanoid.AutoRotate = false


		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 run_bob_speed
				or walk_bob_speed

			local amount =
				running
				and run_bob_amount
				or walk_bob_amount

			local t =
				os.clock() * speed


			local x =
				math.cos(t * 0.5)
				* side_bob_amount

			local y =
				math.abs(math.sin(t))
				* amount


			bob =
				CFrame.new(
					x,
					y,
					0
				)
				*
				CFrame.Angles(
					0,
					0,
					math.sin(t * 0.5)
					* 0.008
				)

		end


		local cameraPosition =
			hrp.Position
			+
			Vector3.new(
				0,
				camera_height,
				forward_offset
			)


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


		camera.FieldOfView =
			first_person_fov


	--------------------------------------------------
	-- ТРЕТЬЕ ЛИЦО
	--------------------------------------------------

	else

		humanoid.AutoRotate = true


		local cameraDirection =
			rotation.LookVector


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


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


		camera.FieldOfView =
			third_person_fov

	end


	if crosshair then
		crosshair.Visible =
			firstPerson
	end

end


--------------------------------------------------
-- НАСТРОЙКА КАМЕРЫ
--------------------------------------------------

local function setupCamera(character)

	camera.CameraType =
		Enum.CameraType.Scriptable

	camera.FieldOfView =
		first_person_fov

	uis.MouseIconEnabled =
		mouse_cursor

	firstPerson = true


	local humanoid =
		character:FindFirstChildOfClass(
			"Humanoid"
		)

	if humanoid then
		humanoid.AutoRotate = false
	end


	hideFirstPersonBody(character)
	showTorso(character)

	createCrosshair()


	--------------------------------------------------
	-- МОБИЛЬНАЯ КНОПКА
	--------------------------------------------------

	if uis.TouchEnabled then

		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.new(
				0.2,
				0.2,
				0.2
			)

		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()

				toggleViewMode()

				button.Text =
					firstPerson
					and "1"
					or "3"

			end
		)

	end

end


--------------------------------------------------
-- ПЕРСОНАЖ
--------------------------------------------------

local function onCharacterAdded(character)

	character:WaitForChild(
		"HumanoidRootPart"
	)


	currentPitch = 0
	currentYaw = 0

	targetPitch = 0
	targetYaw = 0


	setupCamera(character)


	uis.MouseBehavior =
		Enum.MouseBehavior.LockCurrentPosition


	--------------------------------------------------
	-- НОВЫЕ АКСЕССУАРЫ
	--------------------------------------------------

	character.ChildAdded:Connect(
		function(child)

			if firstPerson
				and child:IsA("Accessory") then

				task.wait()

				if character.Parent then

					hideFirstPersonBody(
						character
					)

					showTorso(
						character
					)

				end

			end

		end
	)

end


--------------------------------------------------
-- ПОВОРОТ КАМЕРЫ
--------------------------------------------------

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

		if gameProcessed then
			return
		end


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

			local delta =
				input.Delta


			targetYaw =
				targetYaw
				-
				delta.X
				*
				sensitivity
				*
				0.005


			targetPitch =
				targetPitch
				-
				delta.Y
				*
				sensitivity
				*
				0.005


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


		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 =
				targetYaw
				-
				delta.X
				*
				sensitivity
				*
				0.005


			targetPitch =
				targetPitch
				-
				delta.Y
				*
				sensitivity
				*
				0.005


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

		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
			== first_person_key then

			toggleViewMode()

		end

	end
)


--------------------------------------------------
-- TOUCH ОТПУЩЕН
--------------------------------------------------

uis.InputEnded:Connect(
	function(input)

		if input.UserInputType
			== Enum.UserInputType.Touch then

			draggingTouch = false

		end

	end
)


--------------------------------------------------
-- RENDER
--------------------------------------------------

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


--------------------------------------------------
-- ЗАПУСК
--------------------------------------------------

if player.Character then

	onCharacterAdded(
		player.Character
	)

end


player.CharacterAdded:Connect(
	onCharacterAdded
)


--------------------------------------------------
-- ВЫХОД
--------------------------------------------------

player.AncestryChanged:Connect(
	function()

		if not player.Parent then

			showHiddenParts()

			uis.MouseBehavior =
				Enum.MouseBehavior.Default

		end

	end
)