The raycast origin is your camera position / gun barrel, depending on where you want to shoot from
The direction is the camera look vector / gun barrel look vector
Add spread by adding a Vector3 to the direction. The X value is the horizontal spread, and the Y value is the vertical spread. You can ignore the Z value.
Use RaycastParams to ignore the player’s character, so it’s not detected by the raycast
Do a new raycast for each pellet
No, raycasts don’t cause much lag
Code example:
local PELLETS = 8
local HORIZONTAL_SPREAD = NumberSequence.new(-0.2, 0.2) -- Change these to 1 variable if you want
local VERTICAL_SPREAD = NumberSequence.new(-0.2, 0.2)
local origin = '...' -- Get the origin from the player's character / elsewhere
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = { character } --TODO Get the character from the player
raycastParams.IgnoreWater = true
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local function shoot()
-- Whatever else you're doing
for pellet=1, PELLETS do
local spreadX = HORIZONTAL_SPREAD.Min + (math.random() * (HORIZONTAL_SPREAD.Max - HORIZONTAL_SPREAD.Min))
local spreadY = VERTICAL_SPREAD.Min + (math.random() * (VERTICAL_SPREAD.Max - VERTICAL_SPREAD.Min))
local result = workspace:Raycast(
origin, -- Raycast origin (gun barrel)
origin.CFrame.LookVector + Vector3.new(spreadX, spreadY),
raycastParams
)
end
end
Here is a simple script I whipped up. There is most likely more sophistacted methods you can do to achieve the spread, but here it is:
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {character} -- don't detect the shooter's character, it might get in the way
raycastParams.IgnoreWater = true
local mouse = player:GetMouse()
local MAX_DISTANCE = 50
local BULLETS = 8
local SPREAD = 10
local function shoot(targetCF)
local origin = character.RightHand.CFrame * CFrame.new(0,0,-character.RightHand.Size.Z/2) -- Position at the edge of right hand
for i = 1, BULLETS do
local targetCF = targetCF * CFrame.new(math.random(-SPREAD, SPREAD), math.random(-SPREAD, SPREAD), 0)
local direction = -(origin.Position - targetCF.Position).Unit * MAX_DISTANCE
local part = script.Part:Clone()
part.Size = Vector3.new(.2,.2, direction.Magnitude)
part.CFrame = CFrame.lookAt(origin.Position, targetCF.Position) * CFrame.new(0,0,-part.Size.Z/2)
part.Parent = workspace
game.Debris:AddItem(part, 3)
local raycastResult = workspace:Raycast(origin.Position, direction, raycastParams)
if raycastResult then
print("Hit!")
end
end
end
game:GetService("UserInputService").InputBegan:Connect(function(input, gpe)
if not gpe and input.UserInputType == Enum.UserInputType.MouseButton1 then
shoot(mouse.Hit)
end
end)
sorry to bother, but how would i get direction and make that direction have a distance?
my current code looks like this
-- this is inside an OnServerEvent event
local mossberg = player.Character:FindFirstChildOfClass("Tool")
local damage = 11
local PELLETS = 8
local HORIZONTAL_SPREAD = {min = -0.2, max = 0.2}
local VERTICAL_SPREAD = {min = -0.2, max = 0.2}
local MAX_DISTANCE = 50
local origin = mossberg:WaitForChild("Flash")
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = { player.Character }
raycastParams.IgnoreWater = true
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local function shoot()
for pellet=1, PELLETS do
local spreadX = HORIZONTAL_SPREAD.min + (math.random() * (HORIZONTAL_SPREAD.max - HORIZONTAL_SPREAD.min))
local spreadY = VERTICAL_SPREAD.min + (math.random() * (VERTICAL_SPREAD.max - VERTICAL_SPREAD.min))
local result = workspace:Raycast(
origin.Position,
origin.CFrame.LookVector + Vector3.new(spreadX, spreadY),
raycastParams
)
local tracer = Instance.new("Part")
tracer.Size = Vector3.new(0.1,0.1, origin.CFrame.LookVector)
tracer.Parent = workspace
tracer.CFrame = CFrame.lookAt(origin.Position, origin.Position, origin.CFrame.LookVector)
tracer.Anchored = true
tracer.Color = Color3.new(0.960784, 0.666667, 0.156863)
if result ~= nil then
print(result)
local enemy = result.Instance.Parent:FindFirstChild("Humanoid")
if enemy == game:GetService("Players"):GetPlayerFromCharacter(result.Instance.Parent) then continue end
enemy:TakeDamage(damage)
DamageGUIEvent:FireClient(player, damage, enemy)
end
end
end