Hey guys, I’m new to roblox studio and new to lua, and I really need help with this. So what I’m trying to do is make a script that makes a fireball (or waterball etc etc), sends it to the server, and then fires the ball. The script nearly works fine, but for some reason, at random instances, when the character is walking while firing the attack, the ball just decides to stop and stay in front of the character. I thought it might be the simple fact that another key was being pressed at the same time at first, and tried to fix that, but that wasn’t the problem, as this issue only occurs if it’s one of the movement keys I’m holding down when it’s fired. I also thought the character could possibly be touching the ball before it launches and is causing some reaction, but then I realized that wasn’t the case because I have my script set up so that the character using the skill and the skill object can not touch each other. I now think that the way I’m handling the ball’s position and velocity is causing it to reset when the player is moving, but I can’t seem to find the issue.
Video link because the file was too large:
Here’s the server script:
local UIS = game:GetService("UserInputService")
local RS = game:GetService("ReplicatedStorage")
local debris = game:GetService("Debris")
local TS = game:GetService("TweenService")
local SS = game:GetService("ServerStorage")
local fxFolder = workspace.Fx
local spawnBlocks = workspace.SpawnBlocks
local fireballEvent = RS.SkillRemoteEvents.FireballEvent
local chargeAttack = RS.SkillRemoteEvents.ChargeAttack
local makeBall = RS.Fx.ballAttacks.makeBall
--ALL FUNCTIONS START HERE------------------------------------------------------------------------------------------------------------------------------
local function receiveAttack(hit, attacker, damageBase, charge, resistanceIncrease, firePower)
--CODE IN THIS FUNCTION IS IRRELEVANT
end
local function beFireball(hit, player, fireball, current, charge, firePower)
--CODE IN THIS FUNCTION IS IRRELEVANT
end
local function createBall(player, current, skill)
if RS.ToolsForSkills:FindFirstChild(skill) ~= nil then
player:WaitForChild("leaderstats"):WaitForChild("Skills"):FindFirstChild(skill):SetAttribute("LastUsed", 0)
local attack = RS.ToolsForSkills:FindFirstChild(skill):Clone()
attack.Name = player.Name..skill..current
attack.Parent = RS.ToolsForSkills
local newForce = Instance.new("BodyForce")
newForce.Force = Vector3.new(0, workspace.Gravity * attack:GetMass(), 0)
newForce.Parent = attack
end
end
local function chargeSkill(player, charge, current, skill)
local attack
if RS.ToolsForSkills:FindFirstChild(player.Name..skill..current) ~= nil then
attack = RS.ToolsForSkills:FindFirstChild(player.Name..skill..current)
attack.Parent = workspace.Map:FindFirstChild(player.Name.."CurrentProjectiles")
else
attack = workspace.Map:FindFirstChild(player.Name.."CurrentProjectiles"):FindFirstChild(player.Name..skill..current)
end
attack.Position = player.Character.HumanoidRootPart.Position + player.Character.HumanoidRootPart.CFrame.LookVector * 5
local chargeFx = SS.Fx:FindFirstChild("chargeDisperse"..skill):Clone()
chargeFx.Color = ColorSequence.new(attack.Color)
chargeFx.Parent = attack.Attachment
if charge > 1.5 then
attack.ParticleEmitter.Enabled = true
attack.ParticleEmitter.Rate = 50 * charge
end
if charge > 2 then
chargeFx.Enabled = true
end
if charge >= 2.5 then
chargeFx.Rate = 100
end
print("I REPEAT! Charge is "..charge)
end
local function fireAttack(player, MousePosition, current, charge, skill, attackName, velocity)
local attack = workspace.Map:FindFirstChild(player.Name.."CurrentProjectiles"):FindFirstChild(player.Name..skill..current)
if charge == 1 then
attack.Parent = workspace.Map:FindFirstChild(player.Name.."CurrentProjectiles")
end
if attack:GetAttribute(player.Name..attack.Name) == nil then
attack:SetAttribute(player.Name..attack.Name, "Exists")
local attackElement = player.leaderstats.Skills:FindFirstChild(skill):GetAttribute("Element")
local firePower = player.leaderstats.Stats:FindFirstChild(attackElement.." Power")
local level = player.leaderstats.Stats:FindFirstChild("Level")
local levelEXP = level:GetAttribute("CurrentEXP")
local requiredLevelEXP = level:GetAttribute("RequiredEXP")
local remainingLevelEXP = level:GetAttribute("RemainingEXP")
local fireballLevel = player.leaderstats.Skills:FindFirstChild(skill)
local fireballLevelEXP = fireballLevel:GetAttribute("CurrentEXP")
local fireballRequiredLevelEXP = fireballLevel:GetAttribute("RequiredEXP")
local fireballRemainingLevelEXP = fireballLevel:GetAttribute("RemainingEXP")
firePower.Value += math.round(1 * charge)
if math.round(1 * charge) > requiredLevelEXP - levelEXP then
local obtainedEXP = requiredLevelEXP - levelEXP
local leftoverEXP = math.round(1 * charge) - (requiredLevelEXP - levelEXP)
local nextCurrentEXP = levelEXP + obtainedEXP
level:SetAttribute("CurrentEXP", nextCurrentEXP)
level:SetAttribute("RemainingEXP", leftoverEXP)
else
local nextCurrentEXP = levelEXP + math.round(1 * charge)
level:SetAttribute("CurrentEXP", nextCurrentEXP)
end
if math.round(1 * charge) > fireballRequiredLevelEXP - fireballLevelEXP then
local obtainedEXP = fireballRequiredLevelEXP - fireballLevelEXP
local leftoverEXP = math.round(1 * charge) - (fireballRequiredLevelEXP - fireballLevelEXP)
local nextCurrentEXP = fireballLevelEXP + obtainedEXP
fireballLevel:SetAttribute("CurrentEXP", nextCurrentEXP)
fireballLevel:SetAttribute("RemainingEXP", leftoverEXP)
else
local nextCurrentEXP = fireballLevelEXP + math.round(1 * charge)
fireballLevel:SetAttribute("CurrentEXP", nextCurrentEXP)
end
attack.Anchored = false
attack.Velocity *= 100
print("Ball should be moving")
attack.Touched:Connect(function(hit)
if not hit:IsDescendantOf(workspace:FindFirstChild(player.Name)) and not hit:IsDescendantOf(workspace.SimpleRings) and not hit:IsDescendantOf(fxFolder) and not hit:IsDescendantOf(spawnBlocks)then
if hit:IsDescendantOf(workspace.Map) or hit.Parent:FindFirstChild("Humanoid") then
beFireball(hit, player, attack, current, charge, firePower)
attack:Destroy()
current -= 1
print("THE PARENT OF WHAT WAS HIT IS "..hit.Name)
if hit.Parent:FindFirstChild("Humanoid") then
local resistanceIncrease = math.round(1 * charge)
receiveAttack(hit, player, 25, charge, resistanceIncrease, firePower.Value)
end
end
end
end)
end
end
--ALL FUNCTIONS END HERE--------------------------------------------------------------------------------------------------------------------------------
makeBall.OnServerEvent:Connect(function(player, current, skill)
createBall(player, current, skill)
end)
chargeAttack.OnServerEvent:Connect(function(player, charge, current, skill)
chargeSkill(player, charge, current, skill)
end)
fireballEvent.OnServerEvent:Connect(function(player, MousePosition, current, charge, skill)
fireAttack(player, MousePosition, current, charge, skill)
end)
And here’s the local script:
local current = 0
while true do
local UIS = game:GetService("UserInputService")
local RS = game:GetService("ReplicatedStorage")
local debris = game:GetService("Debris")
local TS = game:GetService("TweenService")
local player = game.Players.LocalPlayer
local character = player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local HRP = character:WaitForChild("HumanoidRootPart")
local currentProjectiles = workspace.Map:WaitForChild(player.Name.."CurrentProjectiles"):GetChildren()
local makeBall = RS.Fx.ballAttacks.makeBall
local fireballEvent = RS.SkillRemoteEvents.FireballEvent
local chargeAttack = RS.SkillRemoteEvents.ChargeAttack
local mouse = player:GetMouse()
local key
local keyUnpressed
local debounce = false
local charging = false
local cooldown = 3
local charge = 1
local movementKeys = {"W", "A", "S", "D"}
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Include -- Same as saying Enum.RaycastFilterType.Whitelist
params.FilterDescendantsInstances = {workspace.Map}
local function rip()
humanoid = character:WaitForChild("Humanoid")
local lastAttacker = humanoid:GetAttribute("LastAttacker")
local lastAttackerHumanoid
if lastAttacker ~= "None" then
lastAttackerHumanoid = workspace:WaitForChild(lastAttacker):WaitForChild("Humanoid")
end
makeBall = RS.Fx.ballAttacks.makeBall
fireballEvent = RS.SkillRemoteEvents.FireballEvent
chargeAttack = RS.SkillRemoteEvents.ChargeAttack
--current = 0
charge = 1
mouse = player:GetMouse()
debounce = false
if lastAttackerHumanoid ~= nil then
print(humanoid.Parent.Name.." has died. The one who dealt the final blow was "..lastAttackerHumanoid.Parent.Name)
end
if charging == true then
charging = false
end
humanoid = nil
return
end
local function createAttack(input, gpe)
local humanoid = workspace:FindFirstChild(player.Name):FindFirstChild("Humanoid")
local keyPressed = input.KeyCode
if keyPressed ~= nil and player.KeyBinds:FindFirstChild(input.KeyCode) ~= nil then
if humanoid:GetAttribute("UsingSkill") == nil or humanoid:GetAttribute("UsingSkill") == false then
local skill = player.KeyBinds:FindFirstChild(input.KeyCode).Value
if skill ~= nil and skill ~= "None" and skill ~= "" then
local lastUsed = player:WaitForChild("leaderstats"):WaitForChild("Skills"):FindFirstChild(skill):GetAttribute("LastUsed")
local reloadTime = player:WaitForChild("leaderstats"):WaitForChild("Skills"):FindFirstChild(skill):GetAttribute("ReloadTime")
if lastUsed > reloadTime then
print("IT HAS A SKILL ASSIGNED!!! LAUNCHING")
humanoid:SetAttribute("UsingSkill", true)
if humanoid ~= nil then
debounce = true
local secondDebounce = false
local thirdDebounce = false
charging = true
humanoid.WalkSpeed = 0
if not secondDebounce then
secondDebounce = true
print("WE ARE MAKING THE BALL!!!")
current += 1
makeBall:FireServer(current, skill)
end
local attack = RS.ToolsForSkills:WaitForChild(player.Name..skill..current)
attack.Position = player.Character.HumanoidRootPart.Position + player.Character.HumanoidRootPart.CFrame.LookVector * 5
attack.Velocity = CFrame.new(attack.Position, mouse.Hit.p).LookVector
attack.Anchored = true
if player.Character:FindFirstChild("Humanoid"):GetState() == Enum.HumanoidStateType.Freefall then
charging = false
end
repeat
wait(0.1)
if charge + 0.03 > 2.5 then
charge = 2.5
else
charge += 0.03
end
print("Charging is at "..charge.."For the attack "..attack.Name)
attack.Position = player.Character.HumanoidRootPart.Position + player.Character.HumanoidRootPart.CFrame.LookVector * 5
attack.Velocity = CFrame.new(attack.Position, mouse.Hit.p).LookVector
chargeAttack:FireServer(charge, current, skill)
until charging == false or humanoid.Health <= 0
if not thirdDebounce then
print("ADDING ALL THE EXP AND THAT OTHER GOOD STUFF")
thirdDebounce = true
attack.Anchored = false
attack.Velocity *= 100
fireballEvent:FireServer(mouse.Hit.p, current, charge, skill, player.Name..skill..current)
charge = 1
end
wait(0.3)
humanoid.WalkSpeed = 16
end
task.wait(cooldown)
charge = 1.0
debounce = false
print("Debounce is false")
end
end
end
end
end
local function releaseAttack(input, gpe, key)
local humanoid = workspace:FindFirstChild(player.Name):FindFirstChild("Humanoid")
local keyReleased = input.KeyCode
if keyReleased == key and not gpe and charge > 1.03 then
charging = false
print("Attack Launched!!!")
humanoid:SetAttribute("UsingSkill", false)
end
end
player.Character.Humanoid.Died:Connect(function()
rip()
end)
UIS.InputBegan:Connect(function(input, gpe)
local keyPressed = input.KeyCode
if keyPressed ~= nil and player.KeyBinds:FindFirstChild(input.KeyCode) ~= nil then
key = input.KeyCode
createAttack(input, gpe)
end
end)
UIS.InputEnded:Connect(function(input, gpe)
while charge <= 1.03 do
wait()
end
releaseAttack(input, gpe, key)
end)
end
Now as stated previously, I’m very new to programming on lua, as well as roblox studios. So if you also see any bad practices or inconsistencies in the process of helping me then please by all means point them out and help me improve. I’m going to try again to get the video to load, it was not loading at first. If it doesn’t load I will probably link it.