So, I’ve been working on a shotgun for my game. The way it currently works is that it gets 8 “destinations” for each pellet, then loops through the Raycast calculations 8 times, each time with a different “destination”. This code works… except when a round starts.
When the round starts, the game loads in the map from serverStorage, sets up the location of certain objects, then kills every player and begins the round. During the round, the shotgun only repeats the Raycast loop once, instead of 8 times.
However, when the round ends and everything despawns, it starts working again! I’m not even getting any error messages; what gives?
Shotgun Server Script
-- Game Services
local players = game:GetService("Players")
local debris = game:GetService("Debris")
local souSe = game:GetService("SoundService")
local colSe = game:GetService("CollectionService")
local gunModule = require(game.ServerScriptService.serverGunModule)
-- Setup Variables
local tool = script.Parent
local barrel = tool.Handle.Barrel
local att0 = barrel.att0
local att1 = barrel.att1
local tracer = barrel.tracer
local bulletLocation = 0
local assistTable = {}
local headshot = false
local gunFireSFX = tool.shotgunSounds["Gun Fire"]:Clone()
gunFireSFX.Parent = tool.Handle.Barrel
-- Gameplay Variables
local DMG = 5
local spread = 3 -- in Degrees
local pellets = 8
-- On Shoot Event
tool.shotgunShoot.OnServerEvent:Connect(function(player, mousePosition)
print("Received Server Event")
local currentPellet = 0
local spreadValues = {} -- saves all the positions of the barrelLooks so it isn't constantly making 8 parts each time.
-- barrelLook: Basically, it recreates mousePosition - tool.Handle.Barrel.Position BUT with an actual rotation value I can edit
local barrelLook = Instance.new("Part")
barrelLook.Name = "barrelLook"
barrelLook.Size = Vector3.new(0.125, 0.125, 0.125)
barrelLook.CanCollide = false
barrelLook.CanTouch = false
barrelLook.CanQuery = false
barrelLook.Color = Color3.new(1, 0, 0)
-- First, the CFrame is changed to be the barrel's position, looking at the mouse. Then, if there is spread on the gun, adds an angle based on the spread to the rotation.
repeat
for i = 1, pellets do
barrelLook.CFrame = CFrame.lookAt(barrel.CFrame.Position, mousePosition) * CFrame.Angles(math.rad(math.random(-spread, spread)), math.rad(math.random(-spread, spread)), 0)
if table.find(spreadValues, barrelLook.CFrame.LookVector) == true then
print("Found Duplicate")
return
else
table.insert(spreadValues, barrelLook.CFrame.LookVector)
print("Added Value to Table")
end
end
until #spreadValues >= 8
barrelLook.Parent = tool.Handle
local barrelLookWeld = Instance.new("WeldConstraint")
barrelLookWeld.Part0 = tool.Handle
barrelLookWeld.Part1 = barrelLook
barrelLookWeld.Parent = tool.Handle
if tool.Handle:FindFirstChild("barrelLook") == false then
return
end
debris:AddItem(barrelLook, 0)
debris:AddItem(barrelLookWeld, 0)
-- Raycast Paramaters
local raycastParams = RaycastParams.new() -- colSe:GetTagged("leaves")
raycastParams.FilterDescendantsInstances = {player.Character, colSe:GetTagged("water"), colSe:GetTagged("mapBorder"),} -- Add all targets bullet should pass through here
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
-- Raycast Calculations
for i = 1, pellets do
currentPellet += 1
print(currentPellet)
print(spreadValues)
local chosenSpreadValue = spreadValues[math.random(1, #spreadValues)]
local cSVIndex = table.find(spreadValues, chosenSpreadValue)
print(cSVIndex, chosenSpreadValue)
local raycastResult = workspace:Raycast(tool.Handle.Barrel.Position, chosenSpreadValue * 300, raycastParams)
if raycastResult == nil then
bulletLocation = tool.Handle.Barrel.Position + chosenSpreadValue * 300
else
bulletLocation = raycastResult.Position
end
gunModule.makeTracer(bulletLocation, att0, att1, tracer, tool.Handle.Barrel.Position)
gunModule.makeMuzzleFlash(barrel)
print(bulletLocation)
gunFireSFX:Play()
if raycastResult then
local raycastInstance = raycastResult.Instance
local model = raycastInstance:FindFirstAncestorOfClass("Model")
if model then
local humanoid = model:FindFirstChild("Humanoid")
if humanoid == nil then
print("Humanoid not Found")
gunModule.bulletHoleSFX(raycastResult)
gunModule.makebulletHole(bulletLocation, raycastResult)
return
end
local humPlayer = players:GetPlayerFromCharacter(humanoid.Parent)
if humPlayer ~= nil and player.Team == humPlayer.Team then -- Or: if there IS a Player for the model AND that Player's team is equal to yours, return.
print("Hit Teammate!")
return
-- This makes it so NPCs can be damaged (they return "nil" for humPlayer, so cannot complete the if statement)
elseif raycastInstance.Name == "Head" then
gunModule.untagHumanoid(humanoid, assistTable)
gunModule.tagHumanoid(humanoid, player, assistTable)
humanoid:takeDamage(DMG*2)
print("Critical Hit!")
headshot = true
local humHP = humanoid.Health
tool.shotgunHitMarkers:FireClient(player, headshot, humHP)
else
gunModule.untagHumanoid(humanoid, assistTable)
gunModule.tagHumanoid(humanoid, player, assistTable) -- Extremely imporant to note: untagHumanoid and tagHumanoid NEED to pass through humanoid and player
humanoid:takeDamage(DMG)
print("Hit!")
headshot = false
local humHP = humanoid.Health
tool.shotgunHitMarkers:FireClient(player, headshot, humHP)
end
else
gunModule.bulletHoleSFX(raycastResult)
print(bulletLocation)
print(raycastResult)
gunModule.makebulletHole(bulletLocation, raycastResult)
end
end
table.remove(spreadValues, cSVIndex)
print("Loop Completed")
end
print("Finished Calculations")
end)
Map Loading/Unloading Script
local function loadMap()
for i,v in serverStorage.GSG_Map1:GetChildren() do
if v:IsA("Folder") then
for i2,v2 in v:GetChildren() do
local vC2 = v2:Clone()
vC2.Parent = workspace.currentMap
task.wait()
end
end
if v:IsA("Model") or v:IsA("UnionOperation") or v:IsA("Part") then
local vC = v:Clone()
vC.Parent = workspace.currentMap
task.wait()
end
end
for i,v in serverStorage.locations:GetChildren() do
local YCoord = 0.5
local vC = v:Clone() -- location
vC.Parent = workspace.currentLocations -- load it into the workspace
vC:PivotTo(CFrame.new(
locationCoordsX[math.random(1, #locationCoordsX)], -- choose one of the 4 quadrants
YCoord,
locationCoordsZ[math.random(1, #locationCoordsX)]
)
)
while table.find(locationNewPositions, vC:GetPivot()) do -- check if there's a building there, if there is, reroll the location
vC:PivotTo(CFrame.new(
locationCoordsX[math.random(1, #locationCoordsX)],
YCoord,
locationCoordsZ[math.random(1, #locationCoordsX)]
)
)
print("Re-Rolled")
task.wait()
end
table.insert(locationNewPositions, 1, vC:GetPivot()) -- add the location to list of places another location cannot spawn
print(vC:GetPivot())
print(locationNewPositions)
task.wait()
end
if game.Workspace.currentLocations:FindFirstChild("location_House") then
local house = game.Workspace.currentLocations:FindFirstChild("location_House")
house:PivotTo(CFrame.new(house:GetPivot().X, 0.375, house:GetPivot().Z))
end
for _, v in game.Workspace:GetDescendants() do
if v.Name == "leaves" then
collectionService:AddTag(v, "leaves")
end
end
end
local function intermission()
print("intermission")
for i, v in pairs(players:GetPlayers()) do
v.leaderstats.Kills.Value = 0
v.leaderstats.Assists.Value = 0
v.leaderstats.Deaths.Value = 0
end
if gameStarted == false then
currentTime = intermissionTime
repeat
currentTime -= 1
task.wait(1)
updateTimer:FireAllClients(currentTime)
print(currentTime)
until currentTime <= 0
end
end
local function gameRound()
print("gameRound")
loadMap()
for i, v in pairs(players:GetPlayers()) do
v.leaderstats.Kills.Value = 0
v.leaderstats.Assists.Value = 0
v.leaderstats.Deaths.Value = 0
v.Character:FindFirstChild("Humanoid").Health = 0
if v.Backpack:FindFirstChild("Pistol") == false then
local newPistol = game:GetService("StarterPack").Pistol:Clone()
newPistol.Parent = v.Backpack
end
end
task.wait(players.RespawnTime + 1)
gameStarted = true
if gameStarted == true then
currentTime = roundTime
repeat
currentTime -=1
task.wait(1)
updateTimer:FireAllClients(currentTime)
print(currentTime)
until currentTime <= 0
gameStarted = false
end
end
local function determineWinner()
print("determineWinner")
local redKills = 0
local blueKills = 0
local Victory = ""
for _, v in pairs(redTeam:GetPlayers()) do
local killstatRed = v.leaderstats.Kills
redKills += killstatRed.Value
end
for _, v in pairs(blueTeam:GetPlayers()) do
local killstatBlue = v.leaderstats.Kills
blueKills += killstatBlue.Value
end
if redKills > blueKills then
for _, v in pairs(redTeam:GetPlayers()) do
v.leaderstats.Wins += 1
Victory = "red"
declareVictory:FireAllClients(Victory)
end
elseif blueKills > redKills then
for _, v in pairs(blueTeam:GetPlayers()) do
v.leaderstats.Wins.Value += 1
Victory = "blue"
declareVictory:FireAllClients(Victory)
end
else
Victory = ""
declareVictory:FireAllClients(Victory)
end
redKills = 0
blueKills = 0
task.wait(5)
table.clear(locationNewPositions)
for _, v in game.Workspace.currentMap:GetChildren() do
v:Destroy()
end
for _, v in game.Workspace.currentLocations:GetChildren() do
v:Destroy()
end
for i, v in pairs(players:GetPlayers()) do
v.Character:FindFirstChild("Humanoid").Health = 0
end
end
local function roundLoop()
while true do
intermission()
gameRound()
determineWinner()
end
end
Video of what’s going on: