With what I am not satisfied?
Hello! So I am making rpg game which is about a bullet hell game which means there will be a lot of projectiles different types. I have been figuring out how to make good projectiles for a year. And I think im pretty close enough to it! However the reason why I want you to review my code is because projectiles made on the client side. I have been trying it do on server side but it would be too laggy if there would be a lot of knives. I want to know how I can try to make it on server side.
What my code does?
My code uses a module to create projectile on client side. Client side have a caster argument which contains 1 which is max. It depends on the player, if player is the creator projectile then caster will be equal to 1, however if not then it gonna contain ANYTHING expect 1 because there no really any sense at it. It detects hit on both casters, but damage does only on caster which equals to 1. one of the reasons why I want make it on server side - damages goes through remote event
.
Code
COMBAT MODULE
local module = {}
function module:CreateHitbox(CFrame: CFrame, Size: Vector3, Params: OverlapParams, Visual: BoolValue)
end
function module:CreateProjectile(Character: Model, Projectile: StringValue, ProjectileCFrame: CFrame, Speed: NumberValue, Debris :NumberValue)
local overparams = OverlapParams.new()
overparams.FilterDescendantsInstances = {workspace.EffectsFolder}
overparams.FilterType = Enum.RaycastFilterType.Blacklist
game.ReplicatedStorage.Events.Projectile_Events[Projectile]:FireClient(game.Players[Character.Name],Character,ProjectileCFrame,Speed,Debris,1)
local ProjectileCreateHitbox = game.Workspace:GetPartBoundsInRadius(ProjectileCFrame.Position,100,overparams)
for index, hit in pairs(ProjectileCreateHitbox) do
if hit.Name == "HumanoidRootPart" then
if game.Players:GetPlayerFromCharacter(hit.Parent) and hit.Parent.Name ~= Character.Name then
game.ReplicatedStorage.Events.Projectile_Events[Projectile]:FireClient(game.Players:GetPlayerFromCharacter(hit.Parent),Character,ProjectileCFrame,Speed,Debris)
end
end
end
end
function module:CreateProjectileClientSide(character,projectile,cframe,speed,debris,dmg,caster)
local timeStopped = false
local DebrisTime = 0
while game:GetService("RunService").Heartbeat:Wait() do
if game.ReplicatedStorage.TimeStop.Value == false then
local oldPos = projectile.CFrame
local newPos = projectile.CFrame * CFrame.new(0,0,-speed)
local posDifference = (oldPos.Position-newPos.Position).Magnitude
local params = RaycastParams.new()
params.FilterDescendantsInstances = {character,workspace.EffectsFolder}
local ray = workspace:Raycast(oldPos.Position,oldPos.lookVector*posDifference,params)
DebrisTime += .1
if DebrisTime >= debris then
projectile:Destroy()
print("death")
break
end
if ray then
local lookVector = projectile.CFrame.LookVector
print(projectile.Name.."has hitted "..ray.Instance.Name.."!")
projectile.CFrame = CFrame.new(projectile.CFrame.Position,ray.Position)*CFrame.new(0,0,-ray.Distance/2)
if caster == 1 then
if ray.Instance.Parent:FindFirstChild("Humanoid") then
warn("Target has a humanoid, damaging.")
game.ReplicatedStorage.Events.DamageEvent:FireServer(ray.Instance.Parent,dmg)
end
end
game.Debris:AddItem(projectile,2)
break
else
projectile.CFrame = projectile.CFrame * CFrame.new(0,0,-speed)
end
else
warn(projectile.Name.." has been frozen. Reason: Time Stop.")
timeStopped = true
break
end
end
if timeStopped == true then
local changedConnection
changedConnection = game.ReplicatedStorage.TimeStop.Changed:Connect(function()
changedConnection:Disconnect()
local projectileCFrame = projectile.CFrame
module:CreateProjectileClientSide(character,projectile,projectileCFrame,speed,debris,dmg,caster)
end)
end
end
return module
SERVER SIDE SCRIPT
local cmod = require(game.ReplicatedStorage.Modules.CombatModule)
game.ReplicatedStorage.Events.SpellCardEvents.Sakuya.KillingDollEvent.OnServerEvent:Connect(function(player,status,mousePos,angle)
if status == "Message" then
game.ReplicatedStorage.Events.VFX_Events.SignEvent:FireAllClients(player.Character.HumanoidRootPart,"Sakuya",2)
local s = script.UseSound:Clone()
s.Parent = player.Character.HumanoidRootPart
s:Play()
game.Debris:AddItem(s,2)
local params = OverlapParams.new()
params.FilterDescendantsInstances = {workspace.EffectsFolder}
params.FilterType = Enum.RaycastFilterType.Blacklist
local hit = game.Workspace:GetPartBoundsInRadius(player.Character.HumanoidRootPart.CFrame.Position,50,params)
for i,v in pairs(hit) do
if v.Name == "HumanoidRootPart" then
if game.Players:GetPlayerFromCharacter(v.Parent) then
game.ReplicatedStorage.Events.VFX_Events.SpellcardMessage:FireClient(game.Players:GetPlayerFromCharacter(v.Parent),'Illusion Sign "Killing Doll"',Color3.new(1,0,0))
end
end
end
else
local char = player.Character
local hum = char.Humanoid
local hrp = char.HumanoidRootPart
local ProjectileCFrame = hrp.CFrame
wait()
ProjectileCFrame = hrp.CFrame*CFrame.fromEulerAnglesXYZ(0,math.rad(angle),0)*CFrame.new(0,0,-5)
ProjectileCFrame = CFrame.new(ProjectileCFrame.Position,mousePos)
angle += 30
local ray = Ray.new(ProjectileCFrame.Position,mousePos)
local hit,pos = workspace:FindPartOnRay(ray,hrp)
wait(.75)
cmod:CreateProjectile(char,"SakuyaBlueKnife",ProjectileCFrame,2,10)
end
end)
game.ReplicatedStorage.Events.SpellCardEvents.Sakuya.TimestopEvent.OnServerEvent:Connect(function(player)
if game.ReplicatedStorage.TimeStop.Value == false then
game.ReplicatedStorage.Events.VFX_Events.SignEvent:FireAllClients(player.Character.HumanoidRootPart,"Sakuya",2)
local s = script.UseSound:Clone()
s.Parent = player.Character.HumanoidRootPart
s:Play()
game.Debris:AddItem(s,2)
local params = OverlapParams.new()
params.FilterDescendantsInstances = {workspace.EffectsFolder}
params.FilterType = Enum.RaycastFilterType.Blacklist
local hit = game.Workspace:GetPartBoundsInRadius(player.Character.HumanoidRootPart.CFrame.Position,50,params)
for i,v in pairs(hit) do
if v.Name == "HumanoidRootPart" then
if game.Players:GetPlayerFromCharacter(v.Parent) then
game.ReplicatedStorage.Events.VFX_Events.SpellcardMessage:FireClient(game.Players:GetPlayerFromCharacter(v.Parent),'Illusion World "'..player.Name.."'s World"..'"',Color3.new(1,0,0))
end
end
end
wait(1)
end
game.ReplicatedStorage.TimeStop.Value = not game.ReplicatedStorage.TimeStop.Value
game.Lighting.ColorCorrection.Enabled = game.ReplicatedStorage.TimeStop.Value
end)
CLIENT SIDE SCRIPT
local ProjectileEvents = game.ReplicatedStorage.Events.Projectile_Events
local cmod = require(game.ReplicatedStorage.Modules.CombatModule)
local player = game.Players.LocalPlayer
local dmg = 2
ProjectileEvents.SakuyaBlueKnife.OnClientEvent:Connect(function(character,cframe,speed,debris,caster)
local timeStopped = false
local DebrisTime = 0
local knife = game.ReplicatedStorage.Assets.Sakuya.SakuyaBlueKnife:Clone()
knife.MainTrail.Enabled = true
knife.CFrame = cframe
knife.Parent = workspace.EffectsFolder
cmod:CreateProjectileClientSide(character,knife,cframe,speed,debris,dmg,caster)
end)
CODE DEMONSTRATION
Normal projectiles
Projectiles created while time stop
*Projectiles that has been time stopped
LAG TEST
That’s a client side. Imagine if this would be on server side.