Unusual GUI Position Behavior

So I’ve been trying to make this off-screen ship indicator which basically tells you the position of the ship, but for some reason when you turn away from the ship, the indicator shows up in front of you instead of on the sides.
https://gyazo.com/8e1832a4dbaf08dbcb27cc3eb69ba810
Script:

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

local Viewport = script.Parent:WaitForChild("ShipViewport")
local ShipViewport = Viewport:WaitForChild("ShipViewModel")

local RealShip = workspace:WaitForChild("Cutter")
local RealShipSeat = RealShip:WaitForChild("BoatSeat")

local ShipDescendants = RealShip:GetDescendants()
RealShip.DescendantAdded:Connect(function(v)
	table.insert(ShipDescendants, v)
end)
RealShip.DescendantRemoving:Connect(function(v)
	local Found = table.find(ShipDescendants, v)
	ShipDescendants[Found] = nil
end)

local Camera = workspace.CurrentCamera

local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()

local clamp = math.clamp
local rad = math.rad

RunService:BindToRenderStep("SetCirclePos", Enum.RenderPriority.Camera.Value, function(dT)
	if not ShipViewport.PrimaryPart or not Character.PrimaryPart then return end
	
	local Scale = dT * 60
	
	local ShipVectorMath = RealShipSeat.Position + (RealShipSeat.CFrame.LookVector * 35)
	
	local CFPos = CFrame.new(ShipVectorMath, Character.PrimaryPart.Position)
	local PosMath = ShipViewport.PrimaryPart.Position + CFPos.LookVector
	
	ShipViewport:SetPrimaryPartCFrame(CFrame.new(ShipViewport.PrimaryPart.Position, Vector3.new(PosMath.X, ShipViewport.PrimaryPart.Position.Y, PosMath.Z)) * CFrame.Angles(0, rad(180), 0))--CFPos.Position))
	
	local RayShoot = Ray.new(Camera.CFrame.Position, Camera.CFrame.LookVector * 2048)
	local Hit = workspace:FindPartOnRayWithWhitelist(RayShoot, RealShip:GetDescendants())
	
	local Vector, OnScreen = Camera:WorldToScreenPoint(ShipVectorMath)
	local VectorMath = Camera.ViewportSize - script.Parent.AbsoluteSize
	local Vector2Pos = Vector2.new(clamp(Vector.X, 0, VectorMath.X), clamp(Vector.Y, 0, VectorMath.Y))
	
	local LerpAbsPos = script.Parent.AbsolutePosition:Lerp(Vector2Pos, .1 * Scale)
	
	script.Parent.Position = UDim2.new(0, LerpAbsPos.X, 0, LerpAbsPos.Y)
	
	if OnScreen and Hit then
		if Hit:IsDescendantOf(RealShip) then
			script.Parent.Visible = false
			return
		end
	end
	
	script.Parent.Visible = true
end)

Any help is appreciated.

1 Like

I have a good question for you: Where do you expect the indicator to be when the ship is right behind you? Way far off to the side? But that’s where the indicator is when you’re looking perpendicular to where the ship is.

The answer is that the position should still be in the center of the screen when it’s right behind you. That’s because math wise, the camera’s resulting screen positions are symmetrical front to back (well, minus what the clipping planes are). The difference is that behind you you will get a different depth from the camera: What’s currently in Vector.Z which you never used.

When Vector.Z is positive, the ship in the direction you camera is looking, when it’s negative, the ship is behind you. You should hide the indicator entirely when that depth is negative. That or do additional math to map it to an edge of the screen when the depth is negative. That math will have to be different though than for the case where it is in front of you (You’ll have to take the position, which is within the screen bounds, but at a negative depth, and “push” it out to the nearest screen edge).

3 Likes