### Install Wally and Matter using CLI Commands Source: https://matter-ecs.github.io/matter/Installation This sequence of shell commands guides the user through the process of setting up Wally and installing Matter ECS. It includes initializing Aftman, adding Wally, installing packages, initializing Wally, and finally installing the Matter dependency. ```Shell aftman init aftman add UpliftGames/wally aftman install wally init wally search matter-ecs wally install ``` -------------------------------- ### Define a Basic Matter System Source: https://matter-ecs.github.io/matter/GettingStarted This example creates a simple Matter system that prints 'Hello world!' every time it runs. Systems are typically functions that encapsulate game logic and operate on the entities and components within the Matter `World`. ```luau local function myFirstSystem() print("Hello world!") end return myFirstSystem ``` -------------------------------- ### Begin the Matter Loop with Heartbeat Source: https://matter-ecs.github.io/matter/GettingStarted This snippet shows how to start the Matter `Loop`, configuring it to run systems on every `RunService.Heartbeat` event. This ensures that the scheduled systems execute consistently with the game's frame rate. ```luau loop:begin({ default = RunService.Heartbeat }) ``` -------------------------------- ### Initialize Matter World and Loop Source: https://matter-ecs.github.io/matter/GettingStarted This snippet demonstrates how to import the Matter library and initialize a new `World` and `Loop` instance. The `Loop` is configured to pass the `World` to all your systems, which is a fundamental step for any Matter project. ```luau local Matter = require(ReplicatedStorage.Matter) local world = Matter.World.new() local loop = Matter.Loop.new(world) -- This makes Loop pass the world to all your systems. ``` -------------------------------- ### Configure Aftman for Wally Package Manager Source: https://matter-ecs.github.io/matter/Installation This TOML snippet illustrates how to add Wally as a tool within your `aftman.toml` configuration file. It specifies the GitHub repository and a version placeholder for Wally, enabling Aftman to manage its installation. ```TOML [tools] wally = "UpliftGames/wally@x.x.x" ``` -------------------------------- ### Collect and Schedule Systems from a Folder Source: https://matter-ecs.github.io/matter/GettingStarted This code iterates through a specified 'systems' folder, identifies all `ModuleScript` files, and requires them. The collected system modules are then scheduled with the Matter `Loop`, preparing them for execution. ```luau local systems = {} for _, child in ipairs(script.systems:GetChildren()) do if child:IsA("ModuleScript") then table.insert(systems, require(child)) end end loop:scheduleSystems(systems) ``` -------------------------------- ### Add Matter Dependency to wally.toml Source: https://matter-ecs.github.io/matter/Installation This TOML snippet demonstrates how to declare 'matter' as a dependency in your `wally.toml` file. It specifies the package name and a fixed version, ensuring that Wally fetches the correct Matter ECS library. ```TOML [dependencies] matter = "matter-ecs/matter@0.8.4" ``` -------------------------------- ### Define Custom Matter Components Source: https://matter-ecs.github.io/matter/GettingStarted This snippet demonstrates how to define custom components using `Matter.component()`. Components are simple data containers that can be attached to entities, representing their attributes or state within the ECS architecture. ```luau local Matter = require(ReplicatedStorage.Matter) return { Health = Matter.component(), Poison = Matter.component(), } ``` -------------------------------- ### Matter ECS and Roblox API Reference for Replication Source: https://matter-ecs.github.io/matter/Guides/Replication Key API methods from Matter ECS and Roblox's `RemoteEvent` used for world state replication and synchronization. ```APIDOC World: queryChanged(component: Component) -> (entityId: any, record: { new: any, old: any }) Detects when a component changes for an entity. component: The component type to query for changes. Returns: An iterator yielding entity IDs and records containing new and old component data. RemoteEvent: FireAllClients(payload: table) Fires the RemoteEvent to all connected clients, passing the given payload. payload: A table containing data to be sent to clients. FireClient(player: Player, payload: table) Fires the RemoteEvent to a specific client, passing the given payload. player: The Player object representing the target client. payload: A table containing data to be sent to the client. ``` -------------------------------- ### Create a System for Component Interaction (Poison Hurts) Source: https://matter-ecs.github.io/matter/GettingStarted This system queries the `World` for entities that possess both `Health` and `Poison` components. For each matching entity, it reduces the `Health` component's value by 0.1 using the `patch` function, showcasing how systems modify component data immutably. ```luau local Components = require(script.Parent.components) local Health = Components.Health local Poison = Components.Poison local function poisonHurts(world) for id, health in world:query(Health, Poison) do world:insert(id, health:patch({ value = health.value - 0.1 })) end end ``` -------------------------------- ### Install Rewire Dependency using Wally Source: https://matter-ecs.github.io/matter/Guides/HotReloading This `wally.toml` configuration snippet demonstrates how to declare the 'rewire' library as a dependency for your Roblox project using Wally, the Roblox open-source package manager. This setup is crucial for integrating hot-reloading capabilities into your Matter ECS game. ```TOML [dependencies] rewire = "sayhisam1/rewire@0.3.0" ``` -------------------------------- ### Synchronize Full World State for New Players (Lua) Source: https://matter-ecs.github.io/matter/Guides/Replication This Lua code augments the replication system to send the entire current world state to a newly joined player. It iterates through all entities and their replicated components, constructs a payload identical in structure to the change replication, and sends it to the specific player using `RemoteEvent:FireClient`. ```Lua -- Also inside our replication function -- Run some code every time a player joins for _, player in useEvent(Players, "PlayerAdded") do local payload = {} -- Loop over the entire World using the world's __iter metamethod implementation for entityId, entityData in world do local entityPayload = {} -- Loop over all the components the entity has for component, componentData in entityData do -- Only if it's in our list of replicated components... if replicatedComponents[component] then -- Add it to the data we're sending for this entity entityPayload[tostring(component)] = { data = componentData } end end -- Add the entity data to our overall payload payload[tostring(entityId)] = entityPayload end RemoteEvent:FireClient(player, payload) end ``` -------------------------------- ### Initialize Rewire HotReloader in Roblox Source: https://matter-ecs.github.io/matter/Guides/HotReloading This code snippet demonstrates the initial setup for `rewire`'s hot reloading capabilities in a Roblox environment. It retrieves necessary services and modules to create an instance of `HotReloader`, which is essential for monitoring and managing system changes dynamically. ```Lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Packages = ReplicatedStorage.Packages local HotReloader = require(Packages.rewire).HotReloader local hotReloader = HotReloader.new() ``` -------------------------------- ### Map Replicated Component Names to Components (Luau) Source: https://matter-ecs.github.io/matter/Guides/Replication This Luau snippet iterates through the `REPLICATED_COMPONENTS` list (containing string names) and populates a new table, `replicatedComponents`. It uses the actual component objects (assumed to be accessible via a `Components` module) as keys, mapping them to a boolean `true`. This prepares the components for efficient lookup and processing during the replication logic. ```Luau local replicatedComponents = {} for _, name in REPLICATED_COMPONENTS do replicatedComponents[Components[name]] = true end ``` -------------------------------- ### Client-Side Entity Replication Handler (Lua) Source: https://matter-ecs.github.io/matter/Guides/Replication This Lua code snippet demonstrates how a client processes replicated entity data from a server. It listens for `OnClientEvent` on a `MatterRemote` RemoteEvent, iterating through received entities to spawn new ones, despawn removed ones, and update components for existing entities. It maintains an `entityIdMap` to translate server entity IDs to client-side IDs. ```Lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Components = require(ReplicatedStorage.Game.components) -- example -- Get our remote event that we created on the server local RemoteEvent = ReplicatedStorage:WaitForChild("MatterRemote") -- A lookup table from server entity IDs to client entity IDs. They're different! local entityIdMap = {} RemoteEvent.OnClientEvent:Connect(function(entities) -- entities is the data sent from the server. Either the `payload` or `changes` from earlier! -- Loop over the entities the server is replicating for serverEntityId, componentMap in entities do -- Check if we've created this entity on the client before local clientEntityId = entityIdMap[serverEntityId] -- If we've created this entity before, and there are no components inside its list, that means -- the entity was despawned on the server. We despawn it here too. if clientEntityId and next(componentMap) == nil then world:despawn(clientEntityId) -- Remove it from our lookup table entityIdMap[serverEntityId] = nil continue end local componentsToInsert = {} local componentsToRemove = {} -- Loop over all the components in the entity for name, container in componentMap do -- If container.data exists, the component was either changed or added. if container.data then table.insert(componentsToInsert, Components[name](container.data)) else -- if it doesn't exist, it was removed! table.insert(componentsToRemove, Components[name]) end end -- We haven't created this entity on the client before. create it. if clientEntityId == nil then clientEntityId = world:spawn(unpack(componentsToInsert)) -- add the client-side entity id to our lookup table entityIdMap[serverEntityId] = clientEntityId else -- we've seen this entity before. -- Just insert or remove any necessary components. if #componentsToInsert > 0 then world:insert(clientEntityId, unpack(componentsToInsert)) end if #componentsToRemove > 0 then world:remove(clientEntityId, unpack(componentsToRemove)) end end end end) ``` -------------------------------- ### Update Matter ECS Dependency in wally.toml Source: https://matter-ecs.github.io/matter/Guides/Migration This code snippet demonstrates the necessary change in the `wally.toml` configuration file to migrate a Matter ECS project. It updates the package dependency from the old 'evaera/matter' to the new 'matter-ecs/matter' organization, specifying version 0.8.4. ```TOML [dependencies] matter = "matter-ecs/matter@0.8.4" ``` -------------------------------- ### Replicate Component Changes to All Clients (Lua) Source: https://matter-ecs.github.io/matter/Guides/Replication This Lua code snippet demonstrates how to detect and buffer component changes using `world:queryChanged` and then send these buffered changes to all connected clients via a `RemoteEvent`. It handles entity ID and component name conversion for Roblox's remote event limitations and ensures only existing entities' changes are sent. ```Lua -- In the replication function we created above. -- Create a table to buffer up our changes so we only send out at most one remote event per frame local changes = {} -- Loop over our table of replicated components for component in replicatedComponents do -- Loop over queryChanged for this component for entityId, record in world:queryChanged(component) do -- We convert the entity ID to a string because tables sent over remote events in Roblox -- can only have string keys. (did I just teach you something new?) local key = tostring(entityId) -- Get the name of the component. This is done with tostring as well because components have -- a custom __tostring metamethod that returns their human-readable name. local name = tostring(component) -- If there aren't any changes from this entity in the buffer so far, create the table for it if changes[key] == nil then changes[key] = {} end -- Only send over the changed component if the entity still exists in our world. if world:contains(entityId) then -- Lua tables can't contain nil as values, this is indistinguishable from the key just -- not existing at all. -- Instead, we set all values to a table, and then create a key inside that for the real -- value. This lets us detect when a component is removed (set to nil) changes[key][name] = { data = record.new } end end end -- Check if there are any changes in our buffer before sending the changes to all clients. if next(changes) then RemoteEvent:FireAllClients(changes) end ``` -------------------------------- ### Create RemoteEvent for Matter Replication (Luau) Source: https://matter-ecs.github.io/matter/Guides/Replication This Luau code initializes a `RemoteEvent` instance, names it 'MatterRemote', and parents it to `ReplicatedStorage`. This `RemoteEvent` is a crucial communication channel that will be used for sending replication-related data between the server and clients in the Roblox environment. ```Luau local ReplicatedStorage = game:GetService("ReplicatedStorage") local RemoteEvent = Instance.new("RemoteEvent") RemoteEvent.Name = "MatterRemote" RemoteEvent.Parent = ReplicatedStorage ``` -------------------------------- ### Retrieve Component from Entity in Matter ECS (Lua) Source: https://matter-ecs.github.io/matter/Concepts This Lua example illustrates how to retrieve a specific component from an existing entity in the Matter ECS `World`. It uses the `get` method, providing the entity's ID and the component type (`Name` in this case). The retrieved component object allows access to its defined fields, such as `nameComponent.name`. ```lua local nameComponent = world:get(newEntityId, Name) print(nameComponent.name) ``` -------------------------------- ### Define Server-Side Replication System Structure (Luau) Source: https://matter-ecs.github.io/matter/Guides/Replication This Luau code defines the basic structure for the server-side replication system within Matter ECS. It includes an empty `replication` function, which will contain the core replication logic, and sets the system's `priority` to `math.huge`. Setting a high priority ensures that this replication system runs last in the frame, allowing it to process all component changes before replication occurs. ```Luau local function replication(world) -- todo! end return { system = replication, priority = math.huge, } ``` -------------------------------- ### Implement Hot Reloading Logic for Matter ECS Systems Source: https://matter-ecs.github.io/matter/Guides/HotReloading This extensive code block illustrates the core hot-reloading mechanism using `HotReloader:scan`. It defines two critical callback functions: one for loading/reloading systems, handling initial setup, replacements, and new system additions with error checking; and another for unloading systems, ensuring proper eviction from the Matter ECS loop unless a reload is imminent. This enables dynamic updates to game systems without restarting the application. ```Lua local firstRunSystems = {} local systemsByModule = {} hotReloader:scan(container, function(module, context) -- The module HotReloader gives us can be a clone of the original module if it's been hot reloaded. local originalModule = context.originalModule -- Load the cloned module. If it has syntax errors, require will error. local ok, system = pcall(require, module) if not ok then warn("Error when hot-reloading system", module.name, system) return end if firstRunSystems then -- On the first run, we want to schedule all systems in one call, -- so we buffer them up and call one big `loop:scheduleSystems` at the end. table.insert(firstRunSystems, system) elseif systemsByModule[originalModule] then -- If this system was already loaded once before, we tell the loop to replace it. loop:replaceSystem(systemsByModule[originalModule], system) -- If you're also using the Matter debugger, tell the debugger the system was reloaded. -- debugger:replaceSystem(systemsByModule[originalModule], system) else -- If this is a new system (i.e., a new module was created during a hot reload), just schedule it. loop:scheduleSystem(system) end -- Keep a reference to the system, keyed by the original module, so we can detect if the system already existed -- or not systemsByModule[originalModule] = system end, function(_, context) -- This function runs when a system is being unloaded. -- context.isReloading is true if the system is about to be hot reloaded. Otherwise, it's been removed. -- If it's being hot reloaded, do nothing if context.isReloading then return end -- The system is being removed local originalModule = context.originalModule if systemsByModule[originalModule] then -- If the system was loaded, remove it from the loop loop:evictSystem(systemsByModule[originalModule]) systemsByModule[originalModule] = nil end end) ``` -------------------------------- ### Define Replicated Components List (Luau) Source: https://matter-ecs.github.io/matter/Guides/Replication This snippet defines a Luau table (array) named `REPLICATED_COMPONENTS` which lists the string names of components that are intended for replication in the Matter ECS system. This list serves as a configuration to specify which data should be synchronized between the server and clients. ```Luau local REPLICATED_COMPONENTS = { "Roomba", "Model", "Health", "Target", "Mothership", "Spinner", } ``` -------------------------------- ### Initialize Matter Debugger and Loop Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Shows how to instantiate the Matter Debugger by passing the Plasma library, retrieve its widgets, and then initialize the Matter Loop with the world, state, and debugger widgets. This sets up the core components for debugger functionality. ```Lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Packages = ReplicatedStorage.Packages local Matter = require(Packages.matter) local Plasma = require(Packages.plasma) local debugger = Matter.Debugger.new(Plasma) -- Pass Plasma into the debugger! local widgets = debugger:getWidgets() local loop = Matter.Loop.new(world, state, widgets) -- Pass the widgets to all your systems! ``` -------------------------------- ### Create In-System Debug UI Elements Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Demonstrates how to create immediate-mode UI elements like checkboxes, sliders, and buttons within a Matter system function using the debugger's UI context. It shows how to interact with world components based on UI input, with widgets only active when the debugger is open. ```Lua local function spinSpinners(world, _, ui) if ui.checkbox("Disable Spinning"):checked() then return end local transparency = ui.slider(1) local randomize = ui.button("Randomize colors!"):clicked() for id, model in world:query(Components.Model, Components.Spinner) do model.model.PrimaryPart.Transparency = transparency if randomize then model.model.PrimaryPart.BrickColor = BrickColor.random() end end end ``` -------------------------------- ### Auto-Initialize Debugger Loop Middleware Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Invokes the `autoInitialize` method on the debugger, which sets up the necessary Loop middleware to automatically activate the debugger every frame, ensuring it integrates seamlessly with the Matter game loop. ```Lua debugger:autoInitialize(loop) ``` -------------------------------- ### Matter ECS World Object Core API Reference Source: https://matter-ecs.github.io/matter/Concepts This section provides a concise reference for key methods available on the `World` object in Matter ECS. It outlines the purpose of common operations such as spawning, inserting, retrieving, removing, and despawning entities and their components, as well as checking entity existence. For a comprehensive list, users are directed to the full `World` API documentation. ```APIDOC World API Methods: spawn: spawn a new entity with given components insert: Add new or replace an existing component on an existing entity get: Get a specific component or set of components from an existing entity remove: Remove a component from an existing entity. despawn: Remove all components from an entity and delete the entity. contains: Check whether or not an entity still exists in the world. ``` -------------------------------- ### Wally Dependency Configuration for Plasma Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Configuration for Wally, the Roblox package manager, to include Plasma as a dependency for the Matter debugger. This snippet specifies the package name and its required version. ```TOML [dependencies] plasma = "matter-ecs/plasma@0.4.2" ``` -------------------------------- ### Spawn Car Component with Destinations (Lua) Source: https://matter-ecs.github.io/matter/BestPractices/StateMachines Demonstrates how to initialize a `Car` component with a list of `Vector3` destinations using `world:spawn()` in Lua. This sets up the initial state for a car's movement path. ```Lua world:spawn(Car({ destinations = {Vector3.new(0, 0, 0), Vector3.new(10, 0, 5), Vector3.new(-5, 2, 3)} })) ``` -------------------------------- ### Matter ECS: Create Data Model Instance for New Ship Entities Source: https://matter-ecs.github.io/matter/BestPractices/Reconciliation This Luau code snippet demonstrates how to reconcile new `Ship` entities in a Matter ECS world that do not yet have a corresponding `Model` component. It queries for `Ship` entities without `Model`, clones a predefined `Ship` model, parents it to the workspace, and then inserts a `Model` component referencing the newly created instance into the entity. ```Luau for id, ship in world:query(Ship):without(Model) do local model = prefabs.Ship:Clone() -- assuming prefabs is a place where you store pre-made models model.Parent = workspace world:insert(id, Model({ instance = model })) end ``` -------------------------------- ### Spawn Entity with Components in Matter ECS (Lua) Source: https://matter-ecs.github.io/matter/Concepts This Lua code demonstrates how to create a new entity within the Matter ECS `World` using the `spawn` method. It shows how to attach multiple components (e.g., `Enemy`, `Health`, `Name`, `Tree`) to the newly created entity, initializing them with specific data. The method returns the unique ID of the newly spawned entity. ```lua local newEntityId = world:spawn( Enemy(), Health({ current = 100, max = 100, }), Name({ name = "Evil Tree" }), Tree({ type = "oak" }) ) ``` -------------------------------- ### Integrate CollectionService Tags with Matter ECS in Lua Source: https://matter-ecs.github.io/matter/Guides/CollectionService This Lua code snippet demonstrates how to use Roblox's CollectionService to automatically spawn and despawn entities within the Matter ECS world based on assigned tags. It initializes components for tagged instances and handles instance addition and removal signals, linking game instances to Matter entities. ```Lua local CollectionService = game:GetService("CollectionService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Components = require(ReplicatedStorage.Game.components) local boundTags = { Spinner = Components.Spinner, } local function setupTags(world) local function spawnBound(instance, component) local id = world:spawn( component(), Components.Model({ model = instance, }), Components.Transform({ cframe = instance.PrimaryPart.CFrame, }) ) instance:SetAttribute("entityId", id) end for tagName, component in pairs(boundTags) do for _, instance in ipairs(CollectionService:GetTagged(tagName)) do spawnBound(instance, component) end CollectionService:GetInstanceAddedSignal(tagName):Connect(function(instance) spawnBound(instance, component) end) CollectionService:GetInstanceRemovedSignal(tagName):Connect(function(instance) local id = instance:GetAttribute("entityId") if id then world:despawn(id) end end) end end return setupTags ``` -------------------------------- ### Toggle Debugger with User Input Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Connects to `UserInputService.InputBegan` to toggle the debugger's visibility when the F4 key is pressed. This provides a user-facing control for activating or deactivating the debugger during gameplay. ```Lua UserInputService.InputBegan:Connect(function(input) if input.KeyCode == Enum.KeyCode.F4 then debugger:toggle() end end) ``` -------------------------------- ### Enable In-World Hover Selection (Lua) Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Describes how to implement in-world hover selection by creating `clientEntityId` and `serverEntityId` attributes on instances. Includes a Lua system function `updateModelAttribute` that sets these attributes on models when they are added or changed in the world, allowing selection when holding the ALT key. This system should be implemented on both client and server and adapted to the game's component structure. ```Lua local name = RunService:IsServer() and "serverEntityId" or "clientEntityId" local function updateModelAttribute(world) for id, record in world:queryChanged(Components.Model) do if record.new then record.new.model:SetAttribute(name, id) end end end ``` -------------------------------- ### Authorize Server-Side Debugger Access Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Defines an authorization function for the server-side debugger, allowing specific players (e.g., based on group rank) to connect in live games, overriding the default Studio-only behavior. This enables controlled access to debugging tools. ```Lua debugger.authorize = function(player) if player:GetRankInGroup(372) > 250 then -- example return true end end ``` -------------------------------- ### Correcting Control Flow: Using `continue` vs. `return` in Matter ECS Queries Source: https://matter-ecs.github.io/matter/Guides/CommonMistakes This snippet illustrates a common mistake in Matter ECS where 'return' is used instead of 'continue' inside a 'world:query' loop. Using 'return' prematurely exits the entire system function, preventing further processing of entities, whereas 'continue' correctly skips to the next iteration, allowing the system to process all relevant entities. ```Lua function mySystem(world) for id, health, poison in world:query(Health, Poison) do if not poison.active then return -- Oops! After reaching the first inactive poison, -- we're going to stop running the entire system! -- Should have used `continue` here. end world:insert(id, health:patch({ current = health.current - 1 })) end end ``` -------------------------------- ### Lua Car State Machine with Driving and Waiting Modes Source: https://matter-ecs.github.io/matter/BestPractices/StateMachines This snippet demonstrates how to implement a state machine for a 'Car' component in a Matter ECS world. It shows initial spawning of a car with destinations and a 'driving' mode, followed by a game loop that queries for cars and updates their state between 'driving' and 'waiting' based on arrival at destinations or elapsed wait time. The 'mode' property and 'startedWaiting' timestamp manage the car's current behavior. ```Lua world:spawn(Car({ destinations = {Vector3.new(0, 0, 0), Vector3.new(10, 0, 5), Vector3.new(-5, 2, 3)}, mode = "driving" })) ----- for id, car, model in world:query(Car, Model) do if car.mode == "waiting" then if os.clock() - car.startedWaiting > 5 then -- Wait 5 seconds world:insert(id, car:patch({ mode = "driving", startedWaiting = Matter.None })) end elseif car.mode == "driving" then if #car.destinations == 0 then world:despawn(id) continue end local currentPosition = model.model.PrimaryPart.Position if (currentPosition - car.destinations[1]).magnitude < 2 then -- Arrived table.remove(car.destinations, 1) world:insert(id, car:patch({ mode = "waiting", startedWaiting = os.clock() })) continue end model.model.PrimaryPart.BodyPosition.Position = car.destinations[1] --example end end ``` -------------------------------- ### Highlight Selected Entity in World Inspector (Lua) Source: https://matter-ecs.github.io/matter/Guides/MatterDebugger Provides a function `findInstanceFromEntity` for the debugger to locate and return a model instance associated with a given entity ID, enabling highlighting in the World inspector. This function needs to be adapted to the game's specific component structure. ```Lua debugger.findInstanceFromEntity = function(id) if not world:contains(id) then return end local model = world:get(id, components.Model) return model and model.model or nil end ``` -------------------------------- ### Lua System for Car Movement and Destination Handling Source: https://matter-ecs.github.io/matter/BestPractices/StateMachines Illustrates a Lua system that queries `Car` and `Model` components, moves the car towards its current destination, removes destinations upon arrival, and despawns the entity when all destinations are reached. This system progresses the car's state through its defined path. ```Lua for id, car, model in world:query(Car, Model) do local currentPosition = model.model.PrimaryPart.Position if (currentPosition - car.destinations[1]).magnitude < 2 then -- Arrived table.remove(car.destinations, 1) if #car.destinations == 0 then world:despawn(id) continue end end model.model.PrimaryPart.BodyPosition.Position = car.destinations[1] --example end ``` -------------------------------- ### Demonstrating unintended queryChanged behavior with early return Source: https://matter-ecs.github.io/matter/Guides/CommonMistakes This Lua function `mySystem` illustrates how an early return condition, controlled by `useThrottle(1)`, can disrupt the topologically-aware state of `world:queryChanged(Health)`. When the `for` loop is skipped, `queryChanged`'s internal state is cleaned up, causing it to re-iterate over *every* health component as if they were new the next time the loop executes. ```Lua function mySystem() if useThrottle(1) then for id, health in world:queryChanged(Health) do -- Uh oh! Every time this runs, *every* health component will be looped over. -- The for loop runs only once per second, which means that on next frame where this code -- isn't reached, the storage for queryChanged is cleaned up. end end end ``` -------------------------------- ### Matter ECS: Despawn Ship Entity on Data Model Instance Touch Event Source: https://matter-ecs.github.io/matter/BestPractices/Reconciliation This Luau code snippet demonstrates how to handle events from the Data Model back into the Matter ECS. It queries for entities with both `Model` and `Ship` components. For each such entity, it uses `Matter.useEvent` to listen for the 'Touched' event on the associated `model.Instance`. If the instance is touched, the corresponding ECS entity is despawned from the world. ```Luau for id, model in world:query(Model, Ship) do for _ in Matter.useEvent(model.Instance, "Touched") do world:despawn(id) end end ``` -------------------------------- ### Implement Health Regeneration System in Luau Source: https://matter-ecs.github.io/matter/Concepts This Luau code snippet demonstrates a Matter ECS system that regenerates health for entities possessing a 'Health' component. It iterates through all entities with health, checks if their current health is below maximum, and incrementally increases it by 0.1% of max health per frame, capping at the maximum. It utilizes the `world:query` method to efficiently select relevant entities. ```Luau for id, health in world:query(Health) do if health.current < health.max then world:insert(id, health:patch({ -- Regenerate 0.1% of maximum health per frame current = math.min(health.max, health.current + (health.max * 0.001)) }) end end ``` -------------------------------- ### Calculate Player Walk Speed Based on Status Effects (Lua) Source: https://matter-ecs.github.io/matter/BestPractices/DerivedState This Lua code snippet defines a system that calculates a player's effective walk speed. It queries for entities with a 'Player' component and checks for the presence of 'Poison' or 'HeavyWeapon' components. For each affecting component found, the base walk speed is halved. The final calculated speed and modifier are then inserted as a 'WalkSpeed' component on the entity. A crucial note is included about iterating over tables that might contain nil values. ```Lua local affectsWalkSpeed = {Poison, HeavyWeapon} local function walkSpeed(world) for id, player in world:query(Player) do local results = {world:get(id, unpack(affectsWalkSpeed))} -- NOTE: You can't be tricky by just checking the length of this table! -- We MUST iterate over it because the Lua length operator does not work -- as you might expect when a table has nil values in it. -- See for yourself: Lua says #{nil,nil,nil,1,nil} is 0! local modifier = 1 for _ in results do -- For each result, reduce speed by half. modifier *= 0.5 end -- The default Roblox walk speed is 16 local speed = 16 * modifier world:insert(id, WalkSpeed({ speed = speed, modifier = modifier, })) end end return walkSpeed ``` -------------------------------- ### Apply Calculated Walk Speed to Humanoid Model (Lua) Source: https://matter-ecs.github.io/matter/BestPractices/DerivedState This Lua code snippet demonstrates a separate system responsible for applying the 'WalkSpeed' component's calculated value to a player's actual Roblox 'Humanoid' model. It queries for entities that possess both a 'WalkSpeed' component (derived from the previous system) and a 'Model' component, then updates the 'Humanoid.WalkSpeed' property if a Humanoid object is found within the model. ```Lua -- Update anything with WalkSpeed and Model (this could be a separate system) for id, walkSpeed, model in world:query(WalkSpeed, Model) do if model.model:FindFirstChild("Humanoid") then model.model.Humanoid.WalkSpeed = walkSpeed.speed end end ``` -------------------------------- ### Matter ECS: Update Data Model Instance Position for Ship Entities Source: https://matter-ecs.github.io/matter/BestPractices/Reconciliation This Luau code snippet shows how to continuously update the position of a Data Model instance associated with a `Ship` entity in a Matter ECS world. It queries for entities possessing both `Ship` and `Model` components, then sets the `Position` property of the `BodyPosition` within the `model.instance` to the `ship.goalPosition`, ensuring the physical model reflects the ECS state. ```Luau for id, ship, model in world:query(Ship, Model) do model.instance.BodyPosition.Position = ship.goalPosition end ``` -------------------------------- ### Matter ECS: Destroy Data Model Instance on Model Component Removal Source: https://matter-ecs.github.io/matter/BestPractices/Reconciliation This Luau code snippet implements a system to automatically destroy Data Model instances when their corresponding `Model` component is removed or an entity is despawned in a Matter ECS world. It uses `queryChanged(Model)` to detect changes, and if a `Model` component's `new` state is `nil` (meaning it was removed) while an `old` instance existed, it calls `Instance:Destroy()` on that old instance to clean up the physical representation. ```Luau for _id, modelRecord in world:queryChanged(Model) do if modelRecord.new == nil then if modelRecord.old and modelRecord.old.instance then modelRecord.old.instance:Destroy() end end end ``` -------------------------------- ### Synchronize Transform and Model Components with Two-Way Binding in Matter ECS Source: https://matter-ecs.github.io/matter/BestPractices/Reconciliation This system provides a robust two-way binding mechanism between a 'Transform' component (holding CFrame data) and a physical 'Model' instance. It handles three main cases: updating the model when the Transform component changes, updating the model when the Model component is added (if a Transform exists), and updating the Transform component when an unanchored Model moves due to physics. It includes logic to prevent reconciliation loops. ```Luau -- Handle Transform added/changed to existing entity with Model for id, transformRecord in world:queryChanged(Transform) do local model = world:get(id, Model) -- Take care to ignore the changed event if it was us that triggered it if model and transformRecord.new and not transformRecord.new.doNotReconcile then model.instance:SetPrimaryPartCFrame(transformRecord.new.cframe) end end -- Handle Model added/changed on existing entity with Transform for id, modelRecord in world:queryChanged(Model) do local transform = world:get(id, Transform) if transform and modelRecord.new then modelRecord.new.model:SetPrimaryPartCFrame(transform.cframe) end end -- Update Transform on unanchored Models for id, model, transform in world:query(Model, Transform) do if model.instance.PrimaryPart.Anchored then continue end local existingCFrame = transform.cframe local currentCFrame = model.instance.PrimaryPart.CFrame -- Only insert if actual position is different from the Transform component if currentCFrame ~= existingCFrame then world:insert( id, Components.Transform({ cframe = currentCFrame, doNotReconcile = true, }) ) end end ``` -------------------------------- ### Correct Component Update and Reassignment in Matter ECS Source: https://matter-ecs.github.io/matter/Guides/CommonMistakes This snippet illustrates the correct pattern for updating immutable components in Matter ECS. After patching the component, the `health` variable is explicitly reassigned to the new, updated component. This ensures that any subsequent operations or checks using `health` refer to the current state of the component in the world, preventing the use of outdated data. ```Lua local health = world:get(id, Health) health = health:patch({ current = health.current - 10 }) world:insert(id, health) if health.current < 0 then -- ... end ``` -------------------------------- ### Remove Stale Models from World in Matter ECS Source: https://matter-ecs.github.io/matter/BestPractices/Reconciliation This snippet demonstrates how to identify and remove 'Model' instances that are no longer part of the game world, often due to physics interactions causing them to fall out of bounds. It iterates through all models and removes those whose instances are not descendants of the game object. Be aware that this can lead to models being instantly recreated if manually deleted in Studio, and may cause infinite loops if the last Transform was invalid. ```Luau for id, model in world:query(Model) do if model.instance:IsDescendantOf(game) == false then world:remove(id, Model) end end ``` -------------------------------- ### Incorrect Component Update and Usage in Matter ECS Source: https://matter-ecs.github.io/matter/Guides/CommonMistakes This snippet demonstrates a common pitfall when updating immutable components in Matter ECS. The `health` variable retains the old component reference even after a new, patched component is inserted into the world. Subsequent checks using `health.current` will operate on outdated data, leading to logical errors because the variable was not updated to reflect the new component state. ```Lua local health = world:get(id, Health) world:insert(id, health:patch({ current = health.current - 10 })) -- ...and then attempt to use the `health` variable later: if health.current < 0 then -- ... end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.