Hello, I’m working on a spell system for myself, with no end. I’ve been working on the module for some time, and I still have a problem that I couldn’t fix.
There are several spells and functions customized to work correctly, and everything seems to work normally, but you may notice some flaws right after using it for some time. For each spell, there is a specific type of cooldown, and some players selected by me have no cooldown, so they have the ability to spam/cast the spells as many times as they want.
I use a RemoteEvent to send information to the server like mouse position and other features. I even use some checkers to check if they have the spell before executing the spell function.
If you have a cooldown on spells, you can use spells normally without any problem, but when those without cooldown use a spell, for example, 100 times per second, there are many effects and other characteristics created, and the movement of these spells ends up getting very slow. I have seen several games with the same features, but none of this happens. I would like to know what I possibly am doing wrong to remove this problem and make my spells move normally regardless of the number of spells being casted at once.
Check my SpellBase function which creates the effects between spells:
function Events.SpellBase(MousePos, Tool, Sound2, SpellColors, F, Name, Self, IsSpellbolt)
local Character = Tool.Parent
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local WandTip = Tool:WaitForChild("WandTip") -- Where the spell beam will come from
local Player = Players:GetPlayerFromCharacter(Character)
local Head = Character:WaitForChild("Head")
local NametagColor = Head:FindFirstChild("Nametag"):FindFirstChild("Frame"):FindFirstChild("Name").TextColor3 or Color3.new(1, 1, 1) -- May be used for spellbolts color
local IsRainbow = false -- Custom rainbow color for spells
if Player ~= nil then
if Player.UserId == 646638413 then
IsRainbow = true
elseif Player.UserId == 105137002 then
IsRainbow = true
end
end
local SpellPart = Instance.new("Part")
local SpellDuration = tick() -- Current time upon being casted
local SpellTime = 10 -- Max time before being destroyed
if IsSpellbolt == false or not IsSpellbolt then -- THIS WILL APPLY ALL THE FFECTS
if Name == "Aguamenti" or Name == "Incendio" or Name == "Glacius" then
local SpellParticle = ParticleSpellPart.ParticleTrail:Clone()
SpellParticle.Color = ColorSequence.new(SpellColors[1])
SpellParticle.Parent = SpellPart
elseif Name == "Periculum" or Name == "Morsmordre" then
local Left1 = BasicSpellPart.Left1:Clone()
local Left2 = BasicSpellPart.Left2:Clone()
local MovementScript = BasicSpellPart.Movement:Clone()
local Right1 = BasicSpellPart.Right1:Clone()
local Right2 = BasicSpellPart.Right2:Clone()
local TrailThin = BasicSpellPart.TrailThin:Clone()
local TrailWide = BasicSpellPart.TrailWide:Clone()
Left1.Parent = SpellPart
Left2.Parent = SpellPart
MovementScript.Disabled = false
MovementScript.Parent = SpellPart
Right1.Parent = SpellPart
Right2.Parent = SpellPart
TrailWide.Color = ColorSequence.new(SpellColors[1])
TrailThin.Color = ColorSequence.new(SpellColors[2])
TrailWide.Attachment0 = Left1
TrailWide.Attachment1 = Right1
TrailWide.Parent = SpellPart
TrailThin.Attachment0 = Left2
TrailThin.Attachment1 = Right2
TrailThin.Parent = SpellPart
elseif Name == "Incarcerous" then
local Left1 = BasicSpellPart.Left1:Clone()
local MovementScript = BasicSpellPart.Movement:Clone()
local Right1 = BasicSpellPart.Right1:Clone()
local TrailThin = BasicSpellPart.TrailThin:Clone()
Left1.Parent = SpellPart
MovementScript.Disabled = false
MovementScript.Parent = SpellPart
Right1.Parent = SpellPart
TrailThin.Color = ColorSequence.new(SpellColors[1])
TrailThin.Attachment0 = Left1
TrailThin.Attachment1 = Right1
TrailThin.Parent = SpellPart
else
local Left1 = BasicSpellPart.Left1:Clone()
local Left2 = BasicSpellPart.Left2:Clone()
local MovementScript = BasicSpellPart.Movement:Clone()
local Right1 = BasicSpellPart.Right1:Clone()
local Right2 = BasicSpellPart.Right2:Clone()
local TrailThin = BasicSpellPart.TrailThin:Clone()
local TrailWide = BasicSpellPart.TrailWide:Clone()
Left1.Parent = SpellPart
Left2.Parent = SpellPart
MovementScript.Disabled = false
MovementScript.Parent = SpellPart
Right1.Parent = SpellPart
Right2.Parent = SpellPart
TrailWide.Color = ColorSequence.new(SpellColors[1])
TrailThin.Color = ColorSequence.new(SpellColors[2])
TrailWide.Attachment0 = Left1
TrailWide.Attachment1 = Right1
TrailWide.Parent = SpellPart
TrailThin.Attachment0 = Left2
TrailThin.Attachment1 = Right2
TrailThin.Parent = SpellPart
end
elseif IsSpellbolt == true then
local Left1 = BoltSpellPart.Left1:Clone()
local Left2 = BoltSpellPart.Left2:Clone()
local ParticleTrail = BoltSpellPart.ParticleTrail:Clone()
local Right1 = BoltSpellPart.Right1:Clone()
local Right2 = BoltSpellPart.Right2:Clone()
local TrailThin = BoltSpellPart.TrailThin:Clone()
local TrailWide = BoltSpellPart.TrailWide:Clone()
local BoltColor = Color3.new(NametagColor.r, NametagColor.g, NametagColor.b)
if IsRainbow == true then
BoltColor = Color3.new(math.random(), math.random(), math.random())
end
local ColorTable = {
BoltColor.r,
BoltColor.g,
BoltColor.b
}
if ColorTable[1] <= 0.1 and ColorTable[2] <= 0.1 and ColorTable[3] <= 0.1 then
ColorTable[1] = 0.1
ColorTable[2] = 0.1
ColorTable[3] = 0.1
end
Left1.Parent = SpellPart
Left2.Parent = SpellPart
ParticleTrail.Color = ColorSequence.new(Color3.new(ColorTable[1], ColorTable[2], ColorTable[3]))
ParticleTrail.Parent = SpellPart
Right1.Parent = SpellPart
Right2.Parent = SpellPart
TrailWide.Color = ColorSequence.new(Color3.new(ColorTable[1], ColorTable[2], ColorTable[3]))
TrailThin.Color = ColorSequence.new(Color3.new(ColorTable[1], ColorTable[2], ColorTable[3]))
TrailWide.Attachment0 = Left1
TrailWide.Attachment1 = Right1
TrailWide.Parent = SpellPart
TrailThin.Attachment0 = Left2
TrailThin.Attachment1 = Right2
TrailThin.Parent = SpellPart
end
SpellPart.Massless = false
IgnoredItems.AddToIgnoreList(SpellPart) -- Ignore list for raycasting
SpellPart.Parent = Workspace
if Self == true then -- Checks if they're using a spell on themselves
SpellPart.CFrame = WandTip.CFrame:ToWorldSpace(CFrame.new(-1.5, 0, 0))
elseif Self == false or not Self then
SpellPart.CFrame = WandTip.CFrame
end
SpellPart.CFrame = CFrame.new(SpellPart.CFrame.p, MousePos) -- Set its CFrame
SpellPart.Name = "Spell"
local Angle = (MousePos - SpellPart.CFrame.p).Unit
SpellPart.Size = Vector3.new(1, 1, 1)
SpellPart.Material = Enum.Material.Plastic
SpellPart.Transparency = 1
SpellPart.CanCollide = false
SpellPart.Anchored = true
local Creator = Instance.new("ObjectValue", SpellPart)
Creator.Value = Player
Creator.Name = "Creator"
local IsSpell = Instance.new("BoolValue", SpellPart)
IsSpell.Name = "IsSpell"
IsSpell.Value = true
local Collided = Instance.new("BoolValue", SpellPart)
Collided.Value = false
Collided.Name = "Collided"
local SpellName = Instance.new("StringValue", SpellPart)
SpellName.Value = Name
SpellName.Name = "SpellName"
if IsSpellbolt == true then -- Checker
Self = nil
end
SpellPart.Color = SpellColors[1]
local WandPower = (5 * 1.35) / 1.15
if Player ~= nil then
WandPower = (5 * _G.PlayerData[Player.UserId]["WandStatsData"]["Power"]) / 1.45
end -- WandPower calculates their spell speed (I already tested and it's fine)
local Connection -- Movement Function
Connection = RunService.Stepped:Connect(function()
if not SpellPart then
Connection:Disconnect()
end
local SpellRay = Ray.new(SpellPart.Position, SpellPart.CFrame.LookVector * 5)
local Hit,Position = Workspace:FindPartOnRayWithIgnoreList(SpellRay, IgnoredItems.GetIgnoredParts())
EXPLOSION_POSITIONS[SpellPart] = Position -- Upon being hit, the collision effect will be placed at this position (works v well)
if SpellPart.Name == "BouncedSpell" then
SpellPart.CFrame = SpellPart.CFrame - SpellPart.CFrame.LookVector * 5
else
SpellPart.CFrame = SpellPart.CFrame + SpellPart.CFrame.LookVector * WandPower
end
if math.ceil(tick() - SpellDuration) >= SpellTime then -- Checks if the spell can be destroyed already
for _, v in pairs(SpellPart:GetDescendants()) do
if v:IsA("Trail") then
v.Enabled = false
elseif v:IsA("ParticleEmitter") then
v.Enabled = false
end
end
Events.AddToDebrisService(SpellPart, 2)
Connection:Disconnect()
end
if Hit then
if Self == false or not Self then
if Hit:IsDescendantOf(Character) then
return
end
end
if Events.FindShieldReflector(Hit) then
SpellPart.Name = "BouncedSpell"
return
end
if IsSpellbolt == true then
Events.SpellboltDetection(SpellPart, Tool, Position, Hit, IsSpellbolt, SpellName, F, Sound2, false)
elseif Self == false or not Self then
Events.CollisionDetection(SpellPart, Tool, Position, Hit, IsSpellbolt, F, Sound2, false, SpellName.Value)
elseif Self == true then
Events.CollisionDetection(SpellPart, Tool, Position, Hit, IsSpellbolt, F, Sound2, true, SpellName.Value)
end -- These are the collision functions (works v well also)
Connection:Disconnect()
end
end)
SpellPart.Changed:Connect(function(Property)
if Property == "Parent" then
IgnoredItems.RemoveIgnoredPart(SpellPart)
IgnoredItems.RemoveIgnoredPart(Character)
if Connection ~= nil then
Connection:Disconnect()
end
end
end)
return SpellPart -- Returns the spell to the function that called it (won't change anything tho)
end