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

How can I check whether a player is looking at a part?

Asked by 5 years ago

I want to make a Weeping Angel-Like monster, but I do not know where to start. I've seen this post: https://scriptinghelpers.org/questions/25213/how-can-i-create-mechanics-similar-to-dont-blink which has this code:

    local camera = game.Workspace.CurrentCamera
    local worldPosition = Vector3.new()
    local screenPosition,  onScreen = camera:WorldToScreenPoint(worldPosition)

    if onScreen then
        print'Player can see the point!'
    else
        print'Player cannot see the point :('
    end

which started to work, but after I tested it, it broke completely. the part was named CurrentCamera, as it said. Anything I can do?

0
you could try raycasting for the part TheSuperEmeraldYT -2 — 5y

2 answers

Log in to vote
1
Answered by 5 years ago
Edited 5 years ago

Alright, let's start with this:

local offset, onScreen = Camera:WorldToScreenPoint(point)

This is a function that returns:

  1. offset, which is a Vector3 describing how far point is from the camera screen, and
  2. onScreen, which tells you if that point is inside the screen.

So we're going to use this to detect whether that creature is on screen, or not.

First and probably the most intuitive implementation would be to check if the monster's position(well, the position of the PrimaryPart of the monster model, or of the HumanoidRootPart) is inside the screen at every frame, like so:

RunService.Heartbeat:Connect(function() 
    local point = Monster.HumanoidRootPart.Position
    local offset, onScreen = Camera:WorldToScreenPoint(point)
    if onScreen then
        -- point is on screen
    else
        -- point is not on screen
    end
end)

Cool, but that only checks if the point is on screen. You want to know if a player is "looking at" the point, which is to say that the point has to be somewhere in the center of the screen. For this, we could use the offset property like so:

  1. Find out where the point is in the screen using offset
  2. Check how far that point is from the center of the screen
  3. If it's less than a certain radius, then you could say that the part is in the center

To implement that in code, you'd have to know how to get the distance between two points using the distance formula. Here's what that looks like: (note that this script isn't optimized at all)

RunService.Heartbeat:Connect(function() 
    local ViewportSize = Camera.ViewportSize
    local point = Monster.HumanoidRootPart.Position
    local offset, onScreen = Camera:WorldToScreenPoint(point)
    if onScreen then
        -- point is on screen

        -- get the offset, then screen size
        local offsetX, offsetY= offset.X, offset.Y
        local viewportX, viewportY = ViewportSize.X, ViewportSize.Y

        -- this is how far from the center we'd call "close enough"
        local radius = 100

        -- get the distance from the center
        local dist = math.sqrt(
            ((viewportX/2) - offsetX)^2 + ((viewportY/2) - offsetY)^2 
        )

        -- check
        if dist <= radius then -- distance formula
            -- point is at the center of the screen
        else
            -- point is not at the center
        end
    else
        -- point is not on screen
    end
end)

Cool, now we know if a part is roughly at the center of the screen, and maybe this is enough to roughly say that a player is looking at the part.

But... monsters are made up of lots of parts. So maybe we could loop through all of those parts, and see if the player is looking at any of those parts.

But... this only checks the center of each part, and not the extents of the part. So maybe we could get every corner of the boundingbox of the part, then loop through all of those points instead.

As an optimization, we could just do the centers of top/bottom/left/right faces of the part... or we could just check the extents of the model itself, instead of having to check each individual corner of each individual part in the monster model...

And I almost forgot, we forgot to check if there are any parts that are blocking the view... so you'd have to raycast from those points to the camera to ensure that it's unobstructed...

Yeah, no.

You know what, this might have been getting too complicated, yeah? A more simple system would be to just lock the player in FPS, lock the mouse at the center of the screen, listen to mouse movements, then check if mouse.Hit is a monster's body part.

Hope that helps!

1
Thank you for trying though! I think I will use your mouse.Hit idea! Makes it a lot more tense when you have to look at the monster directly then from the corner of your eyes! Noonekirby 162 — 5y
Ad
Log in to vote
-2
Answered by
Bincs58 -6
5 years ago

When answering, if your answer does not fully solve the question, it should be written as a comment to the question instead of as an answer.
local Plr = game:GetService("Players").LocalPlayer
local Mouse = Plr:GetMouse()

Mouse.Button1Down:connect(function()
if not Mouse.Target then return end
print(Mouse.Target.Name)
end)

That would print the name of the part that the localplayer is looking at (if he Button1down's, you can put this in a loop and probably achieve what you need)

1
only works in first person and also doesn't take into account the player's 70 degree FOV theking48989987 2147 — 5y

Answer this question