How do you track a player's distance traveled in studs?

  1. What do you want to achieve? Keep it simple and clear!
    I am looking to track (for an actively updating leaderboard) a player’s stud count. This is for a system that give player’s rewards if they have reached a certain number of studs travelled.
    It will track this distance, then it will update it to a Datastore when the player leaves.
    I have seen other people do it before, but I don’t know where to start on tracking distance travelled.

  2. What is the issue? Include screenshots / videos if possible!
    I have no idea what service, or what system to use to track this. I have tried adding a players magnitude to an old position to a leaderboard value, but standing still added to the leaderboard just the same as moving.

This was where I started, and this is the only thing I have been able to figure out.

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I have tried to looked for solutions, and nothing was showing up except people tracking “footsteps”, which is not what I am looking for. If anything here is unclear, I am willing to clarify.
4 Likes

MoveDirection exists? Let me try this.

Do you wish to save this data? Or have it only work in the session.lock?

As you can see in the code, once the player leaves, it would store the data after it is all collected. Then they can use it for rewards in the future.

If you are using DataStores in MilesSystem.lua (Module), please keep in mind that it is Replicated from ServerScriptService not the DataModel’s workspace

I am not using a Datastore, I am using web requests.

I tried this and it didn’t work:

game:GetService('RunService').Heartbeat:Connect(function()
	for i,Player in pairs(game.Players:GetPlayers()) do
		if Player.Character then
			local Humanoid = Player.Character:FindFirstChildOfClass("Humanoid")
			if Humanoid.MoveDirection.Magnitude > 0 then
				if OldPosition[Player.UserId] then
					local newDistanceTravelled = (Humanoid.RootPart.Position - OldPosition[Player.UserId]).Magnitude
					TotalStudsWalked[Player.UserId] = TotalStudsWalked[Player.UserId] + newDistanceTravelled
					Player:WaitForChild("leaderstats").Miles.Value = Player:WaitForChild("leaderstats").Miles.Value + (newDistanceTravelled / 5)
					OldPosition[Player.UserId] = Humanoid.RootPart.Position
				else
					TotalStudsWalked[Player.UserId] = 0
					OldPosition[Player.UserId] = Humanoid.RootPart.Position
				end
			end
		end
	end
end)

Would you be able to send the Module? You can remove the web-link in it if you want. And, I suggest to use DataStores

The module is not the issue. I do fine working with that, and it is only use at the Player Added and Player Removed endpoints. I use it because this information would travel along multiple games.

--[[
    VISTA-Module
    Please do not edit below.
--]]

-- Variables
local MilesService = {}
local HttpService = game:GetService('HttpService')
local Link = '' -- REMOVED FOR SAFETY PURPOSES
local APIKey = '' -- REMOVED FOR SAFETY PURPOSES

function MilesService:Add(User, Value)
	if type(tonumber(Value)) ~= "number" then
		return false
	end
	local OldContent = {
		userid = 'miles_'..User.UserId;
		key = APIKey;
	}
	local OldData = HttpService:JSONEncode(OldContent)
	local Old = HttpService:PostAsync(Link..'get', OldData)
	if Old:gsub(" ","") == "" or Old == nil then
		Old = 0
	else
		Old = tonumber(Old)
		if type(Old) ~= "number" then
			Old = 0
		end
	end
	local NewContent = {
		userid = 'miles_'..User.UserId;
		data = tonumber(Old + Value);
		key = APIKey;
	}
	local NewData = HttpService:JSONEncode(NewContent)
	local SetSuccess = HttpService:PostAsync(Link..'save', NewData)
	return true
end

function MilesService:Remove(User, Value)
	Value = tonumber(Value)
	if type(Value) ~= "number" then
		return false
	end
	local OldContent = {
		userid = 'miles_'..User.UserId;
		key = APIKey;
	}
	local OldData = HttpService:JSONEncode(OldContent)
	local Old = HttpService:PostAsync(Link..'get', OldData)
	if Old:gsub(" ","") == "" or Old == nil then
		Old = 0
	else
		Old = tonumber(Old)
		if type(Old) ~= "number" then
			Old = 0
		end
	end
	if Old < Value then
		return false
	end
	local NewContent = {
		userid = 'miles_'..User.UserId;
		data = tonumber(Old + Value);
		key = APIKey;
	}
	local NewData = HttpService:JSONEncode(NewContent)
	local SetSuccess = HttpService:PostAsync(Link..'save', NewData)
	return true
end

function MilesService:Get(User)
	local OldContent = {
		userid = 'miles_'..User.UserId;
		key = APIKey;
	}
	local OldData = HttpService:JSONEncode(OldContent)
	local Old = HttpService:PostAsync(Link..'get', OldData)
	if Old:gsub(" ","") == "" or Old == nil then
		Old = 0
	else
		Old = tonumber(Old)
		if type(Old) ~= "number" then
			Old = 0
		end
	end
	return Old
end

function MilesService:Set(User, Value)
	if type(tonumber(Value)) ~= "number" then
		return false
	end
	local NewContent = {
		userid = 'miles_'..User.UserId;
		data = tonumber(Value);
		key = APIKey;
	}
	local NewData = HttpService:JSONEncode(NewContent)
	local SetSuccess = HttpService:PostAsync(Link..'save', NewData)
	return true
end

return MilesService

I will have a look into this and will reply if I have a solution.

I just tested this again. I used RunService Heartbeat (because this is being done through a localscript, and it only worked when I started moving, not while I was moving, and not while I was standing still.

I found the fix! Thanks to TheCarbyneUniverse’s reply, MoveDirection was how it was supposed to be. For those who may get help from this, here is my new code:

local OldPosition = {}
local TotalStudsWalked = {}
local Data = require(script.MilesSystem)
game.Players.PlayerAdded:Connect(function(Player)
	local Board = Instance.new("Folder")
	Board.Name = "leaderstats"
	Board.Parent = Player
	local Traveled = Instance.new("IntValue", Board)
	Traveled.Name = "Miles"
	Traveled.Value = Data:Get(Player)
end)
game.Players.PlayerRemoving:Connect(function(Player)
	Data:Add(Player, TotalStudsWalked[Player.UserId] / 5)
end)
while wait do
	for i,Player in pairs(game.Players:GetPlayers()) do
		if Player.Character then
			local Humanoid = Player.Character:FindFirstChildOfClass("Humanoid")
			if Humanoid.MoveDirection.Magnitude > 0 then
				if OldPosition[Player.UserId] then
					local newDistanceTravelled = (Humanoid.RootPart.Position - OldPosition[Player.UserId]).Magnitude
					TotalStudsWalked[Player.UserId] = TotalStudsWalked[Player.UserId] + newDistanceTravelled
					Player:WaitForChild("leaderstats").Miles.Value = Player.leaderstats.Miles.Value + (newDistanceTravelled / 5)
					OldPosition[Player.UserId] = Humanoid.RootPart.Position
				else
					TotalStudsWalked[Player.UserId] = 0
					OldPosition[Player.UserId] = Humanoid.RootPart.Position
				end
			end
		end
	end
	wait(0.1)
end
3 Likes
local function GetPos()
	local plr = game.Players.LocalPlayer
	local char = workspace:WaitForChild(plr.Name)
	while true do
		local Magnitude = (char:WaitForChild("HumanoidRootPart").Position - workspace.Center.Position).Magnitude
		wait(1)
		print(Magnitude)
	end
end

GetPos()

All I have