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


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

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

local FIRST_PERSON_FOV = 70
local THIRD_PERSON_FOV = 60

local THIRD_PERSON_DISTANCE = 7
local THIRD_PERSON_HEIGHT = 2

local MOUSE_SENSITIVITY = 0.0025
local TOUCH_SENSITIVITY = 0.004

local SMOOTHNESS = 16

local MIN_PITCH = math.rad(-85)
local MAX_PITCH = math.rad(85)

local TOGGLE_KEY = Enum.KeyCode.F

local character
local humanoid
local rootPart
local head

local firstPerson = true

local yaw = 0
local pitch = 0

local targetYaw = 0
local targetPitch = 0

local touchId = nil
local lastTouchPosition = nil

--------------------------------------------------
-- CHARACTER VISIBILITY
--------------------------------------------------

local function updateCharacterVisibility()
	if not character then
		return
	end

	for _, object in ipairs(character:GetDescendants()) do
		if object:IsA("BasePart") then

			if firstPerson then

				-- Hide head
				if object == head then
					object.LocalTransparencyModifier = 1

				-- Hide upper torso
				elseif object.Name == "UpperTorso" then
					object.LocalTransparencyModifier = 1

				-- Hide every accessory part
				elseif object:FindFirstAncestorOfClass("Accessory") then
					object.LocalTransparencyModifier = 1

				else
					object.LocalTransparencyModifier = 0
				end

			else
				object.LocalTransparencyModifier = 0
			end

		elseif object:IsA("Decal") then

			if firstPerson and head and object:IsDescendantOf(head) then
				object.Transparency = 1
			else
				object.Transparency = 0
			end
		end
	end
end

--------------------------------------------------
-- CAMERA MODE
--------------------------------------------------

local function setCameraMode(mode)
	firstPerson = mode

	camera.CameraType = Enum.CameraType.Scriptable

	if firstPerson then
		camera.FieldOfView = FIRST_PERSON_FOV

		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
		UserInputService.MouseIconEnabled = false

		if humanoid then
			humanoid.AutoRotate = false
		end
	else
		camera.FieldOfView = THIRD_PERSON_FOV

		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
		UserInputService.MouseIconEnabled = true

		if humanoid then
			humanoid.AutoRotate = false
		end
	end

	updateCharacterVisibility()
end

local function toggleCamera()
	setCameraMode(not firstPerson)
end

--------------------------------------------------
-- CHARACTER SETUP
--------------------------------------------------

local function setupCharacter(newCharacter)

	character = newCharacter

	humanoid = character:WaitForChild("Humanoid")
	rootPart = character:WaitForChild("HumanoidRootPart")
	head = character:WaitForChild("Head")

	local look = rootPart.CFrame.LookVector

	yaw = math.atan2(-look.X, -look.Z)
	targetYaw = yaw

	pitch = 0
	targetPitch = 0

	setCameraMode(true)
end

--------------------------------------------------
-- MOUSE
--------------------------------------------------

UserInputService.InputChanged:Connect(function(input)

	if not firstPerson then
		return
	end

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

		local delta = input.Delta

		targetYaw -= delta.X * MOUSE_SENSITIVITY
		targetPitch -= delta.Y * MOUSE_SENSITIVITY

		targetPitch = math.clamp(
			targetPitch,
			MIN_PITCH,
			MAX_PITCH
		)
	end
end)

--------------------------------------------------
-- TOUCH START
--------------------------------------------------

UserInputService.TouchStarted:Connect(function(touch)

	if not firstPerson then
		return
	end

	local viewport = camera.ViewportSize

	if touch.Position.X >= viewport.X * 0.45 then
		touchId = touch
		lastTouchPosition = touch.Position
	end
end)

--------------------------------------------------
-- TOUCH MOVE
--------------------------------------------------

UserInputService.TouchMoved:Connect(function(touch)

	if not firstPerson then
		return
	end

	if touchId ~= touch then
		return
	end

	if not lastTouchPosition then
		lastTouchPosition = touch.Position
		return
	end

	local delta = touch.Position - lastTouchPosition

	lastTouchPosition = touch.Position

	targetYaw -= delta.X * TOUCH_SENSITIVITY
	targetPitch -= delta.Y * TOUCH_SENSITIVITY

	targetPitch = math.clamp(
		targetPitch,
		MIN_PITCH,
		MAX_PITCH
	)
end)

--------------------------------------------------
-- TOUCH END
--------------------------------------------------

UserInputService.TouchEnded:Connect(function(touch)

	if touchId == touch then
		touchId = nil
		lastTouchPosition = nil
	end
end)

--------------------------------------------------
-- KEYBOARD
--------------------------------------------------

UserInputService.InputBegan:Connect(function(input, processed)

	if processed then
		return
	end

	if input.KeyCode == TOGGLE_KEY then
		toggleCamera()
	end
end)

--------------------------------------------------
-- MOBILE BUTTON
--------------------------------------------------

local function createMobileButton()

	if not UserInputService.TouchEnabled then
		return
	end

	local playerGui = player:WaitForChild("PlayerGui")

	local old = playerGui:FindFirstChild("CameraToggle")

	if old then
		old:Destroy()
	end

	local gui = Instance.new("ScreenGui")

	gui.Name = "CameraToggle"
	gui.ResetOnSpawn = false
	gui.IgnoreGuiInset = true
	gui.Parent = playerGui

	local button = Instance.new("TextButton")

	button.Name = "Toggle"
	button.Size = UDim2.fromOffset(50, 50)
	button.Position = UDim2.fromOffset(20, 20)

	button.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
	button.BackgroundTransparency = 0.2

	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, 12)
	corner.Parent = button

	button.Activated:Connect(function()

		toggleCamera()

		if firstPerson then
			button.Text = "1"
		else
			button.Text = "3"
		end
	end)
end

--------------------------------------------------
-- CAMERA
--------------------------------------------------

RunService:BindToRenderStep(
	"MainFirstPersonCamera",
	Enum.RenderPriority.Camera.Value + 1,
	function(deltaTime)

		if not character
			or not humanoid
			or not rootPart
			or not head then
			return
		end

		if humanoid.Health <= 0 then
			return
		end

		camera.CameraType = Enum.CameraType.Scriptable

		local alpha = math.clamp(
			deltaTime * SMOOTHNESS,
			0,
			1
		)

		yaw += (targetYaw - yaw) * alpha
		pitch += (targetPitch - pitch) * alpha

		--------------------------------------------------
		-- FIRST PERSON
		--------------------------------------------------

		if firstPerson then

			local cameraPosition =
				head.Position + Vector3.new(0, 0.05, 0)

			local rotation =
				CFrame.Angles(0, yaw, 0)
				*
				CFrame.Angles(pitch, 0, 0)

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

			camera.FieldOfView = FIRST_PERSON_FOV

			--------------------------------------------------
			-- ROTATE CHARACTER HORIZONTALLY
			--------------------------------------------------

			local lookVector = rotation.LookVector

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

			if flatLook.Magnitude > 0.001 then

				rootPart.CFrame =
					CFrame.lookAt(
						rootPart.Position,
						rootPart.Position + flatLook.Unit
					)
			end

		--------------------------------------------------
		-- THIRD PERSON
		--------------------------------------------------

		else

			local rotation =
				CFrame.Angles(0, yaw, 0)
				*
				CFrame.Angles(pitch, 0, 0)

			local direction = rotation.LookVector

			local cameraPosition =
				rootPart.Position
				- direction * THIRD_PERSON_DISTANCE
				+ Vector3.new(
					0,
					THIRD_PERSON_HEIGHT,
					0
				)

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

			camera.FieldOfView = THIRD_PERSON_FOV
		end
	end
)

--------------------------------------------------
-- START
--------------------------------------------------

if player.Character then
	task.spawn(function()
		setupCharacter(player.Character)
	end)
end

player.CharacterAdded:Connect(function(newCharacter)

	task.wait(0.2)

	setupCharacter(newCharacter)
end)

createMobileButton()