for some reason i cant attach a video but i tested creating bullets with remote events and they are quite laggy.
Cool! Code?
local function ReturnDecimal(range)
return Random.new():NextNumber(-range, range)
end
local function Lerp(a, b, t)
return a + (b - a) * t
end
game.ReplicatedStorage.RemoteEvents.CreateBullet.OnServerEvent:Connect(function(Player, Properties)
local Bullet = Instance.new("Part")
for k, v in pairs(Properties) do
if typeof(v) == "table" then
for l, q in pairs(v) do
Bullet:SetAttribute(k.. "_".. l, q)
end
elseif typeof(v) ~= "function" and typeof(v) ~= "Instance" and k ~= "Speed" and k ~= "Direction" and k ~= "Origin" and k ~= "Lifetime" then
Bullet:SetAttribute(k, v)
end
end
Bullet:SetAttribute("ID", tostring(math.random(1, 10^8)))
Bullet:SetAttribute("TimesRicocheted", 0)
Bullet:SetAttribute("EnemiesHit", 0)
Bullet:SetAttribute("BulletVelocity", Vector3.new(Properties.Direction.X + ReturnDecimal(Bullet:GetAttribute("MaxInaccuracy")), Properties.Direction.Y + ReturnDecimal(Bullet:GetAttribute("MaxInaccuracy")), Properties.Direction.Z + ReturnDecimal(Bullet:GetAttribute("MaxInaccuracy"))) * Properties.Speed)
Bullet.Name = (Properties.Name and true or "Bullet").. Bullet:GetAttribute("ID")
Bullet.Size = Properties.Size or Vector3.new(0.75, 0.75, 0.75)
Bullet.Color = Properties.Color or Color3.new(0, 0, 0)
Bullet.Material = Properties.Material or Enum.Material.SmoothPlastic
Bullet.CFrame = Properties.Origin
Bullet.CollisionGroup = "Extra"
Bullet:AddTag("Bullet")
Bullet:AddTag(Properties.ExtraType)
Bullet.CastShadow = false
Bullet.AssemblyLinearVelocity = Bullet:GetAttribute("BulletVelocity")
Bullet.Parent = workspace
local BulletHitByHitscanEvent = Instance.new("BindableEvent")
BulletHitByHitscanEvent.Name = "BulletHitByHitscanEvent"
BulletHitByHitscanEvent.Parent = Bullet
local BulletHitByBulletEvent = Instance.new("BindableEvent")
BulletHitByBulletEvent.Name = "BulletHitByBulletEvent"
BulletHitByBulletEvent.Parent = Bullet
local BulletShooter = Instance.new("ObjectValue")
BulletShooter.Parent = Bullet
BulletShooter.Value = Properties.Shooter
BulletShooter.Name = "Shooter"
BulletHitByBulletEvent.Event:Connect(function()
Properties.BulletHitByBulletFunction(Bullet, Properties)
end)
BulletHitByHitscanEvent.Event:Connect(function()
Properties.BulletHitByHitscanFunction(Bullet, Properties)
end)
local RaycastParameters = RaycastParams.new()
RaycastParameters.RespectCanCollide = true
RaycastParameters.FilterDescendantsInstances = {Bullet.Shooter.Value}
local Loop = game:GetService("RunService").Heartbeat:Connect(function()
local Blockcast = workspace:Blockcast(Bullet.CFrame, Bullet.Size, Bullet.AssemblyLinearVelocity.Unit * 4)
Movement(Blockcast, Bullet, Player)
Damage(Blockcast, Bullet)
end)
Bullet.Destroying:Connect(function()
local EffectProperties = {
EffectType = Bullet:GetAttribute("EffectProperties_EffectType"),
OutColor = Bullet:GetAttribute("EffectProperties_OutColor"),
InColor = Bullet:GetAttribute("EffectProperties_InColor"),
Size = Bullet:GetAttribute("EffectProperties_Size"),
Damage = Bullet:GetAttribute("EffectProperties_Damage"),
Position = Bullet.Position,
}
game.ReplicatedStorage.RemoteEvents.MakeEffect:Fire(EffectProperties)
Loop:Disconnect()
end)
return Bullet
end)
local function SelectTarget(ObjectToSearch, Bullet, Shooter)
local NearestObject = nil
for i, v in pairs(game.CollectionService:GetTagged(ObjectToSearch)) do
local RaycastParameters = RaycastParams.new()
RaycastParameters.RespectCanCollide = true
if NearestObject == nil or (v:IsA("Part") and (v.Position - Bullet.Position).Magnitude < (NearestObject.Position - Bullet.Position).Magnitude) or
(v:IsA("Model") and v ~= Shooter and (v.PrimaryPart.Position - Bullet.Position).Magnitude < (NearestObject.Position - Bullet.Position).Magnitude) then
NearestObject = v
end
end
return NearestObject
end
local function HandleRicocheting(RicochetRay, Bullet)
if RicochetRay and RicochetRay.Instance and not RicochetRay.Instance:HasTag("EffectPart") then
if not RicochetRay.Instance.Parent:FindFirstChildOfClass("Humanoid") and Bullet:GetAttribute("TimesRicocheted") < Bullet:GetAttribute("Ricochet_MaxRicochets") and not Bullet:HasTag("HeldByMagnet") then
Bullet:SetAttribute("TimesRicocheted", Bullet:GetAttribute("TimesRicocheted") + 1)
if Bullet:GetAttribute("Ricochet_RicochetType") == "Perpendicular" then
Bullet.AssemblyLinearVelocity = (RicochetRay.Normal - (-2 * RicochetRay.Normal)).Unit * Bullet.AssemblyLinearVelocity.Magnitude / 1.05
Bullet:SetAttribute("BulletVelocity", (RicochetRay.Normal - (-2 * RicochetRay.Normal)).Unit * Bullet.AssemblyLinearVelocity.Magnitude)
elseif Bullet:GetAttribute("Ricochet_RicochetType") == "Normal" then
Bullet.AssemblyLinearVelocity = (Bullet.AssemblyLinearVelocity - (2 * Bullet.AssemblyLinearVelocity:Dot(RicochetRay.Normal) * RicochetRay.Normal)) / 1.05
Bullet:SetAttribute("BulletVelocity", Bullet:GetAttribute("BulletVelocity") - (2 * Bullet:GetAttribute("BulletVelocity"):Dot(RicochetRay.Normal) * RicochetRay.Normal))
end
end
end
end
local function HandleMagnetism(Bullet)
local NearestMagnet = SelectTarget("Magnet", Bullet, Bullet.Shooter.Value)
if (NearestMagnet.Position - Bullet.Position).Magnitude < Bullet:GetAttribute("Magnetic_MagneticRange") then
NearestMagnet.Destroying:Once(function() Bullet:RemoveTag("HeldByMagnet") end)
if Bullet:GetAttribute("Magnetic_MagneticType") == "Swarm" then
Bullet:SetAttribute("BulletVelocity", Lerp(Bullet:GetAttribute("BulletVelocity"), (NearestMagnet.Position - Bullet.Position).Unit * Bullet:GetAttribute("BulletVelocity").Magnitude, Bullet:GetAttribute("Magnetic_MagneticStrength")))
Bullet.AssemblyLinearVelocity = Lerp(Bullet.AssemblyLinearVelocity, (NearestMagnet.Position - Bullet.Position).Unit * Bullet:GetAttribute("BulletVelocity").Magnitude, Bullet:GetAttribute("Magnetic_MagneticStrength"))
if not Bullet:HasTag("HeldByMagnet") then Bullet:AddTag("HeldByMagnet") end
elseif Bullet:GetAttribute("Magnetic_MagneticType") == "Circular" then
Bullet:SetAttribute("Angle", Bullet:GetAttribute("Angle") + (math.clamp(Bullet:GetAttribute("BulletVelocity").Magnitude / 900, 0, math.huge)))
local NewX = NearestMagnet.Position.X + (7 / Bullet:GetAttribute("Magnetic_MagneticStrength")) * math.cos(Bullet:GetAttribute("Angle"))
local NewZ = NearestMagnet.Position.Z + (7 / Bullet:GetAttribute("Magnetic_MagneticStrength")) * math.sin(Bullet:GetAttribute("Angle"))
Bullet:SetAttribute("BulletVelocity", (Vector3.new(NewX, NearestMagnet.Position.Y, NewZ) - Bullet.Position).Unit * Bullet:GetAttribute("BulletVelocity").Magnitude / Bullet:GetAttribute("Magnetic_MagneticStrength") / 3)
Bullet.AssemblyLinearVelocity = (Vector3.new(NewX, NearestMagnet.Position.Y, NewZ) - Bullet.Position).Unit * Bullet:GetAttribute("BulletVelocity").Magnitude / Bullet:GetAttribute("Magnetic_MagneticStrength") / 3
if not Bullet:HasTag("HeldByMagnet") then Bullet:AddTag("HeldByMagnet") end
end
end
end
local function HandleHoming(Bullet, Player)
local Shooter = Bullet.Shooter.Value
local NearestEnemy = (Shooter ~= Player.Character and Shooter.AttackTarget.Value == Player.Character and SelectTarget("Player", Bullet, Shooter)) or SelectTarget("Enemy", Bullet, Shooter)
if not Bullet:HasTag("HeldByMagnet") and NearestEnemy and NearestEnemy ~= Shooter and NearestEnemy.Humanoid.Health > 0 then
if Shooter ~= Player.Character and NearestEnemy ~= Shooter.AttackTarget.Value then return end
if (NearestEnemy.PrimaryPart.Position - Bullet.Position).Magnitude < Bullet:GetAttribute("Homing_HomingRange") then
Bullet.AssemblyLinearVelocity = Lerp(Bullet.AssemblyLinearVelocity, Vector3.new((NearestEnemy.PrimaryPart.Position - Bullet.Position).Unit.X * Bullet:GetAttribute("BulletVelocity").Magnitude, Bullet.AssemblyLinearVelocity.Y, (NearestEnemy.PrimaryPart.Position - Bullet.Position).Unit.Z * Bullet:GetAttribute("BulletVelocity").Magnitude), Bullet:GetAttribute("Homing_HomingStrength"))
Bullet:SetAttribute("BulletVelocity", Lerp(Bullet:GetAttribute("BulletVelocity"), (NearestEnemy.PrimaryPart.Position - Bullet.Position).Unit * Bullet:GetAttribute("BulletVelocity").Magnitude, Bullet:GetAttribute("Homing_HomingStrength")))
end
end
end
function Movement(RicochetRay, Bullet, Player)
HandleRicocheting(RicochetRay, Bullet)
HandleMagnetism(Bullet)
HandleHoming(Bullet, Player)
Bullet.CFrame = CFrame.lookAt(Bullet.Position, Bullet.Position + Bullet.AssemblyLinearVelocity)
if Bullet:GetAttribute("FollowsGravity") == false then
Bullet.AssemblyLinearVelocity = Bullet:GetAttribute("BulletVelocity")
end
end
function Drill(CharacterCollisionRay, Bullet)
Bullet.Anchored = true
for i = 1, Bullet:GetAttribute("ContinuousDamage_AmountOfLoops") do
task.wait(Bullet:GetAttribute("ContinuousDamage_WaitPerLoop"))
CharacterCollisionRay.Instance.Parent.Humanoid:TakeDamage(Bullet:GetAttribute("Damage") * ((Bullet:GetAttribute("LocationalDamage") == true and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") ~= nil) and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") or 1))
end
Bullet.Anchored = false
end
function Damage(CharacterCollisionRay, Bullet, Playert)
if CharacterCollisionRay and CharacterCollisionRay.Instance and not CharacterCollisionRay.Instance:HasTag("EffectPart") then
if CharacterCollisionRay.Instance:HasTag("Bullet") then
CharacterCollisionRay.Instance.BulletHitByBulletEvent:Fire(Bullet)
else
if CharacterCollisionRay.Instance.Parent == Bullet.Shooter.Value then return end
if CharacterCollisionRay.Instance.Parent:FindFirstChild("Humanoid") and CharacterCollisionRay.Instance.Parent:FindFirstChild("Humanoid").Health > 0 then
local HitHumanoid = CharacterCollisionRay.Instance.Parent:FindFirstChild("Humanoid")
if Bullet:GetAttribute("EnemiesHit") and Bullet:GetAttribute("EnemiesHit") < Bullet:GetAttribute("MaxEnemiesToHit") and not HitHumanoid:HasTag("BeenHit".. Bullet:GetAttribute("ID")) then
Bullet:SetAttribute("EnemiesHit", Bullet:GetAttribute("EnemiesHit") + 1)
HitHumanoid:AddTag("BeenHit".. Bullet:GetAttribute("ID"))
HitHumanoid:TakeDamage(Bullet:GetAttribute("Damage") * ((Bullet:GetAttribute("LocationalDamage") == true and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") ~= nil) and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") or 1))
task.delay(HitHumanoid.Parent:GetExtentsSize().Magnitude / 10, function() HitHumanoid:RemoveTag("BeenHit".. Bullet:GetAttribute("ID")) end)
Drill(CharacterCollisionRay, Bullet)
if Bullet:GetAttribute("FollowsGravity") == true and Bullet:GetAttribute("MaxEnemiesToHit") > 1 and HitHumanoid.Health > 0 and Bullet:GetAttribute("ContinuousDamage_AmountOfTimes") > 0 then
Bullet.AssemblyLinearVelocity = Vector3.yAxis * Bullet:GetAttribute("").Magnitude / 2
Bullet:SetAttribute("TimesRicocheted", Bullet:GetAttribute("Ricochet_MaxRicochets"))
else print("B") Bullet:Destroy() end
if Bullet:GetAttribute("EnemiesHit") >= Bullet:GetAttribute("MaxEnemiesToHit") then print("C") Bullet:Destroy() end
end
elseif not (game.CollectionService:HasTag(CharacterCollisionRay.Instance, "Bullet") or CharacterCollisionRay.Instance.Name == "Bullet") and not Bullet:HasTag("HeldByMagnet") and not CharacterCollisionRay.Instance.Parent:IsA("Accessory") then
Bullet:Destroy()
end
end
end
end
i’ve just had a rough scroll through the code, have you tried setting the network ownership of the part to the player
local Bullet = Instance.new("Part")
for k, v in pairs(Properties) do
if typeof(v) == "table" then
for l, q in pairs(v) do
Bullet:SetAttribute(k.. "_".. l, q)
end
elseif typeof(v) ~= "function" and typeof(v) ~= "Instance" and k ~= "Speed" and k ~= "Direction" and k ~= "Origin" and k ~= "Lifetime" then
Bullet:SetAttribute(k, v)
end
end
Bullet:SetAttribute("ID", tostring(math.random(1, 10^8)))
Bullet:SetAttribute("TimesRicocheted", 0)
Bullet:SetAttribute("EnemiesHit", 0)
Bullet:SetAttribute("BulletVelocity", Vector3.new(Properties.Direction.X + ReturnDecimal(Bullet:GetAttribute("MaxInaccuracy")), Properties.Direction.Y + ReturnDecimal(Bullet:GetAttribute("MaxInaccuracy")), Properties.Direction.Z + ReturnDecimal(Bullet:GetAttribute("MaxInaccuracy"))) * Properties.Speed)
Bullet.Name = (Properties.Name and true or "Bullet").. Bullet:GetAttribute("ID")
Bullet.Size = Properties.Size or Vector3.new(0.75, 0.75, 0.75)
Bullet.Color = Properties.Color or Color3.new(0, 0, 0)
Bullet.Material = Properties.Material or Enum.Material.SmoothPlastic
Bullet.CFrame = Properties.Origin
Bullet.CollisionGroup = "Extra"
Bullet:AddTag("Bullet")
Bullet:AddTag(Properties.ExtraType)
Bullet.CastShadow = false
Bullet.AssemblyLinearVelocity = Bullet:GetAttribute("BulletVelocity")
Bullet.Parent = workspace
Bullet:SetNetworkOwner(Player) -- here
it should make it a bit smoother.
even if you set network ownership, the bullet will still lag for other clients
usually games make a fake bullet on each client and then make the invisible bullet hitbox on the server
thats what im trying to do now, but it keeps on saying “trying to index nil with destroying”
local RemoteEvents = game.ReplicatedStorage.RemoteEvents
RemoteEvents.ReplicateBullet.OnClientEvent:Connect(function(Bullet : Part)
local ClientBullet = Instance.new("Part")
print(Bullet)
local Loop = game["Run Service"].Heartbeat:Connect(function()
if ClientBullet and Bullet then
ClientBullet.Transparency = 0
ClientBullet.Color = Bullet.Color
ClientBullet.Material = Bullet.Material
ClientBullet.CanCollide = false
ClientBullet.Size = Bullet.Size
ClientBullet.Reflectance = Bullet.Reflectance
ClientBullet.CFrame = Bullet.CFrame
end
end)
Bullet.Destroying:Connect(function()
ClientBullet:Destroy()
Loop:Disconnect()
end)
end)
I tried to cleam up your code a little and improve debuggability if you dont mind:
local RunService = game:GetService("RunService")
local RemoteEvents:RemoteEvent = game.ReplicatedStorage.RemoteEvents
local ClientBullet_Model = Instance.new("Part")
ClientBullet_Model.Transparency = 0
ClientBullet_Model.Color = Color3.new(1, 0.776471, 0.258824)
ClientBullet_Model.Material = Enum.Material.Metal
ClientBullet_Model.CanCollide = false
ClientBullet_Model.Anchored = true
ClientBullet_Model.Size = vector.create(1,0.25,1)
ClientBullet_Model.Reflectance = 1
local function ClientBullet(Bullet:Part):()
local ClientBullet:typeof(ClientBullet_Model) = Instance.fromExisting(ClientBullet_Model)
print((typeof(Bullet)=="Instance" and Bullet.ClassName) or typeof(Bullet))
local Loop:RBXScriptConnection = RunService.Heartbeat:Connect(function():()
if ClientBullet and Bullet then
ClientBullet.CFrame = Bullet.CFrame
end
end)
Bullet.Destroying:Connect(function()
ClientBullet:Destroy()
Loop:Disconnect()
end)
end
RemoteEvents.ReplicateBullet.OnClientEvent:Connect(ClientBullet)
Althrough you should change alghoritm complitelly becouse it makes no sense has too many anonimous functions that don’t do anything
YOu should complitelly rewrite it and instead use Beams for bullets
you can use beams for arcade shooters but if you want real projectiles you can use fastcast or implement the bullets yourself with raycasthitbox
The client event doesnt work because you cant send parts over a remote event
Its also not a good idea to send all of the properties of the bullet
You should make a bullet template in replicated storage, and then send the name of which bullet template to use, then the client script clones that template
There is no point in making visuals on server code. Visuals are usually on client, because they are more responsive and way faster than server. I recommend you move your visual to client, while keeping your hit scan logic in the server.