Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
4

How to tell if someone can see an object?

Asked by 5 years ago

I'm working on a part that does something when you look at it, I'm not exactly sure what I can do and I don't think lookVector would work, but I don't know much about it, I've been doing some research and I haven't found anything helpful, most of the things I found were too vague, or didn't seem like they would work. Any help would be nice, thanks in advance!

3 answers

Log in to vote
2
Answered by
ozzyDrive 670 Moderation Voter
5 years ago
Edited 5 years ago

You can get the screen position of a 3D point with the WorldToScreenPoint method of the camera.

local screenPoint, isVisible = camera:WorldToScreenPoint(object.Position)

This however doesn't take the size of the object into account. What you can do is take all the corners of the object and see if any of them are on the screen. Here's an example on how this can be implemented:

local localPlayer = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local part = workspace.Part

local GUI = Instance.new("ScreenGui", localPlayer.PlayerGui)
local function drawFrame(topLeft, bottomRight)
    local size = bottomRight - topLeft
    local frame = Instance.new("Frame")


    frame.Position = UDim2.new(0, topLeft.X - size.X/2, 0, topLeft.Y - size.Y/2)
    frame.Size = UDim2.new(0, size.X, 0, size.Y)    
    frame.BackgroundTransparency = 0.2
    frame.BackgroundColor3 = BrickColor.Red().Color 

    frame.Parent = GUI

    game:GetService("Debris"):AddItem(frame, 1/30)
end

local function isPartVisible(obj)   
    local center = obj.Position

--  No need to do any extra calculations if the center point is on the screen
    local centerPoint, centerVisible = camera:WorldToScreenPoint(center)
    if centerVisible then
        return true, centerPoint
    end 

    local extents = obj.Size/2  

    local extentPoints = {
        [1] = (Vector3.new(center.X + extents.X, center.Y + extents.Y, center.Z + extents.Z)),
        [2] = (Vector3.new(center.X - extents.X, center.Y - extents.Y, center.Z - extents.Z)),
        [3] = (Vector3.new(center.X - extents.X, center.Y + extents.Y, center.Z + extents.Z)),
        [4] = (Vector3.new(center.X + extents.X, center.Y - extents.Y, center.Z + extents.Z)),
        [5] = (Vector3.new(center.X + extents.X, center.Y + extents.Y, center.Z - extents.Z)),
        [6] = (Vector3.new(center.X - extents.X, center.Y - extents.Y, center.Z + extents.Z)),
        [7] = (Vector3.new(center.X + extents.X, center.Y - extents.Y, center.Z - extents.Z)),
        [8] = (Vector3.new(center.X - extents.X, center.Y + extents.Y, center.Z - extents.Z)),
    }   

    for n = 1, #extentPoints do
        local point = extentPoints[n]
        local screenPoint, isVisible = camera:WorldToScreenPoint(point)
        drawFrame(screenPoint, screenPoint + Vector3.new(10, 10))
        if isVisible then
            return true, screenPoint
        end
    end
    return false
end

game:GetService("RunService").Heartbeat:Connect(function()
    print(isPartVisible(part))
end)

edit: Of course it is possible that the object is on the screen without any of the 9 points being visible. The final method depends on what kind of requirements you have.

0
Thanks! All of the others said the same thing, but you also said how I can tell if you can see an object, but I can't see the center, I would've most likely ran into lots of problems if you didn't add that extra comment. Thanks! Inconcinnus 90 — 5y
Ad
Log in to vote
3
Answered by
fredfishy 833 Moderation Voter
5 years ago
Edited 5 years ago

The WorldToScreenPoint method returns information about where on the screen a Vector3 is, but also whether or not it's visible.

This seems to be pretty much exactly what you're looking for, with the caveat that it only returns true if the precise Vector3 is visible. If You've got a large object, you might be able to see the edge of it before its .Position is visible on screen.

If you throw a brick into the workspace called "CanYouSeeMe", then the following should, when you click and hold, take away your health whenever you can see it, and give it back to you when you can't.

script.Parent.Equipped:Connect(function(m)
    held = false

    m.Button1Down:Connect(function()
        local player = game:GetService("Players").LocalPlayer
        local cam = workspace.CurrentCamera
        local fov = math.rad(workspace.CurrentCamera.FieldOfView)
        local mouse = player:GetMouse()
        local character = player.Character
        held = true

        while held and wait() do
            local locationAndDepth, visible = cam:WorldToScreenPoint(workspace.CanYouSeeMe.Position)
            if visible then
                character.Humanoid:TakeDamage(1)
            else
                character.Humanoid.Health = character.Humanoid.Health + 1
            end
        end
    end)

    m.Button1Up:Connect(function()
        held = false
    end)

    script.Parent.Unequipped:Connect(function()
        held = false
    end)
end)
Log in to vote
2
Answered by
Avigant 2374 Moderation Voter Community Moderator
5 years ago

Use Camera:WorldToScreenPoint to accomplish this.

Answer this question