Getting center of mass of a model

Hello. I am working on a script that gets the center of mass of a model. It goes through every part and gets its average position (and does a little bit of multiplying here and there to add the mass of each part in). For some reason, the marker test item I’m using is not at the exact location as it should be. Here is the code and my problem.



local plr = game.Players.LocalPlayer.UserId

function getcenterofmass(model)
	local mass = Vector3.new(0,0,0)
	local num = 0

	for i, v in pairs(model:GetDescendants())do 
		if v:IsA("BasePart") then
			local mass2 = v.Mass
			local wholenumber = math.floor(mass2)
			local decimal = mass2-math.floor(mass2)

			if wholenumber ~= 0 then
				for i = 1,wholenumber do
					num += 1
					mass += v.Position
					--	table.insert(mass,(#mass+1),v.Position)
				end
			end
			
			if decimal >= 0.025 then
				num += 1
				mass += (v.Position*decimal)
			end
			--table.insert(mass,(#mass+1),v.Position*decimal)
		end 
	end
	
	local final = mass/num
	
	mass = Vector3.new(0,0,0)
	num = 0
	return final
end

local part = game:GetService("ReplicatedStorage").Content.PlotIndicator:Clone()
part.Parent = workspace.Storage
part.Position = getcenterofmass(workspace.Plots:WaitForChild(plr.."_Plot"))

game:GetService("RunService").Heartbeat:Connect(function()
	--if part.Transparency == 0 then
		part.Position = getcenterofmass(workspace.Plots:FindFirstChild(plr.."_Plot"))
--	end
end)

![image|690x387](upload://7oJNZ6HQzvdoVEkwWEheq7oiLvk.jpeg)
2 Likes

I think it should be as simple as “model.Center.Postion”

That doesn’t take in part mass though.

Also, I am cycling through a “player plot” which is a part, not a model.
image

Why do you need the part mass?

To give players of my a game a ‘center of mass’ indicator for building planes
image

1 Like

Oh my word, I checked on google for another solution. And I found your other post by accident. What are the odds.

The code works in the test place I made.
image
image

I’d like to note, that I think you can use a function like: “model.CenterOfMass”.
Otherwise we could come up with an artificial way of doing this, by calculating the area of objects and placing them on a table to find its center. This is useful because its very fast. Depends on if its on client or server though.

Oh, do you mean the same code you just used?

I’m already using the mass read-only property so i I don’t need to get area.

1 Like

Here’s the difference between both threads of code.

IN THE GAME



local plr = game.Players.LocalPlayer.UserId

function getcenterofmass(model)
	local mass = Vector3.new(0,0,0)
	local num = 0

	for i, v in pairs(model:GetDescendants())do 
		if v:IsA("BasePart") then
			local mass2 = v.Mass
			local wholenumber = math.floor(mass2)
			local decimal = mass2-math.floor(mass2)

			if wholenumber ~= 0 then
				for i = 1,wholenumber do
					num += 1
					mass += v.Position
					--	table.insert(mass,(#mass+1),v.Position)
				end
			end
			
			if decimal >= 0.025 then
				num += 1
				mass += (v.Position*decimal)
			end
			--table.insert(mass,(#mass+1),v.Position*decimal)
		end 
	end
	
	local final = mass/num
	
	mass = Vector3.new(0,0,0)
	num = 0
	return final
end

local part = game:GetService("ReplicatedStorage").Content.PlotIndicator:Clone()
part.Parent = workspace.Storage
part.Position = getcenterofmass(workspace.Plots:WaitForChild(plr.."_Plot"))

game:GetService("RunService").Heartbeat:Connect(function()
	--if part.Transparency == 0 then
		part.Position = getcenterofmass(workspace.Plots:FindFirstChild(plr.."_Plot"))
--	end
end)

IN THE TEST PLACE

local part = Instance.new("Part",workspace)
part.Anchored = true
part.Size = Vector3.new(3,3,3)
part.Material = Enum.Material.Neon

function getcenterofmass(model)
	local mass = Vector3.new(0,0,0)
	local num = 0
	
	for i, v in pairs(model:GetDescendants())do 
		if v:IsA("BasePart") then
			local mass2 = v.Mass
			local wholenumber = math.floor(mass2)
			local decimal = mass2-math.floor(mass2)
			
			if wholenumber ~= 0 then
				for i = 1,wholenumber do
					num += 1
					mass += v.Position
				--	table.insert(mass,(#mass+1),v.Position)
				end
			end
			
			num += 1
			mass += (v.Position*decimal)
			--table.insert(mass,(#mass+1),v.Position*decimal)
		end 
	end
	
	return mass/num
end

game:GetService("RunService").Stepped:Connect(function()
	part.Position = getcenterofmass(workspace.Model)
end)
1 Like

One of the biggest differences I see is that the returned number is ran through another variable, I’m not sure if this is very needed.

	local final = mass/num
	
	mass = Vector3.new(0,0,0)
	num = 0
	return final

Also is this script being ran locally or on the server?

The script is being ran on the client.

Could you try to run it on the server by means of a remote event? When dealing with parts (even when reading them) it comes with many complications.

Sending messages through remote events every heartbeat!?!?

No we could do this fully on the server unless you only want the model to be viewed locally.

I do want it to be viewed locally, since the game has 10 player servers.

We can still avoid doing it every heart beat by toggling the transparency of the models locally.

Just a suggestion, but I find it fun to interact with other players in plane games. A lot of them do this, like Plane Crazy, Pilote Training Flight Simulator and Project Flightpoint.

Hey, I found the problem. In the test place, I moved the model out to 1000 studs on the X axis, and this is what I found.
image

The further from the origin the model is, the more off the center of mass indicator is.
I think I tracked the problem down to this line of code:
image

1 Like

Yeahhhh that was on purpose, I checked your profile on here because I remember you helping me earlier. Than I saw your yt, and your game flightpoint.

Don’t forget to mark your message as the solution for other people!

1 Like