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.
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)
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.