Tracking speed of anchored parts

Hey, I’m trying to track the speed of anchored parts moved by non-physics based means such as tweens etc. In other words, I’m trying to replicate having AssemblyLinearVelocity but for anchored parts. Here’s my code:

local SPEED_THRESHOLD = 50
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local lastPositions = {}
local lastUpdateTimes = {}

local function updateAnchoredVelocities()
	local currentTime = tick()

	for _, obj in ipairs(workspace:GetDescendants()) do
		if obj:IsA("BasePart") and obj.Anchored then
			local lastPos = lastPositions[obj] or obj.Position
			local lastTime = lastUpdateTimes[obj] or currentTime
			local deltaTime = currentTime - lastTime

			if deltaTime > 0 then
				local velocity = (obj.Position - lastPos).Magnitude / deltaTime
				obj:SetAttribute("CustomVelocity", velocity)
			end

			lastPositions[obj] = obj.Position
			lastUpdateTimes[obj] = currentTime
		end
	end
end

RunService.PreSimulation:Connect(updateAnchoredVelocities)

local function onCharacterAdded(character)
	local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
	if not humanoidRootPart then return end

	local function onPartTouched(hit)
		if hit and hit:IsA("BasePart") then
			local velocity = hit.AssemblyLinearVelocity.Magnitude
			local customVelocity = hit:GetAttribute("CustomVelocity") or 0

			if math.max(velocity, customVelocity) > SPEED_THRESHOLD then
				print(character.Name .. " was hit by a fast-moving object: " .. hit.Name .. 
					" (Speed: " .. math.max(velocity, customVelocity) .. ")")
			end
		end
	end

	humanoidRootPart.Touched:Connect(onPartTouched)
end

game.Players.LocalPlayer.CharacterAdded:Connect(onCharacterAdded)

While this does work somewhat as intended, results are extremely inaccurate and fluctuate massively. I’ve tested the same method of tracking velocity on unanchored parts, and when the AssemblyLinearVelocity is a constant value, the CustomVelocity that this script calculates will be around 3-5 studs inaccurate but constantly fluctuating around the actual value.

If anyone has any solutions for this it would be much appreciated.

Are you moving tweening the part on the server? Maybe it’s simply replication lag that causes it to not move the exact amout of distance in a time.

All tweens and animations are played on the client

So I did a little testing, I found out that if you ‘accumulate’ the time and average out the change in position over a period of time, it becomes much more stable.

local plr = script.Parent

local root : Part= plr:WaitForChild("HumanoidRootPart")

print(root.Name)

local past = root.Position
local accum = 0
game:GetService("RunService").PreSimulation:Connect(function(dt)
	accum += dt
	if accum > 0.1 then
		local dis = (past - root.Position).Magnitude
		past = root.Position
		print(dis/accum)
		accum = 0
	end
	
end)

It was really close to the true speed.

1 Like

Can’t you use the equation distance = speed x time rather than velocity?

That’s exactly what he tried to do, but he did that every simulation step, and because of overhead, the distance that an object moves every time step changes a bit, causing inaccuracy. My version averages the distance over a period of time much larger than a single frame, averaging out the error.

Shouldn’t you do it on a while loop because i’m pretty sure runservice events just runs every block of code inside of it at the same time? I could be mistaken though because i’m currently on break.

RunService provides several events that run at different times during the render/physics pipeline of roblox. In this case, PostSimulation runs after physics has been calculated for the frame. A while loop with a wait in it would simply not be based on the actual physics loop, leading to more inaccuracy.

This is the closest results so far, appreciate the help.

I’m going to assume that the reason it’s so difficult to get the exact value is down to roblox shortening long decimal values leaving us with slightly inaccurate results, not sure though.