Compass Help, Doesn't work after dying

This compass script doesn’t work after dying.

local frame = script.Parent
local n, e, s, w, ne, nw, se, sw, nw2, n2, ne2 = frame.N, frame.E, frame.S, frame.W, frame.NE, frame.NW, frame.SE, frame.SW, frame.NW2, frame.N2, frame.NE2
local directions = {nw, n, ne, e, se, s, sw, w, nw2, n2, ne2}
local camera, cameraPart = workspace.CurrentCamera, workspace.CameraPart
local absoluteSize, canvasSize, Inc = 0, 0, 0

if not cameraPart or not cameraPart:IsDescendantOf(workspace) then
	-- Find or recreate cameraPart here
	return
end

local function updateTextColor(textLabel, condition)
	if condition then
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98) 
	else
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
	end
end


local function partToCamera() 
	cameraPart.CFrame = camera.CFrame 
end

local function tickMarks(position, thickness)	
	local mark = Instance.new("Frame")
	mark.AnchorPoint = Vector2.new(1, 0)
	mark.Position = UDim2.new(0, position, 0, 0)
	mark.BorderSizePixel = 0
	mark.BackgroundColor3 = Color3.fromRGB(171, 142, 98)
	mark.Name = "TickMark"
	mark.Parent = frame

	if thickness == "thicker" then mark.Size = UDim2.new(0, 3, -0.1, 1) end
	if thickness == "thick" then mark.Size = UDim2.new(0, 2, -0.1, 1) end
	if thickness == "thin" then mark.Size = UDim2.new(0, 1, 0.5, 1) end

	return mark	
end

local function removeTickMarks()
	for i, v in pairs(frame:GetChildren()) do		
		if v.Name == "TickMark" then v:Destroy() end		
	end		
end

local function updateTickMarks()
	for i, v in pairs(frame:GetChildren()) do
		if v:IsA("TextLabel") then
			local pxPos = v.Position.X.Offset

			if #v.Text == 1 then tickMarks(pxPos, "thicker") end -- N, W, S, E
			if #v.Text == 2 then tickMarks(pxPos, "thick") end -- Others
		end

	end

	for j = 22.5, 427.5, 45 do tickMarks(j * Inc, "thin") end
	

	--for k = 11.25, 416.25, 45 do tickMarks(k * Inc, "thin") end
	--for l = 33.75, 438.75, 45 do tickMarks(l * Inc, "thin") end
end

local function positionElements()
	absoluteSize = frame.AbsoluteSize.X
	canvasSize = absoluteSize * 5

	Inc = (absoluteSize * 4) / 360

	for i, dir in ipairs(directions) do	
		dir.Position = UDim2.new(0, 45 * (i - 1) * Inc, 0.5, 0)
	end

	removeTickMarks()
	updateTickMarks()

	frame.CanvasSize = UDim2.new(0, canvasSize, 0, 0)
end

local function moveWithOrientation()
	local orientationY = cameraPart.Orientation.Y % 360 
	local deg = (360 - orientationY) % 360 
	local inc = (absoluteSize * 4) / 360
	frame.CanvasPosition = Vector2.new(deg * inc, 0) 
	positionElements()

	local centerPos = frame.AbsoluteSize.X / 2 

	for i, dir in ipairs(directions) do
		local labelPos = (45 * (i - 1) * Inc) - frame.CanvasPosition.X % canvasSize
		local distanceToCenter = math.abs(centerPos - labelPos)
		if distanceToCenter < 10 or distanceToCenter > canvasSize - 10 then
			dir.TextColor3 = Color3.fromRGB(255, 255, 255) 
		else
			dir.TextColor3 = Color3.fromRGB(171, 142, 98) 
		end
	end
end

local Players = game:GetService("Players")

local function onCharacterAdded(character)
    cameraPart = character:WaitForChild("CameraPart") -- Adjust based on actual child
    -- Re-setup any connections or states needed
    partToCamera()
    moveWithOrientation()
end

local function onPlayerAdded(player)
    player.CharacterAdded:Connect(onCharacterAdded)
end

Players.PlayerAdded:Connect(onPlayerAdded)



moveWithOrientation()
partToCamera()

cameraPart:GetPropertyChangedSignal("Orientation"):Connect(moveWithOrientation)
frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(positionElements)
camera:GetPropertyChangedSignal("CFrame"):Connect(partToCamera)

Set the ResetOnSpawn property to true for the compass.

1 Like

I did insert this lol

local frame = script.Parent
frame.ResetOnSpawn = true  
1 Like

On ScreenGui. Not Frame
character

1 Like

It’s suppose to be done on the screengui and mostly manually.

If you are talking about this, it has been on the whole time

Well that’s odd. Can you tell me what really happens to your compass after you reset? Does it just stop working or does it throw any errors?

If this is running from a LocalScript, the onPlayerAdded function would never run for the LocalPlayer, since the PlayerAdded event would fire for them before that code was able to run. As a result, the CharacterAdded event is never connected to the onCharacterAdded function, which means that the camera-related function are not being run upon the Character respawning.

Additionally, in its current state, this would be running both the partToCamera and moveWithOrientation functions for every player in the game any time that someone respawned. Assuming you want these to run on a per-player basis (so that it only calls those functions again for players whose Characters have just respawned, rather than for every player in the game when 1 Character respawns), this should be based on LocalPlayer.CharacterAdded instead of having it listen for other players to join the game.

Example Revision

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local function onCharacterAdded(character)
    cameraPart = character:WaitForChild("CameraPart") -- Adjust based on actual child
    -- Re-setup any connections or states needed
    partToCamera()
    moveWithOrientation()
end

if player.Character then
    onCharacterAdded(player.Character)
end

player.CharacterAdded:Connect(onCharacterAdded)

--[[ This would remove the need for the
"partToCamera" and "moveWithOrientation" function calls that were below --]]

However, given that ResetOnSpawn was already enabled for the ScreenGui, I’m not exactly sure why the code would not have been working upon respawning, since the old ScreenGui and its LocalScript would have been destroyed, and a completely new copy of the ScreenGui would be given to the player (meaning that the code from the new LocalScript would have started from the very top again, eventually calling the moveWithOrientation and partToCamera functions independently from the onCharacterAdded function).

As @lonely1and1afraid mentioned, it would be useful to know more of the specifics about what happens upon respawning (e.g. if an error appears in the Output, if the compass momentarily works but then breaks, etc.)


I’m also a bit confused about the cameraPart variable, because it’s initially referencing an object in the Workspace but then in the onCharacterAdded function, it updates it to reference an object in the Character model. Were you intending for it to default to the one in the Workspace when it could not be found in the Character model or is it meant to be the intended cameraPart for the very first spawn upon loading into the game until the player’s Character respawns for the first time?

It says CameraPart is not a valid member of workspace. That means I have to put a script under CameraPart so it appears when you spawn?

Assuming this is to optimise and make my script better, I rewrote it and took your advice:

local Players = game:GetService("Players")
local player = Players.LocalPlayer 
local frame = script.Parent  

-- Define a list of directions directly
local directions = {
    frame:FindFirstChild("N"), frame:FindFirstChild("E"), frame:FindFirstChild("S"), frame:FindFirstChild("W"),
    frame:FindFirstChild("NE"), frame:FindFirstChild("NW"), frame:FindFirstChild("SE"), frame:FindFirstChild("SW"),
    frame:FindFirstChild("NW2"), frame:FindFirstChild("N2"), frame:FindFirstChild("NE2")
}

local function updateTickMarks()
    local tickPositionIncrement = frame.AbsoluteSize.X * 4 / 360

    for _, direction in ipairs(directions) do
        if direction then
            local pxPos = (45 * (table.indexOf(directions, direction) - 1) * tickPositionIncrement) % (frame.AbsoluteSize.X * 5)
            local mark = Instance.new("Frame", frame)
            mark.Name = "TickMark"
            mark.AnchorPoint = Vector2.new(1, 0)
            mark.Position = UDim2.new(0, pxPos, 0, 0)
            mark.BorderSizePixel = 0
            mark.BackgroundColor3 = Color3.fromRGB(171, 142, 98)
            
            -- Adjust size based on the text length for visual distinction
            local thickness = (#direction.Text == 1 and "thicker") or (#direction.Text == 2 and "thick") or "thin"
            local sizeMapping = { thicker = 3, thick = 2, thin = 1 }
            mark.Size = UDim2.new(0, sizeMapping[thickness], -0.1, 1)
        end
    end
end

local function adjustCameraPartOrientation(cameraPart)
    -- Move with orientation based on camera part's Y orientation
    local orientationY = cameraPart.Orientation.Y % 360
    local deg = (360 - orientationY) % 360
    local increment = (frame.AbsoluteSize.X * 4) / 360
    frame.CanvasPosition = Vector2.new(deg * increment, 0)

    -- Update colors and positions of direction labels based on orientation
    local centerPos = frame.AbsoluteSize.X / 2
    for _, dir in ipairs(directions) do
        if dir then
            local labelPos = (45 * (table.indexOf(directions, dir) - 1) * increment) - frame.CanvasPosition.X % (frame.AbsoluteSize.X * 5)
            local distanceToCenter = math.abs(centerPos - labelPos)
            dir.TextColor3 = (distanceToCenter < 10 or distanceToCenter > frame.AbsoluteSize.X * 5 - 10) and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(171, 142, 98)
        end
    end
end

-- Function to handle character additions, setting up camera and UI updates
local function onCharacterAdded(character)
    local cameraPart = character:WaitForChild("CameraPart")  -- Expect a part named "CameraPart"

    -- Initial setup for the camera part orientation and UI elements
    adjustCameraPartOrientation(cameraPart)
    updateTickMarks()

    -- Connect events to dynamically update the orientation and tick marks
    cameraPart:GetPropertyChangedSignal("Orientation"):Connect(function()
        adjustCameraPartOrientation(cameraPart)
    end)
    frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateTickMarks)
end

-- Connect to the CharacterAdded event and handle existing character
player.CharacterAdded:Connect(onCharacterAdded)
if player.Character then
    onCharacterAdded(player.Character)
end

This ended up completely breaking the script. Sorry I am a bit slow when it comes to scripting.

1 Like

No just use a WaitForChild and it would probably work then.

Are there any errors in the Output after making those changes? A lot of stuff was changed in comparison to the code from the original post, and I haven’t been able to immediately pinpoint anything that might be causing an issue.

Edit: Ah, I saw something right after posting my reply:

(In the updateTickMarks function)

I checked the documentation for table, and I don’t think indexOf exists. Were you trying to refer to the direction at that index of the table?



No worries! The Help and Feedback category of the forum is meant for asking questions, sharing knowledge, and helping others out, after all, so you don’t need to worry about that.

(Oh, one thing I just noticed; I would recommend moving this topic from the “Platform Usage Support” to the “Scripting Support” sub-category. I think it lets you do that from editing the title, but not sure)

Haha, I forgot indexOf doesn’t exist in lua. So I revised it

local frame = script.Parent
local n, e, s, w, ne, nw, se, sw, nw2, n2, ne2 = frame.N, frame.E, frame.S, frame.W, frame.NE, frame.NW, frame.SE, frame.SW, frame.NW2, frame.N2, frame.NE2
local directions = {nw, n, ne, e, se, s, sw, w, nw2, n2, ne2}
local camera, cameraPart = workspace.CurrentCamera, workspace.CameraPart
local absoluteSize, canvasSize, Inc = 0, 0, 0

if not cameraPart or not cameraPart:IsDescendantOf(workspace) then
	-- Find or recreate cameraPart here
	return
end

local function updateTextColor(textLabel, condition)
	if condition then
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98) 
	else
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
	end
end


local function partToCamera() 
	cameraPart.CFrame = camera.CFrame 
end

local function tickMarks(position, thickness)	
	local mark = Instance.new("Frame")
	mark.AnchorPoint = Vector2.new(1, 0)
	mark.Position = UDim2.new(0, position, 0, 0)
	mark.BorderSizePixel = 0
	mark.BackgroundColor3 = Color3.fromRGB(171, 142, 98)
	mark.Name = "TickMark"
	mark.Parent = frame

	if thickness == "thicker" then mark.Size = UDim2.new(0, 3, -0.1, 1) end
	if thickness == "thick" then mark.Size = UDim2.new(0, 2, -0.1, 1) end
	if thickness == "thin" then mark.Size = UDim2.new(0, 1, 0.5, 1) end

	return mark	
end

local function removeTickMarks()
	for i, v in pairs(frame:GetChildren()) do		
		if v.Name == "TickMark" then v:Destroy() end		
	end		
end

local function updateTickMarks()
	for i, v in pairs(frame:GetChildren()) do
		if v:IsA("TextLabel") then
			local pxPos = v.Position.X.Offset

			if #v.Text == 1 then tickMarks(pxPos, "thicker") end -- N, W, S, E
			if #v.Text == 2 then tickMarks(pxPos, "thick") end -- Others
		end

	end

	for j = 22.5, 427.5, 45 do tickMarks(j * Inc, "thin") end


	--for k = 11.25, 416.25, 45 do tickMarks(k * Inc, "thin") end
	--for l = 33.75, 438.75, 45 do tickMarks(l * Inc, "thin") end
end

local function positionElements()
	absoluteSize = frame.AbsoluteSize.X
	canvasSize = absoluteSize * 5

	Inc = (absoluteSize * 4) / 360

	for i, dir in ipairs(directions) do	
		dir.Position = UDim2.new(0, 45 * (i - 1) * Inc, 0.5, 0)
	end

	removeTickMarks()
	updateTickMarks()

	frame.CanvasSize = UDim2.new(0, canvasSize, 0, 0)
end

local function moveWithOrientation()
	local orientationY = cameraPart.Orientation.Y % 360 
	local deg = (360 - orientationY) % 360 
	local inc = (absoluteSize * 4) / 360
	frame.CanvasPosition = Vector2.new(deg * inc, 0) 
	positionElements()

	local centerPos = frame.AbsoluteSize.X / 2 

	for i, dir in ipairs(directions) do
		local labelPos = (45 * (i - 1) * Inc) - frame.CanvasPosition.X % canvasSize
		local distanceToCenter = math.abs(centerPos - labelPos)
		if distanceToCenter < 10 or distanceToCenter > canvasSize - 10 then
			dir.TextColor3 = Color3.fromRGB(255, 255, 255) 
		else
			dir.TextColor3 = Color3.fromRGB(171, 142, 98) 
		end
	end
end

local Players = game:GetService("Players")

local function onCharacterAdded(character)
	cameraPart = character:WaitForChild("CameraPart") -- Adjust based on actual child
	-- Re-setup any connections or states needed
	partToCamera()
	moveWithOrientation()
end

local function onPlayerAdded(player)
	player.CharacterAdded:Connect(onCharacterAdded)
end

Players.PlayerAdded:Connect(onPlayerAdded)



moveWithOrientation()
partToCamera()

cameraPart:GetPropertyChangedSignal("Orientation"):Connect(moveWithOrientation)
frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(positionElements)
camera:GetPropertyChangedSignal("CFrame"):Connect(partToCamera)

It completely broke the compass, with no errors too.

As I said, use your original script and use a :WaitForChild() for the cameraPart. I forgot to tell you that it takes some times for parts to appear on the client so directly calling them would mostly error but using a WaitForChild() would fix it.

1 Like

Like this?

local frame = script.Parent
local n, e, s, w, ne, nw, se, sw, nw2, n2, ne2 = frame.N, frame.E, frame.S, frame.W, frame.NE, frame.NW, frame.SE, frame.SW, frame.NW2, frame.N2, frame.NE2
local directions = {nw, n, ne, e, se, s, sw, w, nw2, n2, ne2}
local camera = workspace.CurrentCamera
local cameraPart
local absoluteSize, canvasSize, Inc = 0, 0, 0

local function updateTextColor(textLabel, condition)
    if condition then
        textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
    else
        textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
    end
end

local function partToCamera()
    if cameraPart then
        cameraPart.CFrame = camera.CFrame
    end
end

local function tickMarks(position, thickness)
    local mark = Instance.new("Frame")
    mark.AnchorPoint = Vector2.new(1, 0)
    mark.Position = UDim2.new(0, position, 0, 0)
    mark.BorderSizePixel = 0
    mark.BackgroundColor3 = Color3.fromRGB(171, 142, 98)
    mark.Name = "TickMark"
    mark.Parent = frame

    if thickness == "thicker" then mark.Size = UDim2.new(0, 3, -0.1, 1) end
    if thickness == "thick" then mark.Size = UDim2.new(0, 2, -0.1, 1) end
    if thickness == "thin" then mark.Size = UDim2.new(0, 1, 0.5, 1) end

    return mark
end

local function removeTickMarks()
    for _, v in pairs(frame:GetChildren()) do
        if v.Name == "TickMark" then v:Destroy() end
    end
end

local function updateTickMarks()
    for _, v in pairs(frame:GetChildren()) do
        if v:IsA("TextLabel") then
            local pxPos = v.Position.X.Offset
            if #v.Text == 1 then tickMarks(pxPos, "thicker") end -- N, W, S, E
            if #v.Text == 2 then tickMarks(pxPos, "thick") end -- Others
        end
    end

    for j = 22.5, 427.5, 45 do tickMarks(j * Inc, "thin") end
end

local function positionElements()
    absoluteSize = frame.AbsoluteSize.X
    canvasSize = absoluteSize * 5
    Inc = (absoluteSize * 4) / 360

    for i, dir in ipairs(directions) do
        dir.Position = UDim2.new(0, 45 * (i - 1) * Inc, 0.5, 0)
    end

    removeTickMarks()
    updateTickMarks()
    frame.CanvasSize = UDim2.new(0, canvasSize, 0, 0)
end

local function moveWithOrientation()
    if cameraPart then
        local orientationY = cameraPart.Orientation.Y % 360
        local deg = (360 - orientationY) % 360
        local inc = (absoluteSize * 4) / 360
        frame.CanvasPosition = Vector2.new(deg * inc, 0)
        positionElements()

        local centerPos = frame.AbsoluteSize.X / 2

        for i, dir in ipairs(directions) do
            local labelPos = (45 * (i - 1) * Inc) - frame.CanvasPosition.X % canvasSize
            local distanceToCenter = math.abs(centerPos - labelPos)
            if distanceToCenter < 10 or distanceToCenter > canvasSize - 10 then
                dir.TextColor3 = Color3.fromRGB(255, 255, 255)
            else
                dir.TextColor3 = Color3.fromRGB(171, 142, 98)
            end
        end
    end
end

local Players = game:GetService("Players")

local function onCharacterAdded(character)
    cameraPart = character:WaitForChild("CameraPart", 10) -- Increase wait time if needed
    if not cameraPart then
        warn("CameraPart not found in the character!")
        return
    end
    cameraPart:GetPropertyChangedSignal("Orientation"):Connect(moveWithOrientation)
    partToCamera()
    moveWithOrientation()
end

local function onPlayerAdded(player)
    player.CharacterAdded:Connect(onCharacterAdded)
end

Players.PlayerAdded:Connect(onPlayerAdded)

frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(positionElements)
camera:GetPropertyChangedSignal("CFrame"):Connect(partToCamera)```

Uhm… no not quite. You need to add a :WaitForChild() to the camera part and you aren’t assigning it here.

local frame = script.Parent
local n, e, s, w, ne, nw, se, sw, nw2, n2, ne2 = frame.N, frame.E, frame.S, frame.W, frame.NE, frame.NW, frame.SE, frame.SW, frame.NW2, frame.N2, frame.NE2
local directions = {nw, n, ne, e, se, s, sw, w, nw2, n2, ne2}
local camera = workspace.CurrentCamera
local cameraPart
local absoluteSize, canvasSize, Inc = 0, 0, 0

local function updateTextColor(textLabel, condition)
	if condition then
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
	else
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
	end
end

local function partToCamera()
	cameraPart = script.Parent:WaitForChild("CameraPart")
	if cameraPart then
		cameraPart.CFrame = camera.CFrame
	end
end

???

Put the local script parented to startercharacterscripts and access the frame, camera and what not from there. Also get rid of the events because you won’t need them if your local script is in startercharacterscripts and they won’t work.

local frame = script.Parent
local n, e, s, w, ne, nw, se, sw, nw2, n2, ne2 = frame.N, frame.E, frame.S, frame.W, frame.NE, frame.NW, frame.SE, frame.SW, frame.NW2, frame.N2, frame.NE2
local directions = {nw, n, ne, e, se, s, sw, w, nw2, n2, ne2}
local camera = workspace.CurrentCamera
local cameraPart = workspace:WaitForChild("CameraPart") -- *sigh*
local absoluteSize, canvasSize, Inc = 0, 0, 0

local function updateTextColor(textLabel, condition)
	if condition then
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
	else
		textLabel.TextColor3 = Color3.fromRGB(171, 142, 98)
	end
end

local function partToCamera()
	--cameraPart = script.Parent:WaitForChild("CameraPart") not here make sure the script is in the screen gui and not somewhere else.
	if cameraPart then
		cameraPart.CFrame = camera.CFrame
	end
end

Wait a minute neither will any of your playeradded events because the script would only run after the player has been added. Unless it’s somehow working to which I say you’re a demon.