PartOnRay not always detected?

Been working on a Wand system that doesn’t seem to detect the PartOnRay each time,
As shown below - A majority of the time it will detect the Part and then creates the hit effect so forth, however other times it will pass straight through a solid brick / Player and this proves problematic.

Projectile uses:

Code
for Movement = 1,math.huge do wait()
	if SpellPart then else return end
	game:GetService("RunService").Heartbeat:wait()
	SpellPart.CFrame = SpellPart.CFrame + SpellPart.CFrame.LookVector * math.random(6, 10)
		local SpellRay = Ray.new(SpellPart.Position, (Wand.Tool["Tip"].Position - SpellPart.Position).Unit * 10)
		local Obj, Position = workspace:FindPartOnRay(SpellRay, IgnoreList)
		if (SpellPart.Position - Position).Magnitude <= 6 then
		if Obj.Parent:FindFirstChild("Protego") == nil and Obj.Parent.Parent:FindFirstChild("Protego") == nil then
		SpellPart:remove() SpellPart = nil
		SpellRayHit(Player, Wand, SpellPart, SpellTrail, Obj, Position)
		return
		else
		SpellPart.CFrame = CFrame.new(SpellPart.CFrame.p, Player.Character["HumanoidRootPart"].CFrame.p)
		IgnoreList = nil
		end
		else end
	end
1 Like

That line would shoot a ray from the spell part back to the wand if I’m not mistaken. It’s possible that in some cases your projectile which moves from math.random(6, 10) studs in distance per heartbeat is further than your ray’s length which is 10 as shown on the line above.

Instead of firing the ray from the projectile back to the wand, it would probably be better to send it from the projectile in the direction of the projectile. That could be done like so by changing the line above to:

local SpellRay = Ray.new(SpellPart.Position, SpellPart.CFrame.LookVector * 20)

This would start the ray at your SpellPart’s position and send it in the direction of the SpellPart. Note that I’ve also made the ray longer (20 studs instead of 10) this should fix the issue you’re seeing.

1 Like

Hi, this seems to still be causing an issue for me.
Though I have just removed the math.random(6,10) and replaced it with * 5 as a singularity and it doesn’t seem to be causing the issue anymore? Could the momentum combined with the Unit have been causing the issue?

EDIT:
I was wrong, it’s still happening.

Okay, one more thing I would recommend trying is moving the ray check before moving the SpellRay. It’s possible that the SpellRay is moving through the ground before the ray is casted.

The issue here seems to me that the projectile is going through the ground before the ray has checked for collisions.

I don’t quite understand what you mean by moving the RayCheck before the SpellRay?

Haha, sorry the words are kinda close together. So these lines here:

local SpellRay = Ray.new(SpellPart.Position, SpellPart.CFrame.LookVector * 20)
local Obj, Position = workspace:FindPartOnRay(SpellRay, IgnoreList)

should be before this line:

SpellPart.CFrame = SpellPart.CFrame + SpellPart.CFrame.LookVector * math.random(6, 10)

There’s actually not even a reason to move the SpellPart if the SpellRay hits something. You could check if the ray hit something and then remove the SpellPart before even moving it.

2 Likes

Hi, tried this too and it also didn’t work :confused:

Hey KossmoZ,
Can you show your code now?

1 Like
for Movement = 1,math.huge do wait()
	if SpellPart then else return end
	game:GetService("RunService").Heartbeat:wait()
	SpellPart.CFrame = SpellPart.CFrame + SpellPart.CFrame.LookVector * 5
		local SpellRay = Ray.new(SpellPart.Position, SpellPart.CFrame.LookVector * 20)
		local Obj, Position = workspace:FindPartOnRay(SpellRay, IgnoreList)
		if (SpellPart.Position - Position).Magnitude <= 6 then
		if Obj.Parent:FindFirstChild("Protego") == nil and Obj.Parent.Parent:FindFirstChild("Protego") == nil then
		SpellPart:remove() SpellPart = nil
		SpellRayHit(Player, Wand, SpellPart, SpellTrail, Obj, Position)
		return
		else
		SpellPart.CFrame = CFrame.new(SpellPart.CFrame.p, Player.Character["HumanoidRootPart"].CFrame.p)
		IgnoreList = nil
		end
		else end
	end

Give this a try. I added some comments to hopefully help you understand the code a bit better.

local SpellSpeed = 5

for Movement = 1, math.huge do 
  if not SpellPart then break end
  wait()
  -- Do ray collision test before moving the SpellPart.
  local SpellRay = Ray.new(SpellPart.Position, SpellPart.CFrame.LookVector * SpellSpeed)
  local Obj, Position = workspace:FindPartOnRay(SpellRay, IgnoreList) -- Is IgnoreList defined somewhere? It's not shown in your code block.
  if not Obj then
    -- Ray didn't hit anything, move the SpellPart and test again.
    SpellPart.CFrame = SpellPart.CFrame + SpellPart.CFrame.LookVector * SpellSpeed
  else
    -- Ray hit something. Do collision logic.
    if Obj.Parent:FindFirstChild("Protego") == nil and Obj.Parent.Parent:FindFirstChild("Protego") == nil then
      SpellPart:remove()
      SpellRayHit(Player, Wand, SpellPart, SpellTrail, Obj, Position)
      break
    else
      SpellPart.CFrame = CFrame.new(SpellPart.CFrame.p, Player.Character["HumanoidRootPart"].CFrame.p)
      break
    end
  end
end
3 Likes

I would think IgnoreList is referring to an object, because he’s using FindPartOnRay and not FindPartOnRayWithIgnoreList. @OP I’d recommend that you have your variable names represent what they do, as this shows not to be a list of objects.

EDIT
@OP I’m just curious, but why’re you using a ray over a projectile? Wouldn’t it be easier to have a projectile go flying, then when it hits (via Touched) it determines whether it hit a player or not?

The ignore list is simply the Players character, however when it hits a protection spell it repels back into their direction and removes them from the IgnoreList allowing them to be vulnerable to damage.

I just wanted to verify that he had actually defined it since I couldn’t see it in the code. I figured it was a model or part anyway.

1 Like

RayOnPart seems to fire much faster than. Touched event and also works much more benficially when it comes to getting the position and so forth.

Using the Ray lets me detect the magnitude better also to note if its within the distance from said PartOnRay and if so, causes the effect.

Just a word of warning to you. If you plan on doing this Raycasting method from the client side you’ll want to verify that the ray actually hit a player. The problem is that it will be impossible to truely verify that because it inevitably requries information from the client to verify. You are almost guaranteed to have issues with exploiters who manipulate the data being sent to the server for verification. There are ways to make it trickier for an exploiter to manipulate the verification but there is no way to totally secure it.

You can also do the raycasting from the server side but that also comes with its downsides. It’s going to feel slower for the client since there is a delay between client and server communications. This is a far more secure method, however.

The .Touched approach is also something that can be handled server side. Since the server handles physics separately from the client there’s almost no way the client can manipulate this, assuming you’re checking for touches server side. This does come with the same draw back as the server-side raycasting method above.

Once you utilize any method online you will find that there are inherent drawbacks to each. You sacrifice security for speed or vice versa. Just keep these things in mind as you implement your projectile logic so that you don’t need to do a major overhaul down the road.

The .Touched approach is also something that can be handled server side. Since the server handles physics separately from the client there’s almost no way the client can manipulate this.

If we’re talking about a projectile launched from the wand, you’re gonna have to manually call SetNetworkOwner() on it. If you don’t, there are probably going to be some edge cases where the client is automatically assigned to it. When the server sets up the Touched event for a part that has a client as a network owner, he is effectively setting up a remote event, asking for the client to tell it whenever it hit something.

You can see this problem in the infamous “range hack” on old-school swords by extending the length of the handle locally (that the client is automatically assigned to).

Tried this method also, and the issue still seems to be happening.
Perhaps I could send you the entire thing if that makes the analysis easier?

That might help. I’m not sure what you’re seeing honestly.

Actually, without seeming like an idiot :rofl: This actually worked.
Turns out I was updating it to a version of the Wand that wasn’t even being used by the Player itself!
Trust me to do that!

Thanking you so much!

1 Like