Ballcamera isn't functioning as intended

Hi Devforum, today I have encountered something that I need help with!

What do you want to achieve? NFL ball camera that focuses on only ONE ball and that it stops following the selected ball when it needs to.

What is the issue? The ballcam signals/sensors doesn’t make sure of the following:

  • that the ballcam stops following the ball when the script says so
  • when the ball gets destroyed, that the ballcam still doesn’t stop following the ball

What solutions have you tried so far? I have looked into the devforum, but i just can’t find the solution??

Video of the ballcam:

The ballcam’s code:

player = game.Players.LocalPlayer
repeat wait() until player

local camera = game.Workspace.CurrentCamera	

local player = game:GetService("Players").LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:FindFirstChild("HumanoidRootPart")	
local humanoid = character:FindFirstChildWhichIsA("Humanoid")	
local CurrentBall

local PartList = {
["WedgePart"] = true,
["Part"] = true,
["CornerWedgePart"] = true,
["MeshPart"] = true,
["TrussPart"] = true,
}

local function Toggle(Boolean, SelectedBall)		
if Boolean == true then 
elseif Boolean == false then
if SelectedBall == CurrentBall then	
CurrentBall = nil				
camera.CameraSubject = humanoid 			
else return	end		
end	
	
if SelectedBall:IsDescendantOf(workspace) and PartList[SelectedBall.ClassName] then 						
CurrentBall = SelectedBall		
camera.CameraSubject =	SelectedBall			
else
CurrentBall = nil		
camera.CameraSubject = humanoid 							
return end		
end	

game.ReplicatedStorage:FindFirstChild("Events").BallCam.OnClientEvent:Connect(function(Enabled, SelectedBall)	
Toggle(Enabled, SelectedBall)	
end)

workspace.DescendantRemoving:Connect(function(Child)
if Child:IsDescendantOf(workspace) and PartList[Child.ClassName] then
if Child == CurrentBall then else return end			
Toggle(false, CurrentBall)			
end		
end)		

Any scripting corrections/solutions would be deeply appreciated!

You aren’t changing the camera type to scriptable and follow, I believe this will fix your error.
(Also, I know this isn’t a huge priority but it is unwise to take gameplay style / visuals from Football Fusion :man_shrugging: )

I’m noticing quite a few interesting choices in your code. I’m gonna assume the lack of indentation is due to some weird copy-paste issue, but you have the following:

-- Example 1:
if Boolean == true then -- Bad name for a variable, it should be named after what it represents
elseif Boolean == false then
    if SelectedBall == CurrentBall then
        ...
    end
end

-- Example 2:
if Child == CurrentBall then else return end

Variables in Lua are typically in snakeCase, not a big deal but something to keep in mind. The code I highlighted above though is something you might want to look into, as it is pretty weird.

-- "Fix" for example 1:
if not Boolean then
    if SelectedBall == CurrentBall then
        ...
    end
end

-- Alternative "fix" for example 1:
if not Boolean and SelectedBall == CurrentBall then
    ...
end


-- "Fix" for example 2:
if Child ~= CurrentBall then return end

ok so
if you made your code a lot cleaner you wouldn’t have bugs like this and bugfixing would be a lot smoother and writing and reading would bo so much easier

here’s the main problems your doing

  1. player(first variable) is a global this is bad don’t
  2. you redeclared it in the local variable below
  3. local player should always be available never encountered a case where is had to do that
  4. DO 4 SPACES(TAB FOR SHORT) THAT IS A INDENT, you have NO indents and it looks horrible
1 Like

Also, adding on to what @ifkpop said, there are some code choices in here that are definitley questionable.

local player = game.Players.LocalPlayer
local camera = game.Workspace.CurrentCamera	
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:FindFirstChild("HumanoidRootPart")	
local humanoid = character:FindFirstChildWhichIsA("Humanoid")	
local CurrentBall

local PartList = {
["WedgePart"] = true,
["Part"] = true,
["CornerWedgePart"] = true,
["MeshPart"] = true,
["TrussPart"] = true,
}

local function Toggle(Boolean, SelectedBall)		
if Boolean == true then 
elseif Boolean == false then
if SelectedBall == CurrentBall then	
CurrentBall = nil
camera.CameraType = follow				
camera.CameraSubject = nil 			
else return	end		
end	
	
if SelectedBall:IsDescendantOf(workspace) and PartList[SelectedBall.ClassName] then 						
CurrentBall = SelectedBall		
camera.CameraSubject =	SelectedBall			
else
CurrentBall = nil		
camera.CameraType = follow				
camera.CameraSubject = nil						
return end		
end	

game.ReplicatedStorage:FindFirstChild("Events").BallCam.OnClientEvent:Connect(function(Enabled, SelectedBall)	
Toggle(Enabled, SelectedBall)	
end)

workspace.DescendantRemoving:Connect(function(Child)
if Child:IsDescendantOf(workspace) and PartList[Child.ClassName] then
if Child == CurrentBall then else return end			
Toggle(false, CurrentBall)			
end		
end)

This should work, tell me if it fixes it.

It still doesn’t work as fully intended, here’s the current code:

local player = game.Players.LocalPlayer
local camera = game.Workspace.CurrentCamera	
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:FindFirstChild("HumanoidRootPart")	
local humanoid = character:FindFirstChildWhichIsA("Humanoid")	
local CurrentBall

local PartList = {
["WedgePart"] = true,
["Part"] = true,
["CornerWedgePart"] = true,
["MeshPart"] = true,
["TrussPart"] = true,
}

local function Toggle(Boolean, SelectedBall)		
if not Boolean then
if SelectedBall == CurrentBall then
CurrentBall = nil
camera.CameraType = Enum.CameraType.Fixed				
camera.CameraSubject = humanoid 			
else return	end		
end		
	
if SelectedBall:IsDescendantOf(workspace) and PartList[SelectedBall.ClassName] then 						
CurrentBall = SelectedBall
camera.CameraType = Enum.CameraType.Follow				
camera.CameraSubject = SelectedBall 			
else
CurrentBall = nil		
camera.CameraType = Enum.CameraType.Fixed				
camera.CameraSubject = humanoid						
return end		
end	

game.ReplicatedStorage:FindFirstChild("Events").BallCam.OnClientEvent:Connect(function(Enabled, SelectedBall)	
Toggle(Enabled, SelectedBall)	
end)

workspace.DescendantRemoving:Connect(function(Child)
if Child:IsDescendantOf(workspace) and PartList[Child.ClassName] then
if Child ~= CurrentBall then 			
Toggle(false, CurrentBall)			
end
end		
end)

And if you’re wondering, it still behaves like the previous video i showed :thinking:

camera.CameraType = Enum.CameraType.Fixed				
camera.CameraSubject = humanoid 

Change this to

camera.CameraType = Enum.CameraType.Follow				
camera.CameraSubject = nil 

Unfortunately, still the same behaviour.

Hmmm, is it possible there are other scripts affecting it? Also, if you reset, what happens (when the camera is on the ball)

  1. The NFL ball’s server-script fires to the client only when it gets thrown, or when it lands.
  2. When the player dies while the camera is on the ball, the camera resets and is on the character again. (specifically the humanoid.)

Can you add some prints into the script? Tell me what isn’t working, like where the print doesnt work.

Here is a list of prints that should’ve been printed:

print("currently following the ball.")
print("stopped following the ball.")
print("ball isn't located in workspace.")
print("ball is apparently destroyed.")	

Hm, that’s weird. Have you tried printing the camera type?

It only printed out the “follow” cameratype.

Go on the server and tell me if the ball is actually being destroyed, as this would explain why it doesn’t change the camera, I’ll keep looking over the code for a solution.

Here, try this script for the function

local function Toggle(Boolean, SelectedBall)
    if not Boolean then
        if SelectedBall == CurrentBall then
            CurrentBall = nil
        end
        camera.CameraType = Enum.CameraType.Fixed
        camera.CameraSubject = humanoid
        return
    end

    if SelectedBall:IsDescendantOf(workspace) and PartList[SelectedBall.ClassName] then
        CurrentBall = SelectedBall
        camera.CameraType = Enum.CameraType.Follow
        camera.CameraSubject = SelectedBall
    else
        CurrentBall = nil
        camera.CameraType = Enum.CameraType.Fixed
        camera.CameraSubject = humanoid
    end
end

Altough the ballcam doesn’t print it, it does fly into the void causing it to be destroyed, any clues over here?

Try the script I just sent and tell me what happens. The issue with the script was that if the SelectedBall is not equal to the CurrentBall , the camera type and subject will not be reset, potentially causing the camera to continue following the previously selected ball object even when it is no longer valid or removed from the game world.

Something interesting happend, when the ballcam triggers the signal to stop following the ball, it actually does but the camera then stays on its position. And the script detects if the ball got destroyed.

Current code:

local player = game.Players.LocalPlayer
local camera = game.Workspace.CurrentCamera	
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:FindFirstChild("HumanoidRootPart")	
local humanoid = character:FindFirstChildWhichIsA("Humanoid")	
local CurrentBall

local PartList = {
["WedgePart"] = true,
["Part"] = true,
["CornerWedgePart"] = true,
["MeshPart"] = true,
["TrussPart"] = true,
}

local function Toggle(Boolean, SelectedBall)
	if not Boolean then
		if SelectedBall == CurrentBall then
			CurrentBall = nil
		end
		camera.CameraType = Enum.CameraType.Fixed
		camera.CameraSubject = humanoid
		print("stopped following the ball.")
		return
	end

	if SelectedBall:IsDescendantOf(workspace) and PartList[SelectedBall.ClassName] then
		CurrentBall = SelectedBall
		camera.CameraType = Enum.CameraType.Follow
		camera.CameraSubject = SelectedBall
		print("currently following the ball.")
	else
		CurrentBall = nil
		camera.CameraType = Enum.CameraType.Fixed
		camera.CameraSubject = humanoid
		print("ball isn't located in workspace.")
	end
end

game.ReplicatedStorage:FindFirstChild("Events").BallCam.OnClientEvent:Connect(function(Enabled, SelectedBall)	
Toggle(Enabled, SelectedBall)	
end)

workspace.DescendantRemoving:Connect(function(Child)
if Child:IsDescendantOf(workspace) and PartList[Child.ClassName] then
if Child ~= CurrentBall then 		
Toggle(false, CurrentBall)			
--print(camera.CameraType.Name)				
print("ball is apparently destroyed.")				
end			
end		
end)

I’ve found a solution thanks to @RealMysticall and everyone that helped in this thread!

1 Like