Hello everyone I made a resource today primarily for people that are newer to scripting and want to help optimize certain parts of their game.
Have you ever worked on a game and found yourself having to iterate through lots of entities at once?
-
Perhaps you’re making a game with AI entities that don’t move, but for client sided effects(sound,particles,animations, or even logic) you want to only consider entities that are close to your player’s camera. It can be pretty costly to iterate through every entity and calculate the distance to them. And kind of defeats the purpose!
-
Or perhaps you’re generating a bunch of points by choosing a random position within a field, but you need to make sure the points are more evenly distributed(aren’t too close to another existing point). Surely you don’t want to search through every point , for every candidate point.
Introducing my free little resource for you! ChunkSystem
It’s nothing fancy, but this is a pretty basic take on static spatial partitioning(dividing a space into more manageable segments basically).
There are other data structures to use, but I’ve personally found this to be useful in a variety of cases and I hope you find use with it too.
How does it work?
To create a ChunkSystem(a holder of chunks), you simply input whether you want 2 or 3 dimensions, and a Chunk Size(in studs)
local chunkSystem = ChunkSystem.new(3,100) -- Creates a holder of 100x100x100 chunks
You can then create chunks or get them with an input position. All this does is round your input position to get the corresponding chunk! It’s also fast enough to use often for most use cases.
local chunkAtCamera = ChunkSystem:GetChunk(camera.CFrame.p,true) -- The second variable will create a chunk if none is found
You can add objects to your chunk, and remove them
chunkAtCamera:AddObject(workspace.Entity);
You can get the objects added to a chunk, and also include their surrounding/adjacent chunks
local objects = chunkAtCamera:GetObjects(); -- Just gets the objects in this chunk
local objects = chunkAtCamera:GetObjects("Surrounding"); -- Includes objects in surrounding chunks
local objects = chunkAtCamera:GetObjects("Adjacent"); -- Includes objects in adjacent chunks
There’s more, but that about sums up the API.
API
API:
ChunkSystem:
ChunkSystem ChunkSystem.new(int Dimensions,int ChunkSize)
Creates a ChunkSystem with 2 or 3 dimensions, and a given ChunkSize
Chunk ChunkSystem:GetChunk(Vector3 position,boolean CreateIfNotFound)
Returns the Chunk at the given position
If a Chunk is not found, create if CreateIfNotFound is true
Chunk ChunkSystem:CreateChunk(Vector3 position)
Creates a Chunk at the given position if one does not exist
Returns the Chunk
void ChunkSystem:RemoveChunk(Vector3 position)
Removes the chunk at the given position
Chunk:
Table Chunk:GetObjects(String IncludeType)
Returns all of the objects added to this chunk
You can optionally pass in “Surrounding” or “Adjacent” for IncludeType.
This will include objects from either the adjacent(directly touching) or surrounding chunks.
Vector3 Chunk:GetPosition()
Returns the position of this chunk. For 2 dimensional chunks, y will always be 0
void Chunk:AddObject(Variant object)
Add this object to the chunk
You can only add tables or instances to chunks
void Chunk:AddObjects(Table objects)
Add multiple objects to this chunk
void Chunk:RemoveObject(Variant object)
Removes object from chunk, if it exists
boolean Chunk:ObjectExists(Variant object)
Returns whether or not the object exists in this chunk
Table Chunk:GetAdjacentChunks()
Returns a table of chunks that are directly touching this chunk
Table Chunk:GetSurroundingChunks()
Returns a table of chunks that are surrounding this chunk
And here are some example problems from before
Solving the example problems
Perhaps you’re making a game with AI entities that don’t move, but for client sided effects(sound,particles,animations, or even logic) you want to only consider entities that are close to your player’s camera. It can be pretty costly to iterate through every entity and calculate the distance to them. And kind of defeats the purpose!
local chunkSystem = ChunkSystem.new(3,50) -- 50 stud chunks
for i = 1,#entities do
local entity = entities[i];
if entity then
chunkSystem:CreateChunk(entity.Position);
end
end
-- On some loop
local chunkAtCamera = chunkSystem:GetChunk(camera.CFrame.p,true); -- Create if none found
local entitiesAroundCamera = chunkAtCamera:GetObjects("Surrounding");
for i = 1,#entitiesAroundCamera do
local entity = entitiesAroundCamera[i];
if entity then
local dist = (cam.CFrame.p-entity.Position).magnitude;
if dist < someThreshold then
-- Do Logic!
end
end
end
Or perhaps you’re generating a bunch of points by choosing a random position within a field, but you need to make sure the points are more evenly distributed(aren’t too close to another existing point). Surely you don’t want to search through every point , for every candidate point.
local chunkSystem = ChunkSystem.new(2,50);
local Points = {};
local Num = 100; -- I want 100 random points that aren't too close to eachother
while #Points<Num do
local index = RNG:NextInteger(1,#SpawnCandidates);
local candidate = SpawnCandidates[index];
if candidate then
local TooCloseDist = 8; -- must be > 8 studs from another placed point!
local candidatePosition = candidate.Position;
local candidateChunk = chunkSystem:GetChunk(candidatePosition,true);
local objectsFound = candidateChunk:GetObjects("Surrounding");
local tooClose;
for i = 1,#objectsFound do
local objectFound = objectsFound[i];
local dist = (objectFound.Position - candidatePosition).magnitude;
if dist <= TooClose then
tooClose=true;
break;
end
end
if not tooClose then -- If they're not too close to another, place, add it to the chunk and repeat!
candidateChunk:AddObject(candidate);
table.remove(SpawnCandidates,index);
table.insert(Points,candidate);
end
end
end
https://www.roblox.com/library/4508568715/ChunkSystem
If you’d like the source directly:
Chunk.lua (5.8 KB) ChunkSystem.lua (6.1 KB)
(Chunk must go under ChunkSystem)