Camera Manipulation on Clicking a Part

Hello, I’m trying to make a script where when you click a part, it will make the camera hover above the part and when the player moves, it tweens back to the player. New to scripting, problems are bound to be faced so I require some help in this…

event.OnClientEvent:Connect(function(Grab)

	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = Grab.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
	Animation:Play()
	
	CurrentCamera.Focus = Grab.CFrame
	
	
	
	local player = game.Players.LocalPlayer
wait(1)
player.Character.Humanoid.Running:Connect(function(speed)
	    if speed > 0 then
	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = player.Character.Head.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
			Animation:Play()
			wait(2)
			Animation:Cancel()
	CurrentCamera.CameraType = Enum.CameraType.Custom		
			
end
end)
end)

The end result is that the camera tweens too close to the brick (I want it to be a bit higher) and then how do I fix the constant tweening whenever a player keeps moving after that? I know I made the silly error but I’m not sure how to fix the issue…

1 Like

Just change the CFrame of the initial goal to something like:

local Goal = {CFrame = CFrame.new(Grab.CFrame.X, Grab.CFrame.Y + somenumber, Grab.CFrame.Z)}
1 Like

Ah thanks, how about the running function?

Ah well, I’ve managed to play around and made it so that when I move, it returns back to the normal player camera, but I can’t seem to have it tween back to the player without the function running everytime the character moves

player.Character.Humanoid.Running:Connect(function(speed)
		    if speed > 0 then
				Animation:Cancel()
		CurrentCamera.CameraType = Enum.CameraType.Custom	
		CurrentCamera.CameraSubject = player.Character.Humanoid	
			
end
end)
end)

You should put it in a loop and then wait for the animation to complete and break the loop

event.OnClientEvent:Connect(function(Grab)

	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = Grab.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
	Animation:Play()
	
	CurrentCamera.Focus = Grab.CFrame
	
	
	
	local player = game.Players.LocalPlayer
wait(1)
local function x()
player.Character.Humanoid.Running:Connect(function(speed)
	    if speed > 0 then
	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = player.Character.Head.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
			Animation:Play()
			wait(2)

			Animation:Cancel()
	CurrentCamera.CameraType = Enum.CameraType.Custom
break
			
end
end)
end
local newcor = coroutine.wrap(function() while wait() do x() end end)
newcor()
end)

Also, could you send me a copy of this, so I can try it out for myself

The script:

-- Local Script:
local Clicky = script.Parent
local Grab = script.Parent.Parent
local event = game.ReplicatedStorage.Camera


Clicky.MouseClick:Connect(function(player)
	event:FireClient(player, Grab)
end)

-- Server Script aka your script
event.OnClientEvent:Connect(function(Grab)

	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = Grab.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
	Animation:Play()
	
	CurrentCamera.Focus = Grab.CFrame
	
	
	
	local player = game.Players.LocalPlayer
wait(1)
local function x()
player.Character.Humanoid.Running:Connect(function(speed)
	    if speed > 0 then
	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = player.Character.Head.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
			Animation:Play()
			wait(2)

			Animation:Cancel()
	CurrentCamera.CameraType = Enum.CameraType.Custom
break
			
end
end)
end
local newcor = coroutine.wrap(function() while wait() do x() end end)
newcor()
end)

for devforum.rbxl (19.5 KB)

This is an awful idea because you’re creating multiple new listeners every single second, which will create massive memory leaks. You only need to create the listener once for the player. And since this function can be called multiple times on the same player, you will want to disconnect the listener at the end of the function.

Here is the new script with the lines I added commented:

local Clicky = script.Parent
local Grab = script.Parent.Parent
local TweenService = game:GetService("TweenService")
local event = game.ReplicatedStorage.Camera
local player = game.Players.LocalPlayer -- added player variable to top of script

local CurrentCamera = workspace.CurrentCamera


event.OnClientEvent:Connect(function(Grab)
	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = Grab.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
	Animation:Play()
	Animation.Completed:Wait() -- wait for tween to finish
	CurrentCamera.Focus = Grab.CFrame
	
	cancelOnMove = player.Character.Humanoid.Running:Connect(function(speed) -- save the connection to remove later
		if speed > 0 then
			CurrentCamera.CameraType = Enum.CameraType.Scriptable
			local TI = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
			local Goal = {CFrame = player.Character.Head.CFrame}
			local Animation = TweenService:Create(CurrentCamera, TI, Goal)
			Animation:Play()
			Animation.Completed:Wait() -- again, wait for tween
			CurrentCamera.CameraType = Enum.CameraType.Custom
			
			cancelOnMove:Disconnect() -- disconnect listener to prevent memory leaks
		end
	end)
end)
1 Like

This works… however I found a bug where if you click the brick twice, the function is never removed so it keeps tweening back to the player constantly when the player moves. Any way around this?

Add a debounce so the function can only run once.

local debounce = false -- used to limit calling of function
event.OnClientEvent:Connect(function(Grab)
    if debounce then return end -- stop function early if it's already running
    debounce  = true
	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	local TI = TweenInfo.new(5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
	local Goal = {CFrame = Grab.CFrame}
	local Animation = TweenService:Create(CurrentCamera, TI, Goal)
	Animation:Play()
	Animation.Completed:Wait() -- wait for tween to finish
	CurrentCamera.Focus = Grab.CFrame
	
	cancelOnMove = player.Character.Humanoid.Running:Connect(function(speed) -- save the connection to remove later
		if speed > 0 then
			CurrentCamera.CameraType = Enum.CameraType.Scriptable
			local TI = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0)
			local Goal = {CFrame = player.Character.Head.CFrame}
			local Animation = TweenService:Create(CurrentCamera, TI, Goal)
			Animation:Play()
			Animation.Completed:Wait() -- again, wait for tween
			CurrentCamera.CameraType = Enum.CameraType.Custom
			
			cancelOnMove:Disconnect() -- disconnect listener to prevent memory leaks
            debounce = false -- allow function to run again
		end
	end)
end)
1 Like