luarobloxluau

How to efficently check parts against data in Luau?


I've been creating a windfield system in Luau (Roblox). I'm creating arrays for the winddata with the key being a Vector3 converted to string format. However, I'm struggling to find the best way to loop through check if parts in the workspace at the position (key converted back to Vector3). My Code:

--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local WindArrow = ReplicatedStorage:WaitForChild("WindArrow")

local module={}

module.WindfieldClass={}
module.WindfieldClass.__index=module.WindfieldClass

--Math Functions
local function roundVector3ToIncrement(n: Vector3, increment: number): Vector3
    return Vector3.new(math.floor((n.X / increment) + 0.5) * increment,
        math.floor((n.Y / increment) + 0.5) * increment,
        math.floor((n.Z / increment) + 0.5) * increment
    )
end

--Misc Functions
function module.vector3Key(v: Vector3): string
    return v.X .. "," .. v.Y .. "," .. v.Z
end

function module.stringToVector3(s: string): Vector3
    local x, y, z = string.match(s, "([^,]+),([^,]+),([^,]+)")
    return Vector3.new(tonumber(x), tonumber(y), tonumber(z))
end




function module.WindfieldClass.new()
    local self={
        WindVA={
            
        },
        WindHA={
            
        },
        Visualized=false,
        Resolution=1
    }
    self=setmetatable(self,module.WindfieldClass)
    return self
end


function module.WindfieldClass:add(Position:Vector3,Orientation:number,Type:string,WindSpeed:number)
    if Type=="HA" then
        local ori=Vector3.new(0,Orientation,0)
        Position=roundVector3ToIncrement(Position,self.Resolution)
        self.WindHA[module.vector3Key(Position)]={
            Orientation=Orientation,
            WindSpeed=WindSpeed
        }
    elseif Type=="VA" then
        local ori=Vector3.new(0,0,180)
        Position=roundVector3ToIncrement(Position,self.Resolution)
        self.WindHA[module.vector3Key(Position)]={
            Orientation=Orientation,
            WindSpeed=WindSpeed
        }
    else
        warn("Type "..Type.." is invaid!")
    end
end

function module.WindfieldClass:visualize(mode:number,Dest:Instance)
    if self.Visualized then
        if mode==0 then
            for key,data in pairs(self.WindHA) do
                local clone=WindArrow:Clone();clone.Position=module.stringToVector3(key);clone.Orientation = Vector3.new(0, data.Orientation, 0)

                clone.Parent=Dest
            end
            
        end
        
    end
end

function module.WindfieldClass:simulate()
    
end


return module

The goal of this code (haven't added it yet) is to get the part's in the arrays created by module.WindfieldClass.new(), and move the part's CFrame based on both tables- WindVA for the lift table (vertical movement). and WindHA for horizontal movement (x and z). I've tried looping through all parts that meet the criteria, but with a lot of destructable parts, it's really laggy. What is the best way of achieving this?


Solution

  • If I were to optimize your code, I would only make a few changes :

    -- create a luau type to allow for compile-time validation of inputs
    export type WindfieldType = "HA" | "VA"
    
    function module.WindfieldClass:add(Position:Vector3, Orientation:number, Type:WindfieldType, WindSpeed:number)
        local ori
        if Type=="HA" then
            ori = Vector3.new(0, Orientation, 0)
        elseif Type=="VA" then
            ori = Vector3.new(0, 0, 180)
        else
            warn("Type "..Type.." is invaid!")
            return
        end
    
        local key = roundVector3ToIncrement(Position, self.Resolution)
        self.WindHA[key] = {
            Orientation = ori,
            WindSpeed = WindSpeed
        }
    end
    -- ...
    function module.WindfieldClass:visualize(mode:number, Dest:Instance)
        if not self.Visualized then
            return
        end
    
        if mode == 0 then
            for key,data in pairs(self.WindHA) do
                local clone = WindArrow:Clone()
                clone.Position = key
                clone.Orientation = data.Orientation
                -- perhaps try to scale the clone by how fast the wind speed is moving?
                -- clone.Size *= data.Windspeed
                clone.Parent = Dest
            end
        end
    end
    
    -- in a Script somewhere...
    -- find the objects that need to move, be sure to parent objects to this Folder
    local objectsFolder : Folder = game.Workspace.SimulatedObjects
    
    for i, child in ipairs(objectsFolder:GetChildren()) do
        -- apply forces from the wind field to each child object...
    end
    

    The goal of optimization is to look at your code, and the operations you do, and try to figure out what you have "too many" of. In your case, your loops have too many objects that they are stepping over. So your goal should be to find ways to reduce that by tracking only the objects you care about.