Radiation System with Raycasting?

Alright so, I wish to make a system that checks if there is a part blocking the way between the player and the radiation source part regardless of the orientation of the player relative to the radiation source.

I’ve tried using raycasts but I have failed miserably as it says that it’s hitting stuff behind the player? Help would be much appreciated.

A nice bonus would be to check all of the parts that block between the player and the radiation source, eg; Part1 and Part2 block the way, however if that isn’t possible then that’s alright.

Thank you!

2 Likes

Something similar that I did was create a line between the source of the radiation and the HumanoidRootPart of a character using the Raycast Hitbox

If you search a bit you will find a github with the documentation you need, it’s in the “HowToUse” session. You basically need to:

  1. Make a raycast line between the target and the source
  2. Enable part mode in the script, you can customize it at your will.
  3. Put a filter so that the raycast doesn’t detect humanoid parts, because if other players were in front of you, you wouldn’t take any damage

So the code would be smh like:

"Put part mode here"
"Put filter here"

while PlayerMagnitudeFromSource < AreaOfRadiation do
NothingBetweenThePlayerAndTheSource = true

"Start raycast"

OnHitDo{
NothingBetweenPlayerAndSource = false
}
"Stop Raycast"

If NothingBetweenPlayerAndSource == true then
"Do anything you want to the player here
end

wait(Time delay between each check)
end

With this, you can detect every part that the raycast hit and do anything you want to the player, I don’t think it’s the best way, but it worked well enough for me, only thing to keep in mind is that the raycast only hit

To get the direction between the player and the radiated part, you just have to subtract the radiatedPart.Position from the player character’s HumanoidRootPart.Position.

local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = {char}

local rayOrigin = HRP.Position
local rayDirection = radiatedPart.Position-rayOrigin

local raycastResults = game.Workspace:Raycast(rayOrigin,rayDirection,raycastParams)

if raycastResults then
	if raycastResults.Instance == radiatedPart then
		playerInRadiation = true
	end
end

You can think about this in 2 dimensions, if the player is at point (1, 1) and the radiated part is at (0, 0), then to go from the player to the part you’d want to go in the direction (-1, -1). To put that thinking into scripting terms, just do the radiated part’s position of (0, 0) minus the player’s position of (1, 1)

(0, 0) - (1, 1) = (-1, -1), so (-1, -1) would be our raycast direction in our hypothetical 2D world.

This carries over to 3 dimensions. (1, 1, 1) - (0, 0, 0) still gives us our direction for going from (1, 1, 1) to (0, 0, 0), which is obviously (-1, -1, -1)

1 Like

Thank you, but would it be possible to calculate the amount of studs that block the way between the radiation source and the player?

Yes, sorry for the late response.
For the difference in distance you can just subtract either one from the other in whatever order you want, then use .Magnitude on the difference:

(radiatedPart.Position-HRP.Position).Magnitude
OR
(HRP.Position-radiatedPart.Position).Magnitude

These both return an always positive number equal to their distance apart.

For more on how this actually does that, it's just basic geometry but in 3 dimensions.

We know from the Pythagorean theorem that we can get the length of the hypotenuse on a right triangle by using the square root of c^2 in the equation a^2 + b^2 = c^2, so if we wanted to get the distance between two points, we just need to get the difference in the X values between the points to use as our a value, then get the different in the Y values between the points to use as our b value.

So the distance between two points in 2 dimensions can be calculated with this line:
Distance = SquareRoot((X2-X1)^2 + (Y2-Y1)^2)

Now thankfully for us, the Pythagorean theorem is scalable to 3 dimensions very easily.
All you need to add to do to find the distance between 2 points in 3d is just add the new dimension to the left side of the equation.
a^2 + b^2 + c^2 = d^2

This means that the equation for the distance between two 2D points can ALSO be scaled easily to 3 dimensions.
Distance = SquareRoot((X2-X1)^2 + (Y2-Y1)^2 + (Z2-Z1)^2)

Also it does math.abs() on the result BEFORE getting the square root, since the result isn’t always positive and the SquareRoot of a negative is undefined.

Sorry if I explained that horribly, it makes sense in my brain but I have trouble transferring that to text.

Yeah I figured that out, what I meant was the parts that block the way between the player and the radiatedPart. Like, if there’s a part in the way then I wish to figure out how thick that part is and it has to be done for all parts that are in the way. Is that possible?

I don’t have that knowledge, but I thought of 2 things that might work:

  1. Do a for loop in every part that the raycast hit and get their length (most sluggish way and will cause problems, like, if there’s a really big wall but it’s width is just 1m, the game will detect like "dam he has 100m protecting him, he’s safe)
  2. Get point A (where the raycast first hit the part) and point B (where the raycast last hit the part), then do (part A - part B).Magnitude, and you got it.

Getting both ends would be way more accurate, since the third way that I thought, which was checking the angle between both points and using a 3d formula to basically get the hipotenuse would be boring and hard to do, and a bit less accurate too, since it would not check if you were in the edge of the wall for example.
So I think the second option is by far the best one.

If the ray is hitting objects the player is not blocked by, try checking how you’re raycasting it.

You could make some kind of repeat until loop for this.

Oh sorry yea that’s possible.

To check all parts between the player and the radiated part you could just do a loop where you raycast towards it and if the raycast hits something that isn’t the radiated part, then you add that to a list of parts you’ve hit, and then use that same list in the raycastParams blacklist.

If you wanted the width of the part then you could do a couple of things, but what I’d do in order to measure how much of each part is actually in between the player and radiated part is basically raycast once towards the radiated part, then if you hit something, do a backwards raycast going from the radiatedPart to the character, and for the backwards raycast you should set the raycastParams to whitelist, and only whitelist the part that you hit in the original raycast.
From there you can take the hit positions of the forward and backwards raycast and measure the distance between them, that should calculate how much wall is between you and the radiated part for one of the walls.

Combining the raycast looping with this would look something like this:

function raycastAwayFromRadiatedPart(raycastFilterType,raycastFilterList)
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = raycastFilterType
	raycastParams.FilterDescendantsInstances = {raycastFilterList}

	local rayOrigin = radiatedPart.Position
	local rayDirection = HRP.Position-rayOrigin

	local raycastResults = game.Workspace:Raycast(rayOrigin,rayDirection,raycastParams)

	if raycastResults then
		return raycastResults
	end
end


function raycastTowardsRadiatedPart(raycastFilterList)
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = {char,raycastFilterList}

	local rayOrigin = HRP.Position
	local rayDirection = (radiatedPart.Position-rayOrigin).Unit*maxDistance

	local raycastResults = game.Workspace:Raycast(rayOrigin,rayDirection,raycastParams)

	if raycastResults then
		return raycastResults
	end
end

function tryRaycastTowardsRadiatedPart()
	local totalWallThicknessBetweenRadiatedPart = 0
	local partsBetweenRadiatedPart = {}

	local hitRadiatedPart = false
	local hitNothing = false
	while not hitRadiatedPart and not hitNothing do
		
		local forwardRaycastResults = raycastTowardsRadiatedPart(partsBetweenRadiatedPart)
		if forwardRaycastResults then
			if forwardRaycastResults.Instance == radiatedPart then
				hitRadiatedPart = true
			else
				table.insert(partsBetweenRadiatedPart,forwardRaycastResults.Instance)
				local backwardsRaycastResult = raycastAwayFromRadiatedPart(Enum.RaycastFilterType.Whitelist,forwardRaycastResults.Instance)
				if backwardsRaycastResult then
					local dist = (backwardsRaycastResult.Position-forwardRaycastResults.Position).Magnitude
					totalWallThicknessBetweenRadiatedPart += dist
				end
			end
		else
			hitNothing = true
		end
		
	end
	
	if hitRadiatedPart then
		print(totalWallThicknessBetweenRadiatedPart)
		local wallCount = #partsBetweenRadiatedPart
		print("hit "..tostring(wallCount).." parts")
		print("radiated part found")
	else
		print("radiated part not found, most likely out of range")
	end
end

Sorry for the messy code, wrote this really quick. It is tested and I’m 99.9% sure it’s completely working. Of course you should always try to pick it apart, figure out how it works, find optimizations, all that. Just remember to look through before copying and pasting basically.

Also made an optimization I wasn’t thinking about before. Instead of using an if statement to check if the player is out of range, just normalize the raycast direction with .Unit then multiply it by the max distance.

Not sure what you’re trying to accomplish with this alone, but from the looks of it, some sort of research game. If you wanted, you could also utilize the raycastResult.Material property and have a check for some of the materials like Enum.Material.Metal or Enum.Material.DiamondPlate, and have those block radiation more than other parts by counting their wall thickness as double or something like that.

Note to anyone who may want to use this solution:
There is an issue where if you parent a part to another, one of the parts will not be detected in the forward raycast, but will be detected in the backward raycast. Be aware of that. My only idea on how to fix this is to set FilterDescendantsInstances to {char}, disable the raycastParams.RespectCanCollide value, then set the .canQuery value for anything you want to blacklist to false. This isn’t the full solution, just look into it if you need to be able to parent parts to one another.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.