Help with my 2D Gun

I made a 2D Battle Royale Game, but I have a problem with my gun.

How do you keep the bullet from going through the wall, so that the Dummy behind the wall doesn’t get damaged?

This is my LocalScript:

local player = game.Players.LocalPlayer
local char = player.Character
local mouse = player:GetMouse()

local run = game:GetService("RunService")
local rep = game:GetService("ReplicatedStorage")

local gun = script.Parent
local part1 = gun:WaitForChild("Part1")
local target = gun:WaitForChild("Target")
local handle = gun:WaitForChild("Handle")
local event = gun:WaitForChild("GunEvent")
local wsEvent = gun:WaitForChild("WalkSpeedEvent")
local click = gun:WaitForChild("Click")
local shot = gun:WaitForChild("Shot")

local beam = part1.Beam

local equipped = false
local firing = false
local aiming = false

local reach = gun.Reach.Value

function advancedPos(pos, snap)
	return CFrame.new(
		math.floor(pos.X / snap + 0.5) * snap,
		math.floor(script.Parent.Parent.HumanoidRootPart.Position.Y / snap + 0.5) * snap,
		math.floor(pos.Z / snap + 0.5) * snap
	)
end

gun.Equipped:Connect(function()
	equipped = true
end)

gun.Unequipped:Connect(function()
	equipped = false
end)

mouse.Button1Down:Connect(function()
	aiming = true
end)

mouse.Button1Up:Connect(function()
	aiming = false
end)

run.RenderStepped:Connect(function()
	if equipped == true and aiming == true then
		beam.TextureLength = reach / 2
		
		local mouseRay = mouse.UnitRay
		local params = RaycastParams.new()
		params.FilterDescendantsInstances = {char, workspace.Bullets}
		params.FilterType = Enum.RaycastFilterType.Blacklist
		params.IgnoreWater = true
		
		local result = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * reach, params)
		
		if result then
			firing = true
			wsEvent:FireServer("10")
			part1.Parent = workspace
			target.Parent = workspace
			part1.CFrame = handle.CFrame
			target.CFrame = advancedPos(result.Position + result.Normal * 1.5, 0.001)
		else
			firing = false
			wsEvent:FireServer("20")
			target.Parent = rep
			part1.Parent = rep
		end
	else
		firing = false
		wsEvent:FireServer("20")
		target.Parent = rep
		part1.Parent = rep
	end
end)

while task.wait() do
	if equipped == true and aiming == true and firing == true then
		click:Play()
		event:FireServer(mouse.UnitRay, target.Position, part1.Position)
		task.wait(0.1)
	end
end

My Script:

local gun = script.Parent
local handle = gun:WaitForChild("Handle")
local event = gun:WaitForChild("GunEvent")
local wsEvent = gun:WaitForChild("WalkSpeedEvent")
local shot = gun:WaitForChild("Shot")

local rep = game:GetService("ReplicatedStorage")
local ammo = rep:WaitForChild("Ammo")

local bullets = workspace:WaitForChild("Bullets")

local equipped = false
local fired = false

local reach = gun.Reach.Value
local damage = gun.Damage.Value
local currentAmmo = gun.CurrentAmmo.Value
local firedTime = 0
local eventTime = 0
local fireRate = 0.1

local humanoidRP = nil

gun.Equipped:Connect(function()
	equipped = true
end)

gun.Unequipped:Connect(function()
	equipped = false
end)

function lerp(a, b, t)
	return a + (b - a) * t
end

function countCheck()
	if firedTime - eventTime >= fireRate or fireRate - (firedTime - eventTime) <= 1 / 60 then
		return true
	end
end

function fire(plr, mouseRay, targetPos, part1Pos)
	local char = plr.Character
	local hrp = char:WaitForChild("HumanoidRootPart")
	
	local newAmmo = ammo:Clone()
	newAmmo.Transparency = 1
	newAmmo.Name = "NewAmmo"
	newAmmo.Parent = bullets
	
	local newBullet = ammo:Clone()
	newBullet.Name = "NewBullet"
	newBullet.Parent = bullets
	
	local params = RaycastParams.new()
	params.FilterDescendantsInstances = {char, bullets}
	params.FilterType = Enum.RaycastFilterType.Blacklist
	params.IgnoreWater = true
	
	local lastPos = targetPos
	
	if currentAmmo == 0 then
		newBullet.Parent = rep
		newAmmo.Parent = rep
		shot.Parent = rep
	end
	
	while reach > 0 and currentAmmo > 0 do
		task.wait()
		currentAmmo -= 1
		humanoidRP = hrp
		
		newAmmo.Size = Vector3.new(0.1, 0.1, (targetPos - part1Pos).Magnitude)
		newAmmo.CFrame = CFrame.new(part1Pos, targetPos) * CFrame.new(0, 0, -(targetPos - part1Pos).Magnitude / 2)
		
		local result = workspace:Raycast(newAmmo.Position, newAmmo.CFrame.LookVector * reach, params)
		
		newBullet.Size = Vector3.new(0.25, 0.25, (targetPos - part1Pos).Magnitude / 4)
		
		for i = 0, 5, 1 do
			local t = i / 5
			
			newBullet.CFrame = CFrame.lookAt(part1Pos, targetPos)
			newBullet.Position = lerp(part1Pos, targetPos, t)
			task.wait(0.001)
		end
		
		if result then
			newBullet:Destroy()
			task.wait(0.1)
			newAmmo:Destroy()
			
			local hit = result.Instance
			local model = hit:FindFirstAncestorOfClass("Model")

			if model then
				local humanoid = model:FindFirstChildWhichIsA("Humanoid") or nil

				if humanoid then
					humanoid:TakeDamage(damage)
				end
			end

			break
		else
			newBullet:Destroy()
			task.wait(0.1)
			newAmmo:Destroy()
		end
		
		if newAmmo.Parent == nil then
			newBullet:Destroy()
			task.wait(0.1)
			newAmmo:Destroy()
			break
		end
	end
end

event.OnServerEvent:Connect(function(plr, mousePos, targetPos, part1Pos)
	local char = plr.Character
	local pack = script.Parent.Parent

	if not char == pack then return end

	firedTime = tick()

	if equipped == true and countCheck() then
		eventTime = tick()
		task.spawn(fire, plr, mousePos, targetPos, part1Pos)
		shot:Play()

	elseif fired == false then
		fired = true
		task.wait(fireRate - (firedTime - eventTime))
		fired = false
	end
end)

wsEvent.OnServerEvent:Connect(function(plr, status)
	if status == "10" then
		plr.Character.Humanoid.WalkSpeed = 10
		
	elseif status == "20" then
		plr.Character.Humanoid.WalkSpeed = 20
	end
end)

Thank you! (This is my first topic)

Look into raycasting. It’s exactly what you need for this, as it can detect if there’s such things as walls in the way.

Make sure that you have your character on the blacklist, though, or it may detect your character. Also, do this from the server for security reasons.

I did it:

local params = RaycastParams.new()
	params.FilterDescendantsInstances = {char, bullets}
	params.FilterType = Enum.RaycastFilterType.Blacklist
	params.IgnoreWater = true

Or because the lerp function?

function lerp(a, b, t)
	return a + (b - a) * t
end
for i = 0, 5, 1 do
			local t = i / 5
			
			newBullet.CFrame = CFrame.lookAt(part1Pos, targetPos)
			newBullet.Position = lerp(part1Pos, targetPos, t)
			task.wait(0.001)
		end

You are using the bullet’s position as origin of the ray, the position of bullet would be at the middle of it and in the case you provided above I think the middle position of the bullet is after the wall thus not hitting the wall. You have to cast the ray from the other end of the bullet.
(newAmmo.CFrame * CFrame.new(0,0,SizeZ/2)).Position or your variable part1Pos you would have to something like this to achieve the origin.

Where do I put the code? And what is the SizeZ?

SizeZ is the Size of the newAmmo in Z axis, replace newAmmo.Position as the origin with part1Pos If that doesn’t work try the first one I gave.

1 Like

Bro it works perfectly with part1Post or the first one. Thank you so much!

But I have another problem, how do I turn my gun into a shotgun?

For this you would have to cast multiple rays but in different angles from the same origin. I would suggest you to check other posts related to this or create a new topic if you are still struggling.

OK OK, I will try it later. Btw thanks for your help!