Too many parts lags the game

Here’s an example I’ve done on a separated experience so I removed the Humanoid in this project and I found a way to make the NPCs run quite smoothly which doesn’t affect much the FPS feel free to let me know how you would adapt this to my project

NPCs_sample.rblx.rbxl (62.0 KB)

Doubled the FPS…

removed deprecated
local PhysicsService = game:GetService("PhysicsService")
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")

-- Collision
local COLLISION_GROUP_NAME = "NPC"
if not pcall(function() PhysicsService:RegisterCollisionGroup(COLLISION_GROUP_NAME) end) then end
PhysicsService:CollisionGroupSetCollidable(COLLISION_GROUP_NAME, COLLISION_GROUP_NAME, false)

-- Dossier pour NPCs
local npcsFolder = Instance.new("Folder", Workspace)
npcsFolder.Name = "NPCs"

-- Constantes
local npcCount = 2000
local SPAWN_RADIUS = 500
local SPEED = 20 -- unités par seconde

local npcs = {}

-- Création d'un NPC minimaliste
local function createNPC(id)
	local part = Instance.new("Part")
	part.Name = "NPC_" .. id
	part.Size = Vector3.new(2, 2, 2)
	part.Position = Vector3.new(math.random(-SPAWN_RADIUS, SPAWN_RADIUS), 5, math.random(-SPAWN_RADIUS, SPAWN_RADIUS))
	part.Anchored = false
	part.CanCollide = true
	part.TopSurface = Enum.SurfaceType.Smooth
	part.BottomSurface = Enum.SurfaceType.Smooth
	part.Parent = npcsFolder

	part.CollisionGroup = COLLISION_GROUP_NAME

	local attachment = Instance.new("Attachment", part)

	local linearVelocity = Instance.new("LinearVelocity")
	linearVelocity.Attachment0 = attachment
	linearVelocity.MaxForce = math.huge
	linearVelocity.RelativeTo = Enum.ActuatorRelativeTo.World
	linearVelocity.VectorVelocity = Vector3.zero
	linearVelocity.Parent = part

	local data = {
		part = part,
		linearVelocity = linearVelocity,
		target = nil,
	}

	table.insert(npcs, data)
	return data
end

-- Mouvement aléatoire
local function pickNewTarget(data)
	local x = math.random(-SPAWN_RADIUS, SPAWN_RADIUS)
	local z = math.random(-SPAWN_RADIUS, SPAWN_RADIUS)
	local y = data.part.Position.Y
	data.target = Vector3.new(x, y, z)
end

local function updateMovement(data)
	if not data.target then
		pickNewTarget(data)
	end

	local direction = (data.target - data.part.Position)
	local distance = direction.Magnitude

	if distance < 5 then
		pickNewTarget(data)
		data.linearVelocity.VectorVelocity = Vector3.zero
	else
		local unit = direction.Unit
		data.linearVelocity.VectorVelocity = unit * SPEED
	end
end

-- Création des NPCs
for i = 1, npcCount do
	createNPC(i)
end

-- Boucle de mise à jour
RunService.Heartbeat:Connect(function()
	for _, npc in ipairs(npcs) do
		updateMovement(npc)
	end
end)

print("✅ 1000 NPCs avec LinearVelocity (sans Humanoid) en déplacement fluide.")

Oh let’s try your solution out what did you change ?

Two lines … :rofl:
Huge return. Noticed it was twice as fast.

Is it your device or somethin because I’m testing right now and I don’t see much difference to be honest

Just took out the deprecated commands and replaced them as needed, nothing wild.
1st few runs your fps said 39-ish… after the switch runs were 59-ish… who knows.

let’s try with 10k NPC the server will probably start lagging lol

Yeah the game is lagging at 10k NPCs ahahahahah the FPS is below 10 sometimes wonder what is the limit toward the Roblox Game Engine