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?
Alright, let's start with this:
local offset, onScreen = Camera:WorldToScreenPoint(point)
This is a function that returns:
offset
, which is a Vector3 describing how far point
is from the camera screen, and 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:
offset
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!
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)