Help with Raycasting Using Attachments

So for a while now, I’ve been trying to make a simple “module” that can be used for a good range of magic-type projectiles and abilities that uses the world position of attachments for raycasting and hit detection. Yes, I know that there are modules out there that can already do this, but I feel like most of them are too specific (e.g. fastcast is specialized for guns and small, fast projectiles) or are simply overkill for my purpose.

In my module, I’ve managed to get a lot of things working, including the raycasting, however there is one small issue. The faster the attachment moves, the further away from the hitbox the rays will begin and end. It’s hard to explain, so I linked a couple of videos (I apologize for the quality🗿):

(The origin of the ray is the cyan blue part, the direction of the ray is the bright red part, and the destination of the part is the light green part. The green circles are the attachments themselves)

In the first video, the projectile had a velocity of 1 and the origin was right on top of the attachment, and the destination part was right in front. This is how I want it, but in the next video, the projectile was moving at a velocity of 3 and the ray was just slightly in front of the attachment. This isn’t too bad, but in the last video, the projectile had a velocity of 60 (the speed I want) and the ray was far ahead of the projectile, which leads to the ray detecting an object prematurely. I don’t yet know if this has anything to do with this, but everything is done on the server (and yes I know VFX is bad on the server, I’m working on moving it to the client). Does anybody know how this could be fixed?

For those who want to see the code:

if object:IsA("BasePart") then
		object:SetNetworkOwner(nil)
		partOrigin = object.Position
		
		object.CFrame = CFrame.lookAt(object.Position, mouseCFrame.Position)
		
		local mainAttachment = object:FindFirstChild("Main")
		
		local linearVelocity = Instance.new("LinearVelocity")
		linearVelocity.MaxForce = 100000000
		linearVelocity.Attachment0 = mainAttachment
		linearVelocity.VectorVelocity = (mouseCFrame.Position - object.Position).Unit * velocity
		linearVelocity.Parent = mainAttachment
		
		local alignOrientation = Instance.new("AlignOrientation")
		alignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
		alignOrientation.Attachment0 = mainAttachment
		alignOrientation.RigidityEnabled = mainAttachment
		alignOrientation.CFrame = mouseCFrame
		alignOrientation.Parent =mainAttachment
		
		eventConnection = runService.Heartbeat:Connect(function()	
			if (object.Position - partOrigin).Magnitude > maxDistance then
				hitHandled(nil)
			end
			
			for i, attachment in ipairs(object:GetChildren()) do
				if attachment.Name == "RayPoint" and attachment:IsA("Attachment") then
					local rayOrigin = attachment:GetAttribute("LastPosition") or attachment.WorldPosition
					local rayDestination = attachment.WorldPosition
					local rayDirection = rayDestination - rayOrigin
					
					local rayCastResult = workspace:Raycast(rayOrigin, rayDirection, fireParams)
					
					if rayCastResult then
						local hitObject = rayCastResult.Instance
						print(hitObject)
						
						if hitObject:IsDescendantOf(workspace:WaitForChild("Passthrough")) or hitObject:IsDescendantOf(workspace:WaitForChild("AbilityFX")) then return end
						
						hitHandled(rayCastResult)
					end
					
					local visualizedRay: BasePart = visualizeRay(rayOrigin, rayDirection, rayDestination)
					debris:AddItem(visualizedRay, .04)
					
					attachment:SetAttribute("LastPosition", attachment.WorldPosition)
				end
			end
		end)
	end	
2 Likes

Can you summarize this? I’m not sure what you mean by this.

Do you mean that the projectile does not detect something that it is supposed to detect, or the other way around? If so, why would this be necessary?

What I mean is that the projectile fires rays that detect objects before the projectile is visibly hitting the object. I linked another video that hopefully shows more of what I mean.

The ray does detect the object ahead of it, but visibly it doesn’t actually hit the object. Essentially, the ray is a bit too far ahead of the actual object and I want it to detect when the projectile is visibly hitting the object.

Not sure what the problem is, theoretically I believe the code should work.

Things I would do to test out further though.

Using other runservice events .Stepped maybe.

Doing it purely on the client, to test if it’s a server vs client visualization issue.

Similar to creating a part on the server to track the humanoid root part, it may just be lagging behind on the client.

1 Like

I don’t see you setting the current worldposition of the attachment in the loop. Perhaps that’s the cause?

Although I find this question hard to understand, I think I know what you want.

So basically, the raycast detects whatever is in front of it. You will need to somehow detect this and have the detected part become “hit” later. You can do this by assumingly seeing if the next heartbeat step will cause the attachment to go past the target and go just enough steps until it detects that the next step will let the attachment go past the target. I’ll have logic like this:

while the target detected by the raycast is the same, do nothing

This will make sure that whenever the part changes (to the baseplate or something), it will assume the projectile went through the part. But this is problematic because if the player receiving the hit dodges the projectile, the projectile will think that it hit the player. This is why I think that the raycast should be smaller, and just the velocity it needs to be. This is an even better solution, and you just simply need to detect if the next frame contains the attachment going through the target or not.

1 Like

After a couple of days, I have been able to use your solution to fix the problem. As dthecoolest said, the problem ended up being a server-vs-client visualization issue, and after testing it on the client-side only, it was completely smooth. I was able to fix this issue by using TweenService rather than body movers (somehow this fixes the problem). However, it still looked as if it deals damage upon touching the object rather then completely hitting it, which is where your solution comes into play. After making the ray smaller and detecting when the target changes rather than when a target exists at all, it works flawlessly. Thanks to both you and @dthecoolest for your guidance.

1 Like