Player.character = nil script not working as expected

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve?
    I am making a game like blade ball, but with different game modes.
  2. What is the issue?
    after a player blocks the ball, it is supposed to target the closest player that is not the person who blocked it. but it keep targeting the player who blocked it.

server script (name: BallHandle)

local replicatedStorage = game:GetService("ReplicatedStorage")
local serverStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local config = require(game.ServerScriptService:WaitForChild("Config"))

local CSpeed = config.BallSpeed
local gameActive = replicatedStorage.RoundSystemEvents.GameActive

local ball = serverStorage.Ball
local clonedBall
local targetPlayer
local playerWhoBlocked = nil
local charWhoBlocked = nil
local deadPlayers = {}

local function findNearestPlr(PreviousTarget)
	local nearestPlr = nil
	local ValidPlrs = 0
	local shortestDistance = math.huge
	
	for i, plr in pairs(Players:GetPlayers()) do
--ERROR ON LINE BELOW
		local distance = (plr.Character.HumanoidRootPart.Position - ball.Position).magnitude
		local InGame = plr:FindFirstChild("InGame")
		
		if InGame then
			ValidPlrs +=1
			if distance < shortestDistance and not table.find( deadPlayers, plr.UserId) and PreviousTarget ~= plr.UserId then
				shortestDistance = distance
				nearestPlr = plr
			end
		end		
	end
	if ValidPlrs > 1 then
		targetPlayer = nearestPlr
	end
end

local function reset()
	if clonedBall then
		clonedBall:Destroy()
	end
	
	CSpeed = config.BallSpeed
	targetPlayer = nil
	
	for i,plr in pairs(Players:GetPlayers()) do
		if plr.Character and plr.Character:FindFirstChildOfClass("Highlight") then
			plr.Character:FindFirstChildOfClass("Highlight"):Destroy()
		end
	end
end

local function HighlightPlayers()
	for i,plr in pairs(Players:GetPlayers()) do
		if plr:FindFirstChild("InGame") then 
			if plr.Character and plr.Character:FindFirstChildOfClass("Highlight") then
				plr.Character:FindFirstChildOfClass("Highlight"):Destroy()
			end
			
			local highlight = Instance.new("Highlight", plr.Character)
			highlight.Adornee = plr.Character
			
			if plr == targetPlayer then
				highlight.FillColor = Color3.fromRGB(255,0,0)
				highlight.OutlineColor = Color3.fromRGB(255,0,0)
			else
				highlight.FillTransparency = 1
				highlight.OutlineColor = Color3.fromRGB(255,255,255)
			end
		end
	end
end

local function SpawnBall()
	reset()
	findNearestPlr()
	
	if not targetPlayer or gameActive.Value ~= true then
		reset()
		return
	end
	
	clonedBall = ball:Clone()
	clonedBall.Parent = workspace
	
	HighlightPlayers()
	
	clonedBall.Touched:Connect(function(hit)
		local HRP = hit.Parent:FindFirstChild("HumanoidRootPart")

		if HRP then
			if HRP.Parent == charWhoBlocked  then
				return
			end
			if HRP.Parent.Blocking.Value == false or HRP.Parent.Blocking == nil then
				local explosion = Instance.new("Explosion")
				explosion.BlastRadius = 1
				explosion.BlastPressure = 5
				explosion.Position = HRP.Position
				explosion.Parent = HRP
				
				local InGame = targetPlayer:FindFirstChild("InGame")
				if InGame then
					InGame:Destroy()
				end
				
				if not table.find(deadPlayers, targetPlayer.UserId) then
					table.insert(deadPlayers, targetPlayer.UserId)
				end
				if playerWhoBlocked ~= nil then
					game.Players:GetPlayerByUserId(playerWhoBlocked).leaderstats.Kills.Value +=1
					
				end
				
				reset()
				task.wait(0.5)
				
				if gameActive.Value == true then
					SpawnBall()
				end
			else
				print("Blocked!")
				playerWhoBlocked = targetPlayer
				charWhoBlocked = targetPlayer.Character
				findNearestPlr(targetPlayer.UserId)
				CSpeed	= CSpeed + 0.5
				
			end
		end
	end)
end

Players.PlayerRemoving:Connect(function(plr)
	if plr == targetPlayer then
		table.insert(deadPlayers, plr.UserId)
		SpawnBall()
	end
end)

gameActive.Changed:Connect(function()
	if gameActive.Value == true then
		task.wait(1.5)
		SpawnBall()
	else
		table.clear(deadPlayers)
	end
end)

RunService.Heartbeat:Connect(function()
	if clonedBall == nil then
		SpawnBall()
	end
	
	if targetPlayer and gameActive.Value == true and targetPlayer:FindFirstChild("InGame") then
		local targetPosition = targetPlayer.Character:WaitForChild("Head").Position
		local currentPosition = clonedBall.Position
		local direction = (targetPosition - currentPosition)
		CSpeed = CSpeed + config.BallAcceleration
		clonedBall.Velocity = direction * CSpeed
	else
		reset()
	end
end)

1 Like

I would try to add another if statement to check if the player has a character on the line before the error occurs when looping through each player.

 if plr.Character then

I think this may work as I have had a similar issue in previous projects where it will return an error if the character has not loaded fully or the player had died, reset or they have left the game.

1 Like

You should be using something else than trying to scan through every player, also are there some other thing than Player instance in the game?

Sometimes Player.Character can be nil, so you should always check that before running anything else ^ Like comment above

It is more efficient to use workspace:GetPartsInRadius() instead, with OverlapParams on all player characters’ HumanoidRootPart.

local ballPosition: Vector3 = ball.Position
local rootPartsInRadius: Array<Part> = workspace:GetPartsInRadius()
table.sort(rootPartsInRadius, function(a,b)
return (a.Position - ballPosition).Magnitude < (a.Position - ballPosition).Magnitude
end)

local closetRootPart: Part = rootPartsInRadius[1]
local closetPlayerCharacter: Model = closetRootPart.Parent
1 Like

Maybe add an if statement to check if the player has a valid HumanoidRootPart at the time of accessing it.

if plr.Character:FindFirstChild("HumanoidRootPart") then
 -- code here
end
1 Like

Sorry for the late reply I will try this now.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.