gun.Activated:Connect(function()
local target = mouse.Target
local targetSurface = mouse.TargetSurface
local hit = mouse.Hit
local start = handle.CFrame.p
local lookAt = hit.p
local ray = Ray.new(start, (lookAt - start).unit*300)
print(target.Name)
local partOnRay = game.Workspace:FindPartOnRay(ray, character)
wait(0.2)
local targetCharacter = target.Parent
if target.Name == 'Handle' then
targetCharacter = target.Parent.Parent
end
local targetHumanoid = targetCharacter:FindFirstChild('Humanoid')
if targetHumanoid then
-- do damage
else
shoot:FireServer(player.TeamColor.Color, hit, target, targetSurface)
end
end)
I’m currently making a gun, using raycasting (because I don’t know how else to) but I’m having problems with it not spreading the bullet shot. Atm the bullet will just go wherever you have clicked. I want to incorporate a ‘spread’ so the further away from the target you are, the greater spread. So shooting something in front of you would hit the spot you clicked, but shooting from a distance would give a random spread. Any information on this would be great! Or if there’s a better way of achieving gun projectiles!
Hmmm, well, I think we’ll want to first determine (randomly) which direction to offset the projectile’s course, and then determine the magnitude of the offset based on the magnitude of the direction (we’ll make it a unit direction for simplicity) and some predefined scale (possibly tuned to the gun that is being fired?). I’m imagining something like this:
local cos = math.cos
local sin = math.sin
local rnd = math.random
local up = Vector3.new(0, 1, 0)
local spread = 1/100 -- +-1 stud precision per 100 studs distance
local function newDir(dir)
dir = dir.Unit
local angle = rnd() * math.pi * 2
local axisA = up:Cross(dir)
local axisB = dir:Cross(axisA)
return dir + spread * (cos(angle) * axisA + sin(angle) * axisB)
end
I’d integrate it into your existing code something like this:
local start = handle.CFrame.p
local lookAt = hit.p
local ray = Ray.new(start, 300 * newDir(lookAt - start))
3 Likes
Doesn’t seem to be working. I changed the spread to be ‘1/2’ so I could see it better (because if its 2 studs away, then if it’s like 10 away I should be able to see it be quite a distance away from the mouse. But it stills just lands where the mouse has clicked
local up = Vector3.new(0, 1, 0)
local spread = 10/1
local function newDirection(direction)
direction = direction.Unit
local angle = math.random()*math.pi * 2
local axisA = up:Cross(direction)
local axisB = direction:Cross(axisA)
return direction + spread*(math.cos(angle)*axisA + math.sin(angle)*axisB)
end
EDIT even with an exaggerated number like 10/1 (move 10 studs away from click for every stud in distance) it still hits the exact spot i clicked from at least 50+ studs
Well, here are some questions for you then:
- Is the direction changing? By how much?
- When it say it just lands where the mouse has clicked, you mean the ray just hits where the mouse has clicked? Are you setting a part’s CFrame to the hit position of the raycast (if something was hit)?
- Could I see how you hooked up my code?
I’ll show you everything I’ve got: LocalScript
local up = Vector3.new(0, 1, 0)
local spread = 10/1
local function newDirection(direction)
direction = direction.Unit
local angle = math.random()*math.pi*2
local axisA = up:Cross(direction)
local axisB = direction:Cross(axisA)
return direction + spread*(math.cos(angle)*axisA + math.sin(angle)*axisB)
end
gun.Activated:Connect(function()
if configuration.RELOADING then return end
if configuration.ACTIVATED then return end
configuration.ACTIVATED = true
local target = mouse.Target
local targetSurface = mouse.TargetSurface
local hit = mouse.Hit
if not target then
configuration.ACTIVATED = false
return
end
local start = handle.CFrame.p
local lookAt = hit.p
local ray = Ray.new(start, 300 * newDirection(lookAt - start))
local partOnRay = game.Workspace:FindPartOnRay(ray, character)
wait(0.2)
local targetCharacter = target.Parent
if target.Name == 'Handle' then
targetCharacter = target.Parent.Parent
end
local targetHumanoid = targetCharacter:FindFirstChild('Humanoid')
if targetHumanoid then
-- do damage
else
shoot:FireServer(player.TeamColor.Color, hit, target, targetSurface)
end
configuration.ACTIVATED = false
end)
Server
local function weld(part1, part2)
local weld = Instance.new('Weld', part1)
weld.C0 = part1.CFrame:inverse()*part2.CFrame
weld.Part0 = part1
weld.Part1 = part2
return weld
end
shoot.OnServerEvent:connect(function(player, color, hit, target, targetSurface)
local bullet = Instance.new('Part')
bullet.CFrame = CFrame.new(hit.p)*CFrame.Angles(target.CFrame:toEulerAnglesXYZ())
bullet.Name = 'Bullet'
bullet.Anchored = false
bullet.CanCollide = false
bullet.Transparency = 0.5
bullet.TopSurface = Enum.SurfaceType.SmoothNoOutlines
bullet.BottomSurface = Enum.SurfaceType.SmoothNoOutlines
bullet.RightSurface = Enum.SurfaceType.SmoothNoOutlines
bullet.LeftSurface = Enum.SurfaceType.SmoothNoOutlines
bullet.FrontSurface = Enum.SurfaceType.SmoothNoOutlines
bullet.BackSurface = Enum.SurfaceType.SmoothNoOutlines
local x = 2
local y = 2
local z = 2
if targetSurface == Enum.NormalId.Back or targetSurface == Enum.NormalId.Front then
z = 0.1
elseif targetSurface == Enum.NormalId.Right or targetSurface == Enum.NormalId.Left then
x = 0.1
elseif targetSurface == Enum.NormalId.Top or targetSurface == Enum.NormalId.Bottom then
y = 0.1
end
bullet.Size = Vector3.new(x, y, z)
bullet.BrickColor = BrickColor.new(color)
debris:AddItem(bullet, 10)
bullet.Parent = projectiles
weld(bullet, target)
end)
I’ve kinda cut out the variables, etc. Just waste of lines for you to read. Basically it creates a part where you have shot, so that’s how I know where the ‘bullet’ has landed basically. I’m not sure if something inside the server script might be ignoring what you’ve done?
EDIT Ok going over it, I see the fireserver event is firing the hit, which is basically where the mouse has clicked, so that’s probably why. How would I go about integrating the ‘actual spot’ it should be hitting?
As it turns out, the workspace:FindPartOnRay() method returns a tuple of three values:
- The part hit
- The point of intersection
- The surface normal at the point of intersection on the part
Which mean that we can do something like this:
local hitPart, hitPoint = workspace:FindPartOnRay(ray, character)
But note that if no part was hit, then the hitPoint shouldn’t be used (I forget what value it actually gets set too though)
How would I go about intergrating it into my code?
Well, I’d change this section like so:
if configuration.RELOADING then return end
if configuration.ACTIVATED then return end
configuration.ACTIVATED = true
local start = handle.CFrame.p
local lookAt = mouse.hit.p
local direction = 300 * newDirection(lookAt - start)
local ray = Ray.new(start, direction)
local target, hit = game.Workspace:FindPartOnRay(ray, character)
if not target then
configuration.ACTIVATED = false
return
end
...
And in the server script just be aware that hit
is now a Vector3 instead of a CFrame, so use hit
instead of hit.p
5 Likes