Physics and spatial queries¶
Nova uses the classic PGS solver, with modern solver-selection and era rules
layered on top. Workspace.Gravity, FallenPartsDestroyHeight, part
properties, joints, and the legacy BodyMover family work.
What is present¶
BasePartphysics properties:Anchored,CanCollide,Massless,Velocity,RotVelocity,CustomPhysicalProperties,CollisionGroup,CollisionGroupId.- Joints:
Weld,Motor6D,WeldConstraint,Snap,Rotate,Glue,ManualWeld. - Constraints:
HingeConstraint,BallSocketConstraint,SpringConstraint,RopeConstraint,AlignPosition,AlignOrientation,LinearVelocity,AngularVelocity,VectorForce, and the rest of the current class list. - Body movers:
BodyPosition,BodyGyro,BodyVelocity,BodyForce,BodyThrust. Terrain,Region3,Ray,PhysicalProperties, collision groups onBasePart.
What is missing¶
WorldRootand the modern spatial-query family:Raycast,Blockcast,Spherecast,Shapecast,GetPartBoundsInBox,GetPartsInPart.RaycastParams,RaycastResult,OverlapParams.PrismaticConstraint,CylindricalConstraint,UniversalConstraint,PlaneConstraint.- The modern
PhysicsServicecollision-group methods.BasePart.CollisionGroupandCollisionGroupIdexist, butCreateCollisionGroupand friends are not exposed.
Raycasting¶
The modern API:
-- Roblox
local params = RaycastParams.new()
params.FilterDescendantsInstances = { character }
params.FilterType = Enum.RaycastFilterType.Exclude
local result = workspace:Raycast(origin, direction, params)
if result then
print(result.Instance, result.Position, result.Normal)
end
The Nova equivalent:
local function raycast(origin: Vector3, direction: Vector3, ignore: { Instance })
local ray = Ray.new(origin, direction)
-- Returns: part, position, normal, material
local part, position, normal, material =
workspace:FindPartOnRayWithIgnoreList(ray, ignore, false, true)
if part then
return {
Instance = part,
Position = position,
Normal = normal,
Material = material,
}
end
end
local hit = raycast(
camera.CFrame.Position,
camera.CFrame.LookVector * 500,
{ character }
)
if hit then
print(hit.Instance:GetFullName(), hit.Position)
end
FindPartOnRay is the simpler version without an ignore list:
The terrainCellsAreCubes and ignoreWater arguments default to false. Pass
true for ignoreWater if you do not want water hits.
Region queries¶
FindPartsInRegion3WithIgnoreList is the replacement for
GetPartBoundsInBox/GetPartsInPart:
local function partsInBox(center: Vector3, size: Vector3, ignore: { Instance })
local half = size / 2
local region = Region3.new(center - half, center + half)
-- The last argument caps the number of returned parts.
return workspace:FindPartsInRegion3WithIgnoreList(region, ignore, 100)
end
To test whether a region is empty, use IsRegion3EmptyWithIgnoreList. For
terrain-specific queries, the legacy methods still use Region3.
Collision groups¶
Parts have a CollisionGroup name and a numeric CollisionGroupId. The modern
management API is not exposed, so treat collision groups as a property set by
the place/Studio rather than something a game script configures at runtime.
Solver behavior¶
Nova uses PGS. The classic Workspace.PGSPhysicsSolverEnabled property was
removed from Roblox in 2019; Nova follows the modern behavior and auto-enables
PGS for era-dated saves. Workspace:PGSIsEnabled() is available for scripts that
need to inspect it.
Do not port assumptions that depend on a specific modern solver iteration count, sleep behavior, or network-ownership heuristic. Re-test vehicles, ragdolls, and stacked parts in Nova; expect small differences.
Common porting problems¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Parts pass through each other | CanCollide off, or both parts anchored, or collision group mismatch |
Check properties and collision groups. |
| A ray never hits | Direction is zero, or the origin is inside the target | Normalize the direction and offset the origin. |
| Ray hits the character | Missing ignore list | Pass the character (and its descendants) to FindPartOnRayWithIgnoreList. |
| Vehicle behaves differently | Solver/constraint differences | Re-tune forces; prefer constraints over BodyMovers. |
| Region query returns nothing | Region3 bounds are inverted |
Build from center - half and center + half. |