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


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

local player = Players.LocalPlayer

--------------------------------------------------
-- SETTINGS
--------------------------------------------------

local FIRST_PERSON_FOV = 70
local THIRD_PERSON_FOV = 60

local CAMERA_HEIGHT = 1.45
local THIRD_PERSON_DISTANCE = 7
local THIRD_PERSON_HEIGHT = 2

local MOUSE_SENSITIVITY = 0.0025
local TOUCH_SENSITIVITY = 0.004

local CAMERA_SMOOTHNESS = 14

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

local TOGGLE_KEY = Enum.KeyCode.F

--------------------------------------------------
-- VARIABLES
--------------------------------------------------

local character
local humanoid
local rootPart
local head

local camera

local firstPerson = true

local targetYaw = 0
local targetPitch = 0

local currentYaw = 0
local currentPitch = 0

local cameraTouch = false
local lastTouchPosition = Vector2.zero

local hiddenObjects = {}

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

local function getCamera()
	camera = workspace.CurrentCamera
	return camera
end

--------------------------------------------------
-- HIDE FIRST PERSON OBJECTS
--------------------------------------------------

local function hideFirstPersonObjects()

	if not character then
		return
	end

	hiddenObjects = {}

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

		--------------------------------------------------
		-- PARTS
		--------------------------------------------------

		if object:IsA("BasePart") then

			-- Head
			if object == head then

				object.LocalTransparencyModifier = 1
				table.insert(hiddenObjects, object)

			-- Upper torso
			elseif object.Name == "UpperTorso" then

				object.LocalTransparencyModifier = 1
				table.insert(hiddenObjects, object)

			-- Accessories
			elseif object:FindFirstAncestorOfClass("Accessory") then

				object.LocalTransparencyModifier = 1
				table.insert(hiddenObjects, object)

			end

		--------------------------------------------------
		-- FACE / DECALS
		--------------------------------------------------

		elseif object:IsA("Decal") then

			if head and object:IsDescendantOf(head) then

				object.Transparency = 1
				table.insert(hiddenObjects, object)

			end
		end
	end
end

--------------------------------------------------
-- RESTORE CHARACTER
--------------------------------------------------

local function showCharacter()

	if not character then
		return
	end

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

		if object:IsA("BasePart") then
			object.LocalTransparencyModifier = 0

		elseif object:IsA("Decal") then
			object.Transparency = 0
		end
	end

	hiddenObjects = {}
end

--------------------------------------------------
-- SET CAMERA MODE
--------------------------------------------------

local function updateVisibility()

	if firstPerson then
		hideFirstPersonObjects()
	else
		showCharacter()
	end
end

--------------------------------------------------
-- TOGGLE
--------------------------------------------------

local function toggleCamera()

	firstPerson = not firstPerson

	local cam = getCamera()

	if not cam then
		return
	end

	if firstPerson then

		cam.CameraType = Enum.CameraType.Scriptable
		cam.FieldOfView = FIRST_PERSON_FOV

		if humanoid then
			humanoid.AutoRotate = false
		end

	else

		cam.CameraType = Enum.CameraType.Scriptable
		cam.FieldOfView = THIRD_PERSON_FOV

		if humanoid then
			humanoid.AutoRotate = false
		end
	end

	updateVisibility()
end

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

local function setupCharacter(newCharacter)

	character = newCharacter

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

	local cam = getCamera()

	firstPerson = true

	cam.CameraType = Enum.CameraType.Scriptable
	cam.FieldOfView = FIRST_PERSON_FOV

	humanoid.AutoRotate = false

	local look = rootPart.CFrame.LookVector

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

	currentYaw = targetYaw

	targetPitch = 0
	currentPitch = 0

	updateVisibility()
end

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

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

	if gameProcessed then
		return
	end

	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)

--------------------------------------------------
-- MOBILE TOUCH START
--------------------------------------------------

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

	if gameProcessed then
		return
	end

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

		local cam = getCamera()

		if not cam then
			return
		end

		local viewport = cam.ViewportSize

		-- Right side of screen = camera
		if input.Position.X >= viewport.X * 0.45 then

			cameraTouch = true
			lastTouchPosition = input.Position
		end
	end
end)

--------------------------------------------------
-- MOBILE TOUCH MOVE
--------------------------------------------------

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

	if gameProcessed then
		return
	end

	if not firstPerson then
		return
	end

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

		local position = input.Position

		local delta =
			position -
			lastTouchPosition

		lastTouchPosition = position

		targetYaw -=
			delta.X *
			TOUCH_SENSITIVITY

		targetPitch -=
			delta.Y *
			TOUCH_SENSITIVITY

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

--------------------------------------------------
-- MOBILE TOUCH END
--------------------------------------------------

UserInputService.InputEnded:Connect(function(input)

	if input.UserInputType == Enum.UserInputType.Touch then
		cameraTouch = false
	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(45, 45)
	button.Position = UDim2.fromOffset(20, 20)

	button.BackgroundColor3 =
		Color3.fromRGB(40, 40, 40)

	button.BackgroundTransparency = 0.25

	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

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

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

	if gameProcessed then
		return
	end

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

--------------------------------------------------
-- CAMERA UPDATE
--------------------------------------------------

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

		local cam = getCamera()

		if not cam then
			return
		end

		cam.CameraType =
			Enum.CameraType.Scriptable

		--------------------------------------------------
		-- SMOOTH ROTATION
		--------------------------------------------------

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

		currentYaw +=
			(targetYaw - currentYaw)
			* alpha

		currentPitch +=
			(targetPitch - currentPitch)
			* alpha

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

		if firstPerson then

			--------------------------------------------------
			-- CAMERA AT HEAD POSITION
			--------------------------------------------------

			local cameraPosition =
				head.Position

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

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

			cam.FieldOfView =
				FIRST_PERSON_FOV

			--------------------------------------------------
			-- BODY ROTATES ONLY HORIZONTALLY
			--------------------------------------------------

			local look =
				rotation.LookVector

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

			if flatLook.Magnitude > 0 then

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

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

		else

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

			local direction =
				rotation.LookVector

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

			cam.CFrame =
				CFrame.lookAt(
					position,
					rootPart.Position +
					Vector3.new(0, 1.5, 0)
				)

			cam.FieldOfView =
				THIRD_PERSON_FOV
		end
	end
)

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

if player.Character then

	setupCharacter(player.Character)

end

player.CharacterAdded:Connect(function(newCharacter)

	task.wait(0.1)

	setupCharacter(newCharacter)

end)

createMobileButton()