Making an effective Jumpscare

Hello Developers,
Im currently making a horror game (no name for it yet), sorry if i cant send any screenshots, this game is still in beta. I was wondering, if there is a method, making an effective jumpscare (not jumpscares like the mimic). These kind of jumpscares are effective too but they only appear if you touched a part (of a monster for example).

The type of jumpscare i mean is:

  • the script checks if a located part in workspace is visible to the players screen. The script makes sure that the players screen really sees the part (also not trough walls, and only from a limited distance). As a function i would make the part disappear after 2 seconds the player saw the part (monster).

I tried making a script with some help from a good scripter (called BeatVien), but every method we tried didnt work… i also informed myself on social media. The only thing ive noticed is that there is a function called raycasting, but i dont know how to use it.

Maybe as a tip: the game is in first person…

Heres the script:

local MainPart = game.Workspace.Basement.Jumpscare
local JumpscareSound = game.Workspace.LightBreak2
local CurrentCam = game.Workspace.CurrentCamera
local Vector, Noticable = CurrentCam:WorldToViewportPoint(MainPart.Position)
local OnScreen = Noticable and Vector.Z > 0
local ViewportRay = CurrentCam:ViewportPointToRay(Vector.X, Vector.Y, 0)

local function Visibilty()
    local RaycastParams = RaycastParams.new()
    RaycastParams.FilterType = Enum.RaycastFilterType.Blacklist
    RaycastParams.FilterDescendantsInstances = {
    MainPart,
    game:GetService("Players").LocalPlayer.Character
    }
    local Outcome = game.Workspace:Raycast(ViewportRay.Origin, ViewportRay.Direction * 1000, RaycastParams)
    local Visible = OnScreen and not Outcome
    return
         Visible
end

while true do
     task.wait()
    local Visible = Visibilty()
    if Visible then
        wait(1)
         MainPart:Destroy()
         JumpscareSound:Play()
     end
end
1 Like

Should work, if there’s any problems its probably because you need to edit your code. Goodluck.

function onTouched(hit)

--jumpscare script here


script.Parent.Touched:connect(onTouched) --place at end of code, add 1 line between the two.

Thank you for your fast Reply!
The script you made just makes a function when you touched a part. It would work fine tho, but you cant make sure that the players screen is really looking at the happening jumpscare… thats my problem. The script i made checks if the players camera sees the part in front of the players screen. Sadly it doesnt works…
Anyways thanks for your help!

Check if player’s orientation is … (not sure negative is the right word) of the jumpscare. Should work.

You mean the players humrootpart orientation between 2 vectors? Thats actually a great idea, since the game is in 1st person. I will try to make a script for this :smile:

Yep! Thanks for considering my idea, I am not the best scripter but I still try. I hope your game can gain a ton of players! :grin:

1 Like

This should work for your intended purpose.

local MainPart = workspace.MainPart
local Camera = game.Workspace.CurrentCamera
local Player = game:GetService("Players").LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()

local Params = RaycastParams.new()
Params.FilterType = Enum.RaycastFilterType.Blacklist
Params.FilterDescendantsInstances = { Character }

local function Visibilty()
	-- Check if the jumpscare object is on the player screen
	local Vector, OnScreen = Camera:WorldToScreenPoint(MainPart.Position)
	
	if not OnScreen then
		return false
	end
	
	-- Cast a ray to the jumpscare object
	local Result = workspace:Raycast(Camera.CFrame.Position, Camera.CFrame.LookVector * 500, Params)
	
	-- Check if the raycast hit anything and if what was hit is the jumpscare object
	if Result and Result.Instance == MainPart then
		return true
	end
end


while true do
	local Visible = Visibilty()
	
	if Visible then
		task.wait(1)
		MainPart:Destroy()
	end
	
	task.wait(1)
end
2 Likes

Thank you for your reply!!! I will try out if the script works later. Does the Raycast function also happens when you look trough walls? Because this should not happen. I also tried this method but the part disappeared even when i saw the part trough a wall (so i didnt really saw it). I will try if the script works and will inform you as soon as I can! :smile:

1 Like

I tried it and it works! Thank you so much. The only strange thing is, that it only disappears when I walked to a direction ( I can’t really explain ). The part only disappeared when I go in first person and stand directly infront of the part. Is there a way to make the part disappear when you just see it on your screen no matter how far away (but still not trough walls)?

Heres a video: (the grey part is the destroy part), so the part only destroys when the cframe is in the middle of the camera I tink

I see what you mean. You can try replacing

local Result = workspace:Raycast(Camera.CFrame.Position, Camera.CFrame.LookVector * 500, Params)

with

local Result = workspace:Raycast(Camera.CFrame.Position, (MainPart.Position - Camera.CFrame.Position).Unit * 500, Params)

and see if that suits your needs better.

Raycasting fires a ray from a given position to another position and returns the first part hit, so the jumpscare cannot trigger if the trigger part is obstructed. However, this would mean that the trigger part is mostly visible, but the center point of it is obstructed - meaning it won’t actually trigger the jump scare.

One solution for this might be to take multiple points from the part and use Raycasting on all those points and see if one. or multiple, are visible to the player.

3 Likes

Ok i will try that out! Is there another good way how to fix this? Someone else suggested me the idea (because the game is in first person), that you can locate the humanoid root part, so the game checks if the humrootpart is looking at the mainpart. I will try out your new method and see if it works!

Classic image-on-screen jumpscares?

Misread the question, sorry.

Checking the orientation of the HumanoidRootPart might be a potential solution for this problem. However, I don’t really know the math behind that off the top of my head, so I couldn’t advise you any further on this idea.

Ok so I tried this out. It works better now but its still visible when you look from different positions… Is there a way too locate the whole players camera?
EDIT: somehow it perfectly worked the 2nd try and all the test after this. Ill mark this as a solution!

1 Like

Heres the finished result :grin:

1 Like