Bullet Weld slightly change it's position

So I made a gun and it fires bullet, and once the bullet hit something it will be weld to the part that hits it, but the problem is that whenever it hit something the bullet position slightly moves. I tried changing some of the code and even adding hit detection but the result is still the same.

A video of it.

Bullet.Touched:Connect(function(Hit)
		if Hit ~= nil and Hit.Name ~= "Bullet" and Hit.Name ~= "Blood" and not Hit:IsDescendantOf(Tool) and not Hit:IsDescendantOf(Character) then
			if not CheckIfHit then CheckIfHit = true else return end
			--[[if Hit:FindFirstAncestorOfClass("Model") and Hit:FindFirstAncestorOfClass("Model"):FindFirstChild("Humanoid") and Hit:FindFirstAncestorOfClass("Model") ~= Character then
				game.ReplicatedStorage.GunRemote.TakeDamage:FireServer(Hit.Name, Hit:FindFirstAncestorOfClass("Model"):FindFirstChild("Humanoid"), Setting.BulletInfo["Damage"])
				MakeBlood(Bullet.Position, Hit)
			elseif game.Workspace:FindFirstChild("Glass") and Hit:IsDescendantOf(game.Workspace.Glass) then
				game.ReplicatedStorage.GunRemote.HitGlass:FireServer(Hit)
			end]]
			if Setting.BulletInfo["WeldToPart"]["Option"] then
				print(Hit.Name)
				local Weld = Instance.new("Weld")
				Weld.Part0 = Hit
				Weld.Part1 = Bullet
				Weld.C0 = Hit.CFrame:inverse()
				Weld.C1 = Bullet.CFrame:inverse()
				Weld.Parent = Bullet
				--game:GetService("Debris"):AddItem(Bullet, Setting.BulletInfo["WeldToPart"]["DebrisTime"])
			end
-- The rest has nothing to do with the bullet.
2 Likes

.Touched does not work reliably for projectiles and is not recommended in any way. I recommend implementing a projectile motion (bullet drop) formula and apply it onto CFrames and an anchored projectile. For the hit detection part, you should raycast inbetween each projectile position using its previous position and its new position which you get using this formula. This is absolutely the best and most accurate way to go about doing this.

1 Like

I tried raycasting too

local CheckForPart
	CheckForPart = game:GetService("RunService").RenderStepped:Connect(function()
		local NewRay = Ray.new(Bullet.CFrame.Position, Bullet.CFrame.lookVector * Bullet.Size.Z)
		local RayHit, Position = game.Workspace:FindPartOnRayWithIgnoreList(NewRay, Ignore, false, true)
		if RayHit ~= nil and RayHit.Name ~= "Bullet" and not RayHit:IsDescendantOf(Player.Character) then
			print(RayHit)
			Bullet.Anchored = true
			CheckForPart:Disconnect()
		end
	end)

But whenever the bullet speed exceed 100-200 studs it just ignore the part and flies away. I also tried the bullet drop but it just go through part when I shot too close to the part.

1 Like

You can’t just anchor the projectile and expect it to work. You need to position it where the ray hit an object.

Also, this is not how you should go about to make sure you don’t hit the player who fired it. You would simply just add the Character model to the IgnoreList before you fire the ray.

For the actual Ray origin and direction, you’ll need to use the position the projectile had during the previous Heartbeat/RenderStep and its current position and fire a ray inbetween those two positions.

1 Like

The reason I anchored it is just to see if the bullet hit something properly, the bullet will anchor itself if it hit somethings.

Edited: Most of the bullet just flew away if the speed exceed 100-200.

1 Like

But you’re stating that the projectile doesn’t weld accurately? I just pointed out why that happens…?

No I mean I also tried welding the bullet and it works just like anchor except it doesn’t stick to something that it hits or hits it.

As I already said twice now, you need to position the projectile to where the ray hit an object for it to ‘stick’.

Ray -> Position the projectile to where the ray hit -> Weld.

But about 85% of the bullet just flew into the part and away into the void even when I used the ray.

I can send you the link of the game that the problem occurs too if you want.

What is your current code? 30 chars

local CheckForPart
	CheckForPart = game:GetService("RunService").RenderStepped:Connect(function()
		local NewRay = Ray.new(Bullet.CFrame.Position, Bullet.CFrame.lookVector * Bullet.Size.Z)
		local RayHit, Position = game.Workspace:FindPartOnRayWithIgnoreList(NewRay, Ignore, false, true)
		if RayHit ~= nil and RayHit.Name ~= "Bullet" and not RayHit:IsDescendantOf(Player.Character) then
			print(RayHit)
			if Setting.BulletInfo["WeldToPart"]["Option"] then
				local Weld = Instance.new("Weld")
				Weld.Part0 = RayHit
				Weld.Part1 = Bullet
				Weld.C0 = RayHit.CFrame:inverse()
				Weld.C1 = Bullet.CFrame:inverse()
				Weld.Parent = Bullet
				game:GetService("Debris"):AddItem(Bullet, Setting.BulletInfo["WeldToPart"]["DebrisTime"])
			end
			CheckForPart:Disconnect()
		end
	end)

I also use this one but it instantly get the part that it hits not when the part flies toward it

local FirePoint = Tool.FirePoint.Position
	local Raycast = Ray.new(FirePoint, (Mouse.Hit.p - FirePoint).Unit * Setting.BulletInfo["Range"] + (Vector3.new(math.random(-Setting.BulletInfo["Spread"] * 10000,Setting.BulletInfo["Spread"] * 10000),math.random(-Setting.BulletInfo["Spread"] * 10000,Setting.BulletInfo["Spread"] * 10000),math.random(-Setting.BulletInfo["Spread"] * 10000,Setting.BulletInfo["Spread"] * 10000)) / (1500*2.5)))
	local Hit, Position = game.Workspace:FindPartOnRayWithIgnoreList(Raycast, Ignore, false, true)
	local Distance = (FirePoint - Position).magnitude
	local Bullet = Instance.new("Part", game.Workspace)
	Bullet.Name = "Bullet"
	Bullet.Anchored = false
	Bullet.CanCollide = false
	Bullet.Massless = true
	Bullet.Size = Setting.BulletInfo["Size"]
	Bullet.CFrame = CFrame.new(FirePoint, Position) * CFrame.new(0, 0, -Setting.BulletInfo["Size"].Z/2 + Setting.BulletInfo["BulletSpeed"]/100)
	Bullet.Transparency = Setting.BulletInfo["Transparency"]
	Bullet.BrickColor = BrickColor.new(Setting.BulletInfo["Color"])
	Bullet.Material = Setting.BulletInfo["Material"]
	Bullet.Velocity = Bullet.CFrame.lookVector * Setting.BulletInfo["BulletSpeed"]
	local BodyForce = Instance.new("BodyForce", Bullet)
	BodyForce.Force = Vector3.new(0,workspace.Gravity,0) * Bullet:GetMass()
	game:GetService("Debris"):AddItem(Bullet, 5)
	Bullet.Touched:Connect(function(Hit)
		if Hit ~= nil and Hit.Name ~= "Bullet" and Hit.Name ~= "Blood" and not Hit:IsDescendantOf(Tool) and not Hit:IsDescendantOf(Character) then
			if Hit:FindFirstAncestorOfClass("Model") and Hit:FindFirstAncestorOfClass("Model"):FindFirstChild("Humanoid") and Hit:FindFirstAncestorOfClass("Model") ~= Character then	
				game.ReplicatedStorage.GunRemote.TakeDamage:FireServer(Hit:FindFirstAncestorOfClass("Model"):FindFirstChild("Humanoid"), Setting.BulletInfo["Damage"])
				MakeBlood(Position, Hit)
			elseif game.Workspace:FindFirstChild("Glass") and Hit:IsDescendantOf(game.Workspace.Glass) then
				game.ReplicatedStorage.GunRemote.HitGlass:FireServer(Hit)
			end
			print(Hit.Name)
			Bullet:Destroy()
		end
	end)

You might want to try this:

Bullet.Anchored = true
Bullet.CFrame = CFrame.new(Position) * CFrame.fromOrientation(Bullet.CFrame:ToOrientation())
local Weld = Instance.new("Weld")
Weld.C0 = RayHit.CFrame:inverse() * Bullet.CFrame
Weld.Part0 = RayHit
Weld.Part1 = Bullet
Bullet.Anchored = false

instead of this:

local Weld = Instance.new("Weld")
Weld.Part0 = RayHit
Weld.Part1 = Bullet
Weld.C0 = RayHit.CFrame:inverse()
Weld.C1 = Bullet.CFrame:inverse()

Nothing changed

Please read what I said and try to adapt your code to it. You’re simply just casting a ray in front of the object, which naturally lead to hit-detection problems like these.

I edited my code again, sorry if I didn’t follow some of your steps since I’m not from the country that is influenced in English.

I’m not sure if I did it correctly.

local PreviousPosition = Bullet.Position
	local CheckForPart
	CheckForPart = game:GetService("RunService").RenderStepped:Connect(function() 
		local NewRay = Ray.new(PreviousPosition, (PreviousPosition - Bullet.CFrame.lookVector) * (PreviousPosition - Bullet.CFrame.lookVector).Magnitude)
		local RayHit, Position = game.Workspace:FindPartOnRayWithIgnoreList(NewRay, Ignore, false, true)
		if RayHit ~= nil and RayHit.Name ~= "Bullet" and not RayHit:IsDescendantOf(Player.Character) then
			print(RayHit)
			if Setting.BulletInfo["WeldToPart"]["Option"] then
				Bullet.Anchored = true
				local Weld = Instance.new("Weld")
				Weld.Part0 = RayHit
				Weld.Part1 = Bullet
				Weld.C0 = RayHit.CFrame:inverse()
				Weld.C1 = Bullet.CFrame:inverse()
				Weld.Parent = Bullet
				Bullet.Anchored = false
				game:GetService("Debris"):AddItem(Bullet, Setting.BulletInfo["WeldToPart"]["DebrisTime"])
			end
			CheckForPart:Disconnect()
		end
		PreviousPosition = Bullet.Position
	end)

Remember if you used the API as a reference for this part, you’re supposed to subtract the two positions to get the direction unit Vector3 not subtract one position with a unit.

local NewRay = Ray.new(PreviousPosition, (Bullet.CFrame.p - PreviousPosition).unit * (PreviousPosition - Bullet.CFrame.p).magnitude)
1 Like

I think I’ll give up for now thank you for helping me though. There are probably some other way to do the detection.

I’ll gladly help you out further on discord if you’d like about doing this part:

There’s no point in leaving you with nothing but frustration. :slight_smile:

1 Like