I want to achieve a smoother simulation of arrows and synchronize it with all players and the server.The fact that when using my script server robloxa poorly processed physics and the arrow begins to stagger from side to side in flight, I tried to make the script local but in this case other players do not see the arrow and can not interact with it.I attach the server script:
local ArrowTemplate = game.ServerStorage:WaitForChild("Arrow")
local RunService = game:GetService("RunService")
script.Parent.Attack.OnServerEvent:Connect(function(plr, targetPosition)
local character = plr.Character
if not character or not character:FindFirstChild("HumanoidRootPart") then return end
local arrow = ArrowTemplate:Clone()
arrow.Parent = workspace
local humanoidRootPart = character.HumanoidRootPart
arrow.CFrame = humanoidRootPart.CFrame * CFrame.new(0, 1, -2)
local startPosition = arrow.Position
local direction = (targetPosition - startPosition).Unit
local initialSpeed = 100 -- Начальная скорость (м/с, примерно как у реальных стрел)
local velocity = direction * initialSpeed
local gravity = Vector3.new(0, -workspace.Gravity*0.2, 0) -- Гравитация из настроек мира
local timeStep = 1/60 -- Шаг симуляции (примерно 60 FPS)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character, arrow}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local function simulateArrow()
local currentPosition = arrow.Position
local currentVelocity = velocity
local hitResult = nil
while arrow and arrow.Parent do
currentVelocity = currentVelocity + gravity * timeStep
local nextPosition = currentPosition + currentVelocity * timeStep
local rayResult = workspace:Raycast(currentPosition, nextPosition - currentPosition, raycastParams)
arrow.CFrame = CFrame.new(currentPosition, currentPosition + currentVelocity)
currentPosition = nextPosition
if rayResult then
hitResult = rayResult
break
end
RunService.Heartbeat:Wait()
end
if hitResult then
local hit = hitResult.Instance
local humanoid = hit.Parent:FindFirstChild("Humanoid")
local ownerHum = character:FindFirstChild("Humanoid")
arrow.CFrame = CFrame.new(hitResult.Position, hitResult.Position + currentVelocity)
if humanoid and humanoid ~= ownerHum then
humanoid:TakeDamage(20)
local weld = Instance.new("WeldConstraint")
weld.Part0 = arrow
weld.Part1 = hit
weld.Parent = arrow
elseif hit ~= workspace.Baseplate then
local weld = Instance.new("WeldConstraint")
weld.Part0 = arrow
weld.Part1 = hit
weld.Parent = arrow
end
end
end
-- simulation
coroutine.wrap(simulateArrow)()
-- destroy
task.delay(10, function()
if arrow and arrow.Parent then
arrow:Destroy()
end
end)
end)
and local script:
local Players = game:GetService("Players")
local Folder = script.Parent
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local attackEvent = Folder:WaitForChild("Attack")
mouse.Button1Down:Connect(function()
local targetPosition = mouse.Hit.Position
attackEvent:FireServer(targetPosition)
end)