roblox-physics
Original:🇺🇸 English
Translated
Physics and spatial queries - Raycast/Blockcast/Spherecast, overlap queries, collision groups, Touched pitfalls, assemblies and welds, mover constraints replacing BodyMovers, mechanical constraints, network ownership, CFrame math, vehicles/projectiles, and server authority (BindToSimulation, prediction, rollback). Use when moving parts, detecting hits, building vehicles or projectiles, or fixing jitter, flinging, or ownership bugs.
8installs
Sourceel4cteo/roblox-skills
Added on
NPX Install
npx skill4agent add el4cteo/roblox-skills roblox-physicsTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Roblox physics and spatial queries
Spatial queries (use these, not Touched, for gameplay decisions)
luau
--!strict
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {} -- e.g. { character } of the shooter
params.IgnoreWater = true
local function castRay(origin: Vector3, direction: Vector3): RaycastResult?
-- direction's length is the max distance
return workspace:Raycast(origin, direction, params)
end
local result = castRay(Vector3.new(0, 50, 0), Vector3.new(0, -100, 0))
if result then
print(result.Instance, result.Position, result.Normal, result.Material, result.Distance)
end
-- Swept volumes: thick bullets, melee arcs, ground checks with width.
local sphereHit = workspace:Spherecast(Vector3.new(0, 10, 0), 2, Vector3.new(0, 0, 50), params)
local boxHit = workspace:Blockcast(CFrame.new(0, 10, 0), Vector3.new(4, 4, 4), Vector3.new(0, 0, 50), params)
-- Volume overlap: explosions, hitboxes, zone checks.
local overlap = OverlapParams.new()
overlap.FilterType = Enum.RaycastFilterType.Exclude
overlap.MaxParts = 50
local partsInBox = workspace:GetPartBoundsInBox(CFrame.new(0, 5, 0), Vector3.new(10, 10, 10), overlap)
local partsInSphere = workspace:GetPartBoundsInRadius(Vector3.zero, 15, overlap)
print(sphereHit, boxHit, #partsInBox, #partsInSphere)- Reuse params objects; update (or
FilterDescendantsInstances) instead of allocating per call.params:AddToFilter(instance) - to ignore non-collidable parts;
RespectCanCollide = trueto query as a group.CollisionGroup = "Name" - does exact geometry overlap (costlier);
GetPartsInPart(part, params)use bounding boxes.GetPartBoundsIn* - Deprecated: ,
FindPartOnRay*,Ray.new→ use the APIs above.FindPartsInRegion3* - Client queries only see streamed-in parts; authoritative checks run on the server.
Touched: know its limits
Touchedluau
--!strict
local Players = game:GetService("Players")
local pad = Instance.new("Part")
pad.Anchored = true
pad.Parent = workspace
local recently: { [Player]: boolean } = {}
pad.Touched:Connect(function(hit)
local character = hit:FindFirstAncestorOfClass("Model")
local player = character and Players:GetPlayerFromCharacter(character)
if not player or recently[player] then
return
end
recently[player] = true
print(`{player.Name} stepped on the pad`)
task.delay(1, function()
recently[player] = nil
end)
end)Collision groups
luau
--!strict
-- Collision group APIs now live on WorldRoot (workspace); the PhysicsService versions are superseded.
workspace:RegisterCollisionGroup("Players")
workspace:RegisterCollisionGroup("Ghosts")
workspace:CollisionGroupSetCollidable("Players", "Ghosts", false)
local ghost = Instance.new("Part")
ghost.CollisionGroup = "Ghosts" -- assign by name (CollisionGroupId/SetPartCollisionGroup are deprecated)
ghost.Parent = workspaceRegister groups once at server start (max 32, see ). removes all collisions;
hides a part from raycasts; disables (saves CPU);
disables collision between two specific parts.
workspace:GetMaxCollisionGroups()CanCollide = falseCanQuery = falseCanTouch = falseTouchedNoCollisionConstraintAssemblies and joints
- An assembly = parts rigidly connected (welds, ,
WeldConstraint, rigid constraints). It simulates as one body; the root part (Motor6D) determines network ownership.part.AssemblyRootPart - Anchor static geometry. Unanchored + welded to an anchored part = anchored assembly.
- Weld at edit time with (keeps current offset); in code set
WeldConstraint/Part0and parent.Part1 - Move whole models with . Moving many parts at once:
model:PivotTo(cframe).workspace:BulkMoveTo - Read/set physics via /
AssemblyLinearVelocity,AssemblyAngularVelocity,part:ApplyImpulse(),ApplyAngularImpulse().AssemblyMass/Velocityare deprecated.RotVelocity - .
CustomPhysicalProperties = PhysicalProperties.new(density, friction, elasticity, frictionWeight, elasticityWeight) - Units: 1 stud ≈ 0.28 m, default 196.2 studs/s².
workspace.Gravity
Mover constraints (replace BodyMovers)
| Goal | Constraint | Replaces |
|---|---|---|
| Hold/drive a velocity | | |
| Move toward a position | | |
| Rotate toward an orientation | | |
| Constant force | | |
| Spin | | |
| Pull toward point | | |
| Torque | | — |
All need an (). Set / realistically (not
unless intended) or objects fling. Mechanical constraints: (Motor/Servo actuators for
wheels, doors), (sliders, elevators), (suspension),
, , , (wheel + steering),
, .
AttachmentAttachment0MaxForceMaxTorquemath.hugeHingeConstraintPrismaticConstraintSpringConstraintRopeConstraintRodConstraintBallSocketConstraintCylindricalConstraintUniversalConstraintRigidConstraintVehicle and projectile recipes, CFrame cookbook: references/recipes.md.
Network ownership
- The server auto-assigns ownership of unanchored assemblies to a nearby client (smooth for that client, exploitable by it). Characters are owned by their player.
- = server simulates (secure, laggier for players);
part:SetNetworkOwner(nil)for a vehicle driver;SetNetworkOwner(player)to restore. Call on the root part, server-side, after the assembly is inSetNetworkOwnershipAuto(). Anchored parts have no owner.Workspace - Ownership changes cause hitches; don't flip it every frame. Visualize with the viewport's Visualization options → Network owners toggle.
Server authority (competitive games)
Workspace makes the server simulate everything while clients predict a few
frames ahead and roll back/resimulate on mispredictions. Requirements: ,
, , ,
(setting sets these). Core rules:
AuthorityMode = ServerNextGenerationReplicationPlayerScriptsUseInputActionSystemSignalBehavior = DeferredUseFixedSimulationStreamingEnabledAuthorityMode- Game logic lives in functions bound with inside a ModuleScript required by both server and client.
RunService:BindToSimulation(fn) - Clients affect the game only through Input Actions (InputContexts parented under the ), not
Playerevents.UserInputService - Sync custom state through attributes on predicted instances, written only inside simulation callbacks.
- Don't cache s; query
AnimationTrackeach step.Animator:GetTrackByAnimationId()
Rollout status can change — check the docs. Details and patterns: references/server-authority.md.
Stability tips
- Jitter: conflicting ownership, constraints fighting, huge mass ratios (> 1:100), or setting CFrame on unanchored parts every frame (use constraints instead).
- Flinging: on light parts, overlapping collisions at spawn, NaN/huge velocities.
MaxForce = math.huge - Sleeping assemblies stop simulating until disturbed — wake with a small impulse if needed.
- Adaptive timestepping () saves CPU; use fixed for precise mechanisms.
Workspace.PhysicsSteppingMethod = Adaptive
Related skills
roblox-securityroblox-characters-animationroblox-networkingroblox-performanceroblox-input