Optimizing the script for bow and arrow

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)

1 Like

send a remote event to the server

then the server should send a remote event to all clients

then on the client create an arrow when it receives that event

with this, arrow is on the client (smooth physics) but its also on all clients at around the same time

Hi,
Do you happen to have a .rbxl of just a simple block and block arrow that show the server remote event / client reading the event ?

Thanks