Any easier ways to get ray result with FastCast module? Or to return result from a function to use in the rest of your script?

FastCast is a pretty neat module and is probably heaps better than normal Raycast so I want to implement it into my future game. Basically I only need to use it for part detection and only need ray hitted part’s point normal. (Note, that i’m not an experienced scripter)

The current/normal Raycast module lets you easily do:

local Result = workspace:Raycast(Origin, Direction, raycastParams)

and you can easily access the ‘Result.Normal’ and etc. throughout the rest of your script.

BUT with FastCast you need to do all that other stuff and without a lot of coverage online I just don’t know how to work with it and the Result only stays in the ‘OnRayHit’ function.

This is where i’m currently at:

local FastCast = require(game.ServerScriptService.FastCastRedux)
local caster = FastCast.new()
local part = workspace.Part

local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Whitelist
params.FilterDescendantsInstances = {part}

local castBehavior = FastCast.newBehavior()
castBehavior.RaycastParams = params

local function OnRayHit(cast, result, velocity, bullet)
	-- as far as i know this is the only place where i can work with and check 'result.Normal' 
end

caster:Fire(SomeOrigin, SomeDirection, SomeVelocity, castBehavior)-- i input my own variables, but here i just wrote parameter names to make it understandable
caster.RayHit:Connect(OnRayHit) -- is this the only way i can find out result?

if result.Normal.Y >= 0 then -- I want to access the result and it's contents here - outside any functions
	print(result.Normal.Y) 
end

Any help is greatly appreciated, thank you! xoxo

  • Tady

What is the issue with something like this? It does seem like the only way to access the raycast result is via the RayHit event from looking at the docs.

local FastCast = require(game.ServerScriptService.FastCastRedux)
local caster = FastCast.new()
local part = workspace.Part

local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Whitelist
params.FilterDescendantsInstances = {part}

local castBehavior = FastCast.newBehavior()
castBehavior.RaycastParams = params

local function OnRayHit(cast, result, velocity, bullet)
	-- as far as i know this is the only place where i can work with and check 'result.Normal' 
	if result.Normal.Y >= 0 then -- I want to access the result and it's contents here - outside any functions
		print(result.Normal.Y) 
	end
end

caster:Fire(SomeOrigin, SomeDirection, SomeVelocity, castBehavior)-- i input my own variables, but here i just wrote parameter names to make it understandable
caster.RayHit:Connect(OnRayHit) -- is this the only way i can find out result?

2 Likes

Also what is this part detection for? Seems odd to only whitelist a single part to raycast against.

I just excerpted that example from my main script and edited that to seem more understandable. Only one part is needed because it’s the part that would need to be worked on if the ray hit it, any other hits must be ignored.

Because this whole FastCast process is gonna be happening in a loop which i want to break: if Raycast detects part’s result.Normal >= 0. So I want to have the result outside the function, so I can compare and break the loop.

I think this is where it would be useful to see the bigger picture with what you’re up to. You could have a variable in the enclosing scope to keep track of if a part was hit but I reckon there’s a cleaner way to do it - probably without a loop at all.

I feel sorry for my fingers and for you but we just have to dive into the ‘deep’ of my ‘script cave’. Here we go haha…

The idea: ‘part2’ falls on top of ‘part1’. Both of the parts have identical shape, mass and the force (I only focus on force F = mg). The Part2 applies it’s force onto the Part1. So Part1’s force = Part1’s force + Part2’s force. Part2’s force remains the same because it’s on top. Basically I’m trying to achieve force exchange due to gravity and store these values. Both parts have exact same scripts. Let’s focus on Part1’s script:

  • When Part2 comes in contact with Part1 - Touched event fires. (from now on Part2 will be called ‘OtherPart’ because it’s the one that touched Part1 and Part1 will be called ‘ParentPart’)
  • We check if OtherPart is already touching, if not we will have to add its name to ParentPart’s ‘StationaryLooseTouchers’ table and set the “true” value (because now it is touching) + add its force to ParentPart.

This is where the raycasting comes in handy. Since I want to check if the OtherPart is above ParentPart, i’m gonna cast multiple (26 to be precise) rays straight down out of OtherPart’s corners, side centers and so on AND check if it hits ParentPart. That’s the loop I was talking about - the separate 26 rays - and if during the loop even ONE ray touches ParentPart and the result.Normal.Y >= 0 ( ← with this we’re checking if the ParentPart’s face is facing upwards) then the OtherPart’s force should be added onto ParentPart’s and the loop breaks to not waste time and computing power.

The problem:
If I were to perform action (add forces with condition) IN the event function of ‘OnRayHit()’, i couldn’t break the loop and the rays would just keep on hitting and adding incredible amounts of unreal force. (I also noticed that I somehow cannot change variables inside that function)

Note that I’m storing Part’s forces and some calculation functions in ObjectDataBase module script

The Part1’s (ParentPart’s) script section when ParentPart.Touched:Connect(Mass) is activated:

local FastCast = require(game.ServerScriptService.FastCastRedux)
local ObjectDatabase = require(game.ServerStorage.Database)
local ParentPart = script.Parent.Parent
local intrudercorners2 = {}
local StationaryLooseTouchers = {}

local function Mass(OtherPart)
	if OtherPart == workspace.Baseplate or OtherPart.CanCollide == false or OtherPart.Name == "ZonePart" then return end
	local function OnRayHit(cast, result, velocity, bullet)
		if result.Instance and result.Normal.Y >= 0 then 
			----- idk how to return the result
		end
	end
	
	local params2 = RaycastParams.new()
	params2.FilterType = Enum.RaycastFilterType.Whitelist
	params2.FilterDescendantsInstances = {ParentPart}
	local castBehavior = FastCast.newBehavior()
	castBehavior.RaycastParams = params2

    --checking if otherpart is already touching
	local touch = false
	for i, key in pairs(StationaryLooseTouchers) do
		if OtherPart.Name == i and key == true then
			touch = true
			break
		end 
	end

    -- if it wasn't touching before then we'll have to perform force addition
	if touch == false then
		StationaryLooseTouchers[OtherPart.Name] = true
		for i = 1, 26 do -- 'THE loop'
			ObjectDatabase.GetSurfacePoints(ObjectDatabase.Vertices, OtherPart, OtherPart.Size, intrudercorners2) -- finding various points across OtherPart and storing them in ParentParts script's 'intrudercorners2' table
			caster:Fire(intrudercorners2[i], (Vector3.new(0, -1, 0)).Unit, 10000, castBehavior)	
			caster.RayHit:Connect(OnRayHit)
			if result.Instance and result >=0 then
				ObjectDatabase.AddForces(ParentPart, OtherPart)
				break -- stops the loop so no more unreal force gets added
			end
		end	
	end
end

Thank you for your time and help.

1 Like

Okay if you know the parts are touching can you not just use the relative positions to see if part 2 is on top of part 1 rather than raycasting?

I.e if (Part2.Position - Part1.Position).Y > 0 ?

Also I’m not sure why you don’t just use the standard workspace:Raycast method as fast cast seems to be aimed towards projectiles. If you want to see if the part is hit by a ray in a single frame I don’t think the fast cast event will trigger quick enough (you’d have to wait an arbitrary amount of time and see if the event fires).

1 Like

The (Part2.Position - Part1.Position).Y > 0 wouldn’t work, as positions are just centers of parts. It wouldn’t work with something else than cubes, I think. I’m working with these flat slabs.

RobloxDev Example1

As you can see in the picture above, part2 is lower than part1, but still, in theory, should transfer it’s force to part1.

My method:

RobloxDev Example2

With my method that is taken into account. With the normal, you can check that the Part1’s face is facing upwards, and can take the force.

Well, I really don’t know which casting method is actually better, I seemed to be having issues with the standard method and after realizing that there’s something like “fastcast” I had to try it. I’m not experienced, that’s why any opinion like yours is pretty important in this case. I’ll try to work it the standard way and share on how it goes.

1 Like

Yeah that makes sense. In the case of a slanted part you’ll need to account for other supporting parts. I.e. when a corner of part 2 is above part 1 but the CoM of part 2 is not over part 1.

What issues were you having with the standard raycasting?

1 Like

Okay, I came back to the standard way.
I guess it’s time to introduce the other part of a script. So similarly, I have another function when TouchEnded. So the force from the bottom part will be subtracted because the upper part untouched.
The force distribution seems to work when part1 is stationary on the ground, while part2 is the one that falls on top.

Whenever I try to put both of the parts in the air and let them fall, the part1 bounces up, and they both meet in the air, basically hitting each other head on, and the rays just give up, all of them bring back nil. The Part2 force just sometimes doubles/triples for unknown reasons

Here’s the entirety of Part1’s script:

local ObjectDatabase = require(game.ServerStorage.Database)
local ParentPart = script.Parent.Parent
local ParentSize = ParentPart.Size
local ParentMASS = ParentPart.Mass
local intrudercorners2 = {}
local intrudercorners3 = {}
local StationaryLooseTouchers = {}

local function Mass(OtherPart)
	if OtherPart == workspace.Baseplate or OtherPart.CanCollide == false or OtherPart.Name == "ZonePart" then return end
	local params2 = RaycastParams.new()
	params2.FilterDescendantsInstances = {ParentPart}
	params2.FilterType = Enum.RaycastFilterType.Whitelist
	local Result
	local touch = false
	for i, key in pairs(StationaryLooseTouchers) do
		if OtherPart.Name == i and key == true then
			touch = true
			break
		end 
	end
	if touch == false then
		StationaryLooseTouchers[OtherPart.Name] = true
		for i = 1, 26 do
			ObjectDatabase.GetSurfacePoints(ObjectDatabase.Vertices, OtherPart, OtherPart.Size, intrudercorners2)
			Result = workspace:Raycast(intrudercorners2[i], (Vector3.new(0, -1, 0)).Unit, params2)
			if Result and Result.Normal.Y >= 0 then 
				StationaryLooseTouchersForces[OtherPart.Name] = ObjectDatabase.Forces[OtherPart.Name]
				ObjectDatabase.AddForces(ParentPart, OtherPart)
				break
			end
		end	
	end
end

local function Mass2(OtherPart)
	if OtherPart == workspace.Baseplate or OtherPart.CanCollide == false or OtherPart.Name == "ZonePart" then return end
	local params2 = RaycastParams.new()
	params2.FilterDescendantsInstances = {ParentPart}
	params2.FilterType = Enum.RaycastFilterType.Whitelist
	local Result
	
	local touch = false
	for i, key in pairs(StationaryLooseTouchers) do
		if OtherPart.Name == i and key == true then
			touch = true
			break
		end
	end		
	if touch == true then
		StationaryLooseTouchers[OtherPart.Name] = false
		for int = 1, 26 do
			ObjectDatabase.GetSurfacePoints(ObjectDatabase.Vertices, OtherPart, OtherPart.Size, intrudercorners3)
			Result = workspace:Raycast(intrudercorners3[int], (Vector3.new(0, -1, 0)).Unit, params2)
			if Result and Result.Normal.Y >= 0 then
				ObjectDatabase.SubtractForces(ParentPart, OtherPart)
				break
			end
		end	
	end	
end

ParentPart.Touched:Connect(Mass)
ParentPart.TouchEnded:Connect(Mass2)

Keep in mind, that the exact same script is in Part2

Edit: Actually each time i do it, there are different results, one time it was accurate haha.
I think the problem is, that the upper part somehow gets Part1’s force added/subtracted multiple times, even though, the rays from Part1 are going down, not up.
My guess is that calculations just can’t catch up with the physics, probably the calculated corners just aren’t accurate as they are late.

.Touched events are a bit hit and miss, you may be better connecting to run service and using BasePart:GetTouchingParts() and then work out the forces from that

1 Like