Laser bullets "splitting" when piercing a target

I’m working on a weapons system for my game that uses a heavily modified version of the laser gun in the “Hit Detection with Lasers” tutorial on the Creator Hub Documentation. My mods are working perfectly as far as I can tell, except for the piercing bullets. In the weapon, there’s a variable called pierced which increases every time it hits an enemy up to the maximum amount allowed (which is maxpierced). The weapon repeatedly fires bullets up until pierced exceeds maxpierced, with each bullet being rendered seperately; while they are separate bullets, they are intended to look like one continuous bullet as seen here:
image
This is how it’s supposed to look…
image
…but this is how it actually looks. The highlighted bullet is the second one that was created, so it pierces the enemy but doesn’t deal damage since the Raycast is updated to not do so (explanation below).

The weapon has a part called FirePoint inside it, and the bullets are made to look like they are starting at FirePoint’s Position. However, the Raycast that is used to visualize the bullets actually begins at the character of the player who fired; more specifically, the character’s torso’s NeckAttachment. I’ve tested it out so that the Raycast also starts at FirePoint (as seen in the first example) and it looks perfectly fine, so I’m certain that the issue stems from the actual Raycast starting at NeckAttachment but the visualized bullet starting at FirePoint.

The reason I want it to start at NeckAttachment is so that there are no discrepancies in the weapon’s range; if the range is set to 70, I want it to travel 70 studs maximum, and FirePoint is not meant to be placed exactly the same in each weapon model since it may look like the bullet is not coming out of the gun’s barrel. Here is all the relevant code from the main weapon LocalScript and the LaserRenderer ModuleScript.


Weapon LocalScript

function fire()
	local mouselocation = getmouse() -- gets the mouse's location, I've tested this and this doesn't appear to be what's causing the issue
	local raycastresult

	repeat
		local targetdirection = (mouselocation - neckattach.WorldPosition).Unit -- "neckattach" is the NeckAttachment I was referring to
		local direction = targetdirection * range -- the weapon's defined range (here, it's 140)
		local raycastparams = RaycastParams.new()
		raycastparams.FilterType = Enum.RaycastFilterType.Exclude
		raycastparams.FilterDescendantsInstances = filtertable -- models are added here and ignored if the loop continues
		raycastparams.RespectCanCollide = false
		raycastparams.IgnoreWater = false
		raycastresult = workspace:Raycast(neckattach.WorldPosition, direction, raycastparams)
		local hitpos
		if raycastresult then
			hitpos = raycastresult.Position
			local charmodel = raycastresult.Instance:FindFirstAncestorOfClass("Model") -- see if the bullet hit a model
			if charmodel then
				local humanoid = charmodel:FindFirstChildOfClass("Humanoid")
				local hrp = charmodel:FindFirstChild("HumanoidRootPart")
				if humanoid and hrp then -- if true, then a character was detected
					table.insert(filtertable, charmodel) -- if a model is in "filtertable", it will not be detected by the Raycast if it loops
				end
			end
		else -- no character was detected, so have the Raycast continue for the rest of its range
			hitpos = neckattach.WorldPosition + direction
		end
		bulletfired:FireServer(tool.FirePoint, hitpos, currentbullettype) -- "bulletfired" calls the same "laserrender" module, allowing the other players to see the bullet
		laserrender.createLaser(tool.FirePoint, hitpos, currentbullettype) -- creates the bullet, but it's only visible by the LocalPlayer
		pierced = pierced + 1
	until not raycastresult or pierced > maxpierced -- if maxpierced is 0 or pierced has exceeded maxpierced, this loop should end
--loop ends here and everything is reset
	pierced = 0
	timeofpreviousshot = tick()
	table.clear(filtertable)
end

LaserRenderer ModuleScript

function LaserRenderer.createLaser(firepoint, endPosition, bullettype)
	local startPosition = firepoint.Position

	local laserDistance = (startPosition - endPosition).Magnitude
	local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
	local laserPart = normalbullet:Clone() -- "normalbullet" is a part whose ancestor is ReplicatedStorage
	laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
	laserPart.CFrame  = laserCFrame
	laserPart.Parent = workspace:FindFirstChild("Effects")

	game.Debris:AddItem(laserPart, SHOT_DURATION)
end

I understand that this topic might be a little complicated and I may have failed to explain things clearly, so don’t be afraid to ask me to clarify. To reiterate, the problem comes from the fact that the Raycast used to visualize the bullets starts at NeckAttachment, but the bullet is made to appear from the weapon’s FirePoint for cosmetic purposes.

1 Like

I’m assuming these two functions create the laser visual by having it start at the first parameter and end at the second one? If that’s the case, that would be the problem since that means the laser will ALWAYS start at the firepoint, and not at where the last bullet met its target.

You can try restructuring your code to make the starting point depend on the last hit position, and default to the firepoint if it doesn’t exist

local bulletStart: Vector3 = tool.FirePoint
...
	repeat
	...
	raycastresult = workspace:Raycast(neckattach.WorldPosition, direction, raycastparams)
	if raycastresult then
		...
		bulletStart = raycastresult.Position
		...
	end
	...
	bulletfired:FireServer(bulletStart, hitpos, currentbullettype)
	laserrender.createLaser(bulletStart, hitpos, currentbullettype)
2 Likes

It works mostly well, but since the second bullet doesn’t start at the FirePoint, it bends when it hits the target.
image

Instead of using a target position, just get the direction of the previous laser which should be (fire point - target point).unit

1 Like

I’ve experimented a little bit, but I’m not sure where I’d implement this in the script.