Basically, I’m trying to check if a part(the small cube in the image, not the spawn) is within my camera’s view and is unblocked by anything via checking every corner of the part and seeing if its on screen and then checking if its blocked or not through raycasting. It works somewhat, although, it will say its blocked even if several corners are very clearly unblocked(see picture)
My script is within the starter character scripts and is as following:
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local camera = workspace.CurrentCamera
function getCorners(part)
local cf = part.CFrame
local size = part.Size
local corners = {}
local frontFaceCenter = (cf + cf.LookVector * size.Z/2)
local backFaceCenter = (cf - cf.LookVector * size.Z/2)
-- edge centers - 4 of 12 edges referenced
local topFrontEdgeCenter = frontFaceCenter + frontFaceCenter.UpVector * size.Y/2
local bottomFrontEdgeCenter = frontFaceCenter - frontFaceCenter.UpVector * size.Y/2
local topBackEdgeCenter = backFaceCenter + backFaceCenter.UpVector * size.Y/2
local bottomBackEdgeCenter = backFaceCenter - backFaceCenter.UpVector * size.Y/2
-- corners
corners.topFrontRight = (topFrontEdgeCenter + topFrontEdgeCenter.RightVector * size.X/2).Position
corners.topFrontLeft = (topFrontEdgeCenter - topFrontEdgeCenter.RightVector * size.X/2).Position
corners.bottomFrontRight = (bottomFrontEdgeCenter + bottomFrontEdgeCenter.RightVector * size.X/2).Position
corners.bottomFrontLeft = (bottomFrontEdgeCenter - bottomFrontEdgeCenter.RightVector * size.X/2).Position
corners.topBackRight = (topBackEdgeCenter + topBackEdgeCenter.RightVector * size.X/2).Position
corners.topBackLeft = (topBackEdgeCenter - topBackEdgeCenter.RightVector * size.X/2).Position
corners.bottomBackRight = (bottomBackEdgeCenter + bottomBackEdgeCenter.RightVector * size.X/2).Position
corners.bottomBackLeft = (bottomBackEdgeCenter - bottomBackEdgeCenter.RightVector * size.X/2).Position
return corners
end
function checkVisibility(target)
local corners = getCorners(target)
for corner, cornerPos in pairs(corners) do
local vector, onScreen = camera:WorldToScreenPoint(cornerPos)
if not onScreen then print("target not onscreen") return false end
local screenPoint = Vector2.new(vector.X, vector.Y)
local depth = vector.Z
local raystart = camera.CFrame.Position
local raydestination = target.Position
local raydirection = raydestination - raystart
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {camera}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local result = workspace:Raycast(raystart, raydirection, raycastParams)
---checking to see if we hit anything
if result then
local part = result.Instance
print(part.Name)
if result.Instance == target then
print("target unblocked")
return true
end
end
end
print("target blocked or not there")
return false
end
RunService.RenderStepped:Connect(function()
if checkVisibility(workspace:FindFirstChild("Part")) then
workspace:FindFirstChild("SpawnLocation").BrickColor = BrickColor.new("Lime green")
else
workspace:FindFirstChild("SpawnLocation").BrickColor = BrickColor.new("Really red")
end
end)
The corner’s script is pretty much directly taken from another post:
I’m no expert, but you seem to be returning false if any of the corners aren’t visible before you do the check.
for corner, cornerPos in pairs(corners) do
local vector, onScreen = camera:WorldToScreenPoint(cornerPos)
if not onScreen then print("target not onscreen") return false end
Shouldn’t you be going through all the corner in the pairs loop, putting their OnScreen result into a table, then checking to see if any of them are true? If even one out of the 8 corners returns true then the object is visible.
If you want to you may also be able to use WorldToScreenPoint
Then you can get the size of the players screen and check if its between the edges of the screen.
local screenSize = workspace.CurrentCamera.ViewportSize
oh yeah you seem to be right. i removed the if not onScreen then print("target not onscreen") return false end
as well as add a check if its onsceen at the final portion and combined it with smashman65’s solutions and works really well now:
local RunService = game:GetService("RunService")
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local camera = workspace.CurrentCamera
function getCorners(part)
local cf = part.CFrame
local size = part.Size
local corners = {}
local frontFaceCenter = (cf + cf.LookVector * size.Z/2)
local backFaceCenter = (cf - cf.LookVector * size.Z/2)
-- edge centers - 4 of 12 edges referenced
local topFrontEdgeCenter = frontFaceCenter + frontFaceCenter.UpVector * size.Y/2
local bottomFrontEdgeCenter = frontFaceCenter - frontFaceCenter.UpVector * size.Y/2
local topBackEdgeCenter = backFaceCenter + backFaceCenter.UpVector * size.Y/2
local bottomBackEdgeCenter = backFaceCenter - backFaceCenter.UpVector * size.Y/2
-- corners
corners.topFrontRight = (topFrontEdgeCenter + topFrontEdgeCenter.RightVector * size.X/2).Position
corners.topFrontLeft = (topFrontEdgeCenter - topFrontEdgeCenter.RightVector * size.X/2).Position
corners.bottomFrontRight = (bottomFrontEdgeCenter + bottomFrontEdgeCenter.RightVector * size.X/2).Position
corners.bottomFrontLeft = (bottomFrontEdgeCenter - bottomFrontEdgeCenter.RightVector * size.X/2).Position
corners.topBackRight = (topBackEdgeCenter + topBackEdgeCenter.RightVector * size.X/2).Position
corners.topBackLeft = (topBackEdgeCenter - topBackEdgeCenter.RightVector * size.X/2).Position
corners.bottomBackRight = (bottomBackEdgeCenter + bottomBackEdgeCenter.RightVector * size.X/2).Position
corners.bottomBackLeft = (bottomBackEdgeCenter - bottomBackEdgeCenter.RightVector * size.X/2).Position
return corners
end
function checkVisibility(target)
local corners = getCorners(target)
for corner, cornerPos in pairs(corners) do
local vector, onScreen = camera:WorldToViewportPoint(cornerPos)
if not onScreen then continue end
local blockingParts = camera:GetPartsObscuringTarget({cornerPos}, {target})
print(blockingParts)
if #blockingParts == 0 and onScreen then
print("target unblocked")
return true
end
---checking to see if we hit anything
end
print("target blocked or not there")
return false
end
RunService.RenderStepped:Connect(function()
if checkVisibility(workspace:FindFirstChild("Part")) then
workspace:FindFirstChild("SpawnLocation").BrickColor = BrickColor.new("Lime green")
else
workspace:FindFirstChild("SpawnLocation").BrickColor = BrickColor.new("Really red")
end
end)