Raycast detect wall

so recently I posted a topic similar to this one except this time I’ve found a script that makes a part where the raycast is
please note that I have no idea what I’m doing I found this script from a tutorial on youtube:

local radius = 1
local function MakeRayVisible(ray)

local midpoint = ray.Origin + ray.Direction/2

local part = Instance.new("Part")
part.Parent = workspace

part.Anchored = true
part.CFrame = CFrame.new(midpoint, ray.Origin)
part.Size = Vector3.new(radius, radius, ray.Direction.Magnitude)

return part
end

local part = script.Parent

local Origin = part.Position
local direction = part.CFrame.LookVector*1000

local ray = Ray.new(Origin, direction)

MakeRayVisible(ray)

the issue is the part goes through the wall which is bad. Is there a way so the raycast doen’t go through the wall?
thanks

1 Like

show me the video if you can i need more information
@42Spider_man42

3 Likes

Just perform the raycast and take the length of the hit.Position - part.Position updated code:

local radius = 1
local function MakeRayVisible(ray)

    local part = Instance.new("Part")

    part.Anchored = true
    
    local result = workspace:Raycast(ray.Origin, ray.Direction)
    
    local len = ray.Direction.Magnitude
    if result then
        len = (ray.Origin - result.Position).Magnitude
    end
    
    part.Size = Vector3.new(radius, radius, len)
    part.CFrame = CFrame.new(ray.Origin, ray.Direction) * CFrame.new(0, 0, -len*0.5)
    
    part.Parent = workspace

    return part
end

local part = script.Parent

local Origin = part.Position
local direction = part.CFrame.LookVector*1000

local ray = Ray.new(Origin, direction)

MakeRayVisible(ray)
1 Like

is there a way for it to re-adjust when stuff moves?

video (I don’t know why the link thing looks weird):
robloxapp-20220819-1306130.wmv (403.9 KB)

1 Like

ofcourse just check the ray each frame and destroy the previous one:

local RunService = game:GetService("RunService")


local radius = 1
local function MakeRayVisible(ray)

	local part = Instance.new("Part")

	part.Anchored = true

	local result = workspace:Raycast(ray.Origin, ray.Direction)

	local len = ray.Direction.Magnitude
	if result then
		len = (ray.Origin - result.Position).Magnitude
	end

	part.Size = Vector3.new(radius, radius, len)
	part.CFrame = CFrame.new(ray.Origin, ray.Direction) * CFrame.new(0, 0, -len*0.5)

	part.Parent = workspace

	return part
end


do
	
	local part = script.Parent
	local lastRayPart = nil

	RunService.Heartbeat:Connect(function()
		
		if lastRayPart then
			lastRayPart:Destroy()
		end
		
		local Origin = part.Position
		local direction = part.CFrame.LookVector*1000

		local ray = Ray.new(Origin, direction)

		lastRayPart = MakeRayVisible(ray)
		
	end)
end
2 Likes

sorry to ask but, is there a way the ray can kill a player that moves in front of it?

maybe:

part.Touched:Connect(function(hit)
 hit.Parent.Humanoid.Health = 0
end)
1 Like

Thats one way of doing it:

You can also cast the ray and check if the hit is and Humanoid BodyPart

local function getPlayerHit(origin: Vector3, direction: Vector3): (Player, Humanoid)?

	-- Create a whitelist with all players
	local playerCharacters = {}

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(playerCharacters, player.Character)
		end
	end
	
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Whitelist
	params.FilterDescendantsInstances = playerCharacters
	
	local result = workspace:Raycast(origin, direction, params)
	
	if result then
		
		local character, humanoid =  result.Instance
		
		--- Idk if this is necesery but just repeat get parent until we have the character
		repeat
			character = character.Parent
            humanoid = character  and character:FindFirstChild("Humanoid")
		until character == nil or humanoid
		
		if not character then
			warn("Something went wrong did not find the player's character")
		end
		
		return Players:GetPlayerFromCharacter(character), humanoid
	end
end

local origin = part.Position
local direction = part.CFrame.LookVector*1000

local player, humanoid = getPlayerHit(origin, direction)

if player then  -- do something example
     humanoid:TakeDamage(50)
end
1 Like

do I replace the previous script with this one?

append the function to it.

edit: Don’t forget to put this on top of your script

local Players = game:GetService("Players")
1 Like
local RunService = game:GetService("RunService")

  ---------- spot 1

local radius = 1
local function MakeRayVisible(ray)

	local part = Instance.new("Part")

	part.Anchored = true
	part.BrickColor = BrickColor.new("Really red")
	part.Material = "Neon"
	part.CanCollide = false
         --- spot 2
	local result = workspace:Raycast(ray.Origin, ray.Direction)

	local len = ray.Direction.Magnitude
	if result then
		len = (ray.Origin - result.Position).Magnitude
	end

	part.Size = Vector3.new(radius, radius, len)
	part.CFrame = CFrame.new(ray.Origin, ray.Direction) * CFrame.new(0, 0, -len*0.5)
	part.Parent = workspace
	

	return part
end

 ------ spot 3

do

	local Part = script.Parent
	local lastRayPart = nil

RunService.Heartbeat:Connect(function()
		

		if lastRayPart then
			lastRayPart:Destroy()
		end

		local Origin = Part.Position
		local direction = Part.CFrame.LookVector*1000
		
             -----spot 4
		local ray = Ray.new(Origin, direction)
		
		
		lastRayPart = MakeRayVisible(ray)

	end)
end
 ----------- spot 5

which spot do I put it in?

place this on spot 3:

local function getPlayerHit(origin: Vector3, direction: Vector3): (Player, Humanoid)?

	-- Create a whitelist with all players
	local playerCharacters = {}

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(playerCharacters, player.Character)
		end
	end
	
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Whitelist
	params.FilterDescendantsInstances = playerCharacters
	
	local result = workspace:Raycast(origin, direction, params)
	
	if result then
		
		local character, humanoid =  result.Instance
		
		--- Idk if this is necesery but just repeat get parent until we have the character
		repeat
			character = character.Parent
            humanoid = character  and character:FindFirstChild("Humanoid")
		until character == nil or humanoid
		
		if not character then
			warn("Something went wrong did not find the player's character")
		end
		
		return Players:GetPlayerFromCharacter(character), humanoid
	end
end

Do you want to check hits when the player pressed a button or just all the time?

1 Like

all the time please

(don’t mind this)

The script is a ServerScript right otherwise you need some RemoteEvent instead.

local Debris = game:GetService("Debris")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local RAY_LIFETIME = 0.1
local RAY_RADIUS = 1
local RAY_COLOR = BrickColor.Red()
local RAY_TRANSPARENCY = 0.5


--- function to get player hit returns a player and humanoid
local function GetPlayerHit(origin: Vector3, direction: Vector3): (Player?, Humanoid?)

	-- Create a whitelist with all players
	local playerCharacters = {}

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(playerCharacters, player.Character)
		end
	end

	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Whitelist
	params.FilterDescendantsInstances = playerCharacters

	local result = workspace:Raycast(origin, direction, params)

	if result then

		local character, humanoid =  result.Instance

		--- idk if this is necesery but just repeat get parent until we have the character
		repeat
			character = character.Parent
            humanoid = character  and character:FindFirstChild("Humanoid")
		until character == nil or humanoid

		if not character then
			warn("Something went wrong did not find the player's character")
		end

		return Players:GetPlayerFromCharacter(character), humanoid
	end
end

local function DrawRay(origin: Vector3, direction: Vector3)

	local part = Instance.new("Part")
    part.Name = "Ray"
	part.Anchored = true

	local result = workspace:Raycast(origin, direction)

	local len = (origin + direction).Magnitude
	if result then
		len = (origin - direction).Magnitude
	end

	part.Size = Vector3.new(RAY_RADIUS , RAY_RADIUS , len)
    part.Material = Enum.Material.SmoothPlastic
    part.BrickColor = RAY_COLOR
    part.Transparency = RAY_TRANSPARENCY
	part.CFrame = CFrame.new(ray.Origin, ray.Direction) * CFrame.new(0, 0, -len*0.5)

	part.Parent = workspace

	return part
end


--- Ray loop
do
	local part = script.Parent
	local lastRayPart

	RunService.Heartbeat:Connect(function()

		if lastRayPart then
			lastRayPart:Destroy()
		end

		local origin = part.Position
		local direction = part.CFrame.LookVector*1000

		local rayPart = DrawRay(origin, direction)

		--- Add the ray to debris to remove after a sertain amount of time
		Debris:AddItem(rayPart, RAY_LIFETIME)

		local player, humanoid = GetPlayerHit(origin, direction)

		if player then  -- do something example
			humanoid:TakeDamage(50)
		end
	end)
end

Didn’t test the code so there may be an error.

1 Like

there are three errors:

 local character, humanoid =  result.Instance has the error UnbalancedAssignment: (31,3) Assigning 1 values to 2 variables initializes extra variables with nil; add 'nil' to value list to silence                                 	

part.CFrame = CFrame.new(ray.Origin, ray.Direction) * CFrame.new(0, 0, -len*0.5) has the error UnknownGlobal: (64,27) Unknown global 'ray'	

if lastRayPart then has the error UninitializedLocal: (79,6) Variable 'lastRayPart' defined at line 75 is never initialized or assigned; initialize with 'nil' to silence

assuming that the script goes into ServerScriptService

ServerScripts can also be inserted under any descendant of the workspace and the workspace itself So you can put it under your part.

local Debris = game:GetService("Debris")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local RAY_LIFETIME = 0.1
local RAY_RADIUS = 1
local RAY_COLOR = BrickColor.Red()
local RAY_TRANSPARENCY = 0.5


--- function to get player hit returns a player and humanoid
local function GetPlayerHit(origin: Vector3, direction: Vector3): (Player?, Humanoid?)

	-- Create a whitelist with all players
	local playerCharacters = {}

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(playerCharacters, player.Character)
		end
	end

	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Whitelist
	params.FilterDescendantsInstances = playerCharacters

	local result = workspace:Raycast(origin, direction, params)

	if result then

		local character, humanoid =  result.Instance, nil

		--- idk if this is necesery but just repeat get parent until we have the character
		repeat
			character = character.Parent
            humanoid = character  and character:FindFirstChild("Humanoid")
		until character == nil or humanoid

		if not character then
			warn("Something went wrong did not find the player's character")
		end

		return Players:GetPlayerFromCharacter(character), humanoid
	end
end

local function DrawRay(origin: Vector3, direction: Vector3)

	local part = Instance.new("Part")
    part.Name = "Ray"
	part.Anchored = true

	local result = workspace:Raycast(origin, direction)

	local len = (origin + direction).Magnitude
	if result then
		len = (origin - direction).Magnitude
	end

	part.Size = Vector3.new(RAY_RADIUS , RAY_RADIUS , len)
    part.Material = Enum.Material.SmoothPlastic
    part.BrickColor = RAY_COLOR
    part.Transparency = RAY_TRANSPARENCY
	part.CFrame = CFrame.new(origin, direction) * CFrame.new(0, 0, -len*0.5)

	part.Parent = workspace

	return part
end


--- Ray loop
do
	local part = script.Parent
	local lastRayPart = nil

	RunService.Heartbeat:Connect(function()

		if lastRayPart then
			lastRayPart:Destroy()
		end

		local origin = part.Position
		local direction = part.CFrame.LookVector*1000

		local rayPart = DrawRay(origin, direction)

		--- Add the ray to debris to remove after a sertain amount of time
		Debris:AddItem(rayPart, RAY_LIFETIME)

		local player, humanoid = GetPlayerHit(origin, direction)

		if player then  -- do something example
			humanoid:TakeDamage(50)
		end
	end)
end
1 Like

thanks for all of your help and I’m sorry I’m an idiot but, it’s going through walls for some reason
sorry about all of the issues but I’m pretty sure that this will be the last one

Don’t worry happy to help here you go.
Added config vars at the top.

  • RAY_RADIUS → number | Ray thickness
  • RAY_COLOR → BrickColor. | color of part
  • RAY_TRANSPARENCY → number | Transparency [0 - 1].
  • RAY_INTERVAL → number | how many seconds to wait to shoot a ray set it 0 if you want all the time.
  • RAY_DURATION → number | how long the beam should shoot.

for a little test set both RAY_INTERVAL and RAY_DURATION to 1

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local RAY_RADIUS = 1
local RAY_COLOR = BrickColor.Red()
local RAY_TRANSPARENCY = 0.5
local RAY_INTERVAL = 0 -- Ray shoot interval in seconds set it to zero for no interval
local RAY_DURATION = 0 -- How long until we stop shooting


--- function to get player hit returns a player and humanoid
local function GetPlayerHit(origin: Vector3, direction: Vector3): (Player?, Humanoid?)

	-- Create a whitelist with all players
	local playerCharacters = {}

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(playerCharacters, player.Character)
		end
	end

	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Whitelist
	params.FilterDescendantsInstances = playerCharacters

	local result = workspace:Raycast(origin, direction, params)

	if result then

		local character, humanoid =  result.Instance, nil

		--- idk if this is necesery but just repeat get parent until we have the character
		repeat
			character = character.Parent
			humanoid = character  and character:FindFirstChild("Humanoid")
		until character == nil or humanoid

		if not character then
			warn("Something went wrong did not find the player's character")
		end

		return Players:GetPlayerFromCharacter(character), humanoid
	end
	
	return nil, nil -- to silent the warning
end

local function DrawRay(origin: Vector3, direction: Vector3)

	local part = Instance.new("Part")
	part.Name = "Ray"
	part.Anchored = true

	local result = workspace:Raycast(origin, direction)

	local len = (origin - (origin + direction)).Magnitude
	if result then
		len = (origin - result.Position).Magnitude
	end

	part.Size = Vector3.new(RAY_RADIUS, RAY_RADIUS , len)
	part.Material = Enum.Material.SmoothPlastic
	part.BrickColor = RAY_COLOR
	part.Transparency = RAY_TRANSPARENCY
	part.CFrame = CFrame.new(origin, direction) * CFrame.new(0, 0, -len*0.5)

	part.Parent = workspace

	return part
end


--- Ray loop
do
	local part = script.Parent
	local lastRayPart = nil
	local timePassed = RAY_INTERVAL

	RunService.Heartbeat:Connect(function(dt: number)
		
		if lastRayPart and lastRayPart.Parent then -- if debris is to slow
			lastRayPart:Destroy()
		end
		
		timePassed += dt
		
		if timePassed < RAY_INTERVAL then -- Return if its not time yet
			return
		end
		
		if timePassed > RAY_INTERVAL + RAY_DURATION then -- Reset the time passed after the duration has been reached
			timePassed = 0
		end

		local origin = part.Position
		local direction = part.CFrame.LookVector*1000

		lastRayPart = DrawRay(origin, direction)

		local player, humanoid = GetPlayerHit(origin, direction)

		if player then  -- do something example
			humanoid:TakeDamage(50)
		end
	end)
end
1 Like

well, the part that it is creating doesn’t go through walls anymore, but the ray does for some reason

Yeah my bad we have to remove the whitelist.

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local RAY_RADIUS = 1
local RAY_COLOR = BrickColor.Red()
local RAY_TRANSPARENCY = 0.5
local RAY_INTERVAL = 0 -- Ray shoot interval in seconds set it to zero for no interval
local RAY_DURATION = 0 -- How long until we stop shooting


--- function to get player hit returns a player and humanoid
local function GetPlayerHit(origin: Vector3, direction: Vector3): (Player?, Humanoid?)

	local result = workspace:Raycast(origin, direction)

	if result  then

		local character, humanoid =  result.Instance, nil

		--- idk if this is necesery but just repeat get parent until we have the character
		repeat
			character = character.Parent
			humanoid = character  and character:FindFirstChild("Humanoid")
		until character == nil or humanoid

		if not character or not humanoid then
			return
		end

		return Players:GetPlayerFromCharacter(character), humanoid
	end
	
	return nil, nil -- to silent the warning
end

local function DrawRay(origin: Vector3, direction: Vector3)

	local part = Instance.new("Part")
	part.Name = "Ray"
	part.Anchored = true

	local result = workspace:Raycast(origin, direction)

	local len = (origin - (origin + direction)).Magnitude
	if result then
		len = (origin - result.Position).Magnitude
	end

	part.Size = Vector3.new(RAY_RADIUS, RAY_RADIUS , len)
	part.Material = Enum.Material.SmoothPlastic
	part.BrickColor = RAY_COLOR
	part.Transparency = RAY_TRANSPARENCY
	part.CFrame = CFrame.new(origin, direction) * CFrame.new(0, 0, -len*0.5)

	part.Parent = workspace

	return part
end


--- Ray loop
do
	local part = script.Parent
	local lastRayPart = nil
	local timePassed = RAY_INTERVAL

	RunService.Heartbeat:Connect(function(dt: number)
		
		if lastRayPart and lastRayPart.Parent then -- if debris is to slow
			lastRayPart:Destroy()
		end
		
		timePassed += dt
		
		if timePassed < RAY_INTERVAL then -- Return if its not time yet
			return
		end
		
		if timePassed > RAY_INTERVAL + RAY_DURATION then -- Reset the time passed after the duration has been reached
			timePassed = 0
		end

		local origin = part.Position
		local direction = part.CFrame.LookVector*1000

		lastRayPart = DrawRay(origin, direction)

		local player, humanoid = GetPlayerHit(origin, direction)

		if player then  -- do something example
			humanoid:TakeDamage(50)
		end
	end)
end
4 Likes