Best way to detect change in CFrame/Position of a BasePart?

So recently I’ve been making a mini-map and I want to locate all the NPC’s in the world. I’ve been trying to detect for any position or CFrame updates but I am unable to do so on the PrimaryPart of the NPC:

local function trackBlueMinion(Minion)
	local MinionTracker = LocationPart:Clone()
	MinionTracker.Position = Minion.PrimaryPart.Position
	MinionTracker.Color = Color3.fromRGB(0, 0, 255)
	MinionTracker.Name = Minion.Name.."'s Tracker"
	MinionTracker.Parent =
	if Minion.Name ~= "Nexus" then
			print(Minion.Name, Minion.PrimaryPart.Position)

I’ve tried on Orientation, CFrame, Position, Velocity. But none of them prints. What I’m trying to do is actively update the position of the Dummy on the mini-map without looping.

I also want to avoid Humanoid objects that’s why I’m checking on the part.

EDIT: My current solution is creating a RunService.Stepped listener upon every minion which I believe can be chaotic. I do make sure to disconnect the event upon minion death.


Your edit seems to work just find, I see no reason to search for a different solution unless you find issues with game performance.

That is exactly the problem, I’d assume I will have at most 200 minions at once. Just imagine 200 stepped Connections running.

Yeah, this is actually something that games do. They constantly keep track of where the player is every time they move. This is extremely hard to do, so games like slitherio actually only update every few seconds to avoid all the traffic. Unfortunately, there’s no way around the lag that’d happen with keeping the position of all those NPCs.

1 Like

But is there a way to detect position / cframe change?

Ok so I wrote this to hopefully figure out exactly what you had in mind
This is in no way meant to be reliable, Just glance over it and see if this is something you were trying to do:

do -- Minion Set-Up

local MinionFolder = workspace.MinionFolder -- Or whatever the NPCs are parented to
local MinionTab = {}

for i,v in pairs(MinionFolder:GetChildren()) do
	if v.Humanoid.Health > 0 then
		if v.Name ~= "Nexus" then

			if not table.find(MinionTab, v.PrimaryPart) then
				MinionTab[v.Name] = v.PrimaryPart

for i,v in pairs(MinionTab) do
	if v then
		Connection = v:GetPropertyChangedSignal("Position"):Connect(function()
			print(Minion.Name, Minion.PrimaryPart.Position) -- Change this to whatever u wanna do


	if Child.Name ~= "Nexus" then
		if not table.find(MinionTab, Child.PrimaryPart) then
			MinionTab[Child.Name] = Child.PrimparyPart


^ This end for some reason did not fit in the Preformatted text option, so oof.


Should definitely work. But like I said, it’s a lot less expensive to update the minimap every few seconds based on the tenacity you intend your minions to have.

The issue is GetPropertyChangedSignal(“Position”) does not receive the signal so It never runs.

It actually doesn’t work for some reason through testing. I’ll try to do some other part rather then primary part.

Did you double check to absolutely make sure it does have a primary part?
May seem like a stupid question but I have done this before.

The gif you sent had it working didn’t it? Was there something wrong?

Yea I’m 100% sure, It’s a brand new dummy and if it didn’t have one it would error since i do set the locator based on the dummy primary part before checking.

Well it was working but it’s extremely expensive which is the issue. The lag, I would love to reduce this as much as possible by detecting changes in position.

Oh right, I’m a bit tired so I’m kind of overlooking things, Maybe you could use PrimaryPart.Changed
I know it’s not really the most popular way of getting changes but :man_shrugging:

Like I said earlier, the lag you’d experience is inevitable. That’s why games with high player counts update the minimap every few seconds rather than constantly

I was just about to suggest updating maybe every 1-5 seconds.

Alternatively you could make it so that the update interval changes everytime a minion is added by maybe 0.5 seconds per minion


Right now I’m running on Stepped. If I would be able to find a way to only update upon change of position or cframe or even velocity it would reduce lag because it’s only updating if needed so.

To @ToshiharuMidori I’ll try

Edit: @ToshiharuMidori, .Changed doesn’t run either.

1 Like

So bizarre, There’s obviously a reason why but it’s kind of hard to tell when you can’t really see someone else’s screen.

I’m gonna read up on the GetPropertyChangedSignal function to see if I can get an explanation.

Edit: I can’t seem to find a reason as to why this is not working, As usual when I can’t figure something out I get some rest. Maybe tomorrow the answer will come to me :slight_smile:


Connecting to a changed event would be equivalent to connecting to RunService.Heartbeat since this is when physics properties would be updated. Heartbeat runs after physics so you’d actually end up wanting to use RunService.Stepped anyway which runs before physics. That will give you better results when objects are moving quickly or the game is experiencing lag (e.g. 30fps instead of 60).

In order to optimize your connection you can use .Touched/.TouchEnded events to enable the connection and wait until the Velocity.Magnitude as well as the RotVelocity.Magnitude values are at a desirable “stand-still” speed before disabling the event again. (E.g. 5 studs per second and 5 degrees per second)

There u go.