Shape

Shape extends Object, adding functions and properties to it.

A Shape is an Object that carries a voxel model made of Blocks.

It introduces an additional coordinate system called model space i.e. relative to model origin.
Any point can be expressed in model space. If the point is expressed with integers, then it may represent a Block coordinates.

Note that if the Shape.Pivot is set to zero, then model space and local space become equivalent.

Constructors

Shape ( table config optional )
Shape ( Item item, table config optional )
Shape ( Shape copiedShape, table config optional )
Shape ( MutableShape copiedMutableShape, table config optional )

Creates a Shape which model can be empty, loaded from an imported Item (see Items), or copied from an existing Shape or MutableShape.

The optional table parameter can be used to override default configuration: {includeChildren = false, bakedLight = false}.
- includeChildren (false by default) will load all children of the original shape recursively.
- bakedLight (false by default) determines whether or not the shape should be loaded with baked lighting. If true, it will use the baked lighting information saved with the original item, or compute it from scratch if there was none. Any subsequent changes to the shape's blocks will automatically maintain its baked lighting.

When copying a Shape, includeChildren (false by default) determines if children should be copied as well.

-- CREATE SHAPE FROM LOADED ITEM
local myShape = Shape(Items.someuser.someitem)
World:AddChild(myShape) -- adds created Shape to the World
-- COPY SHAPE, INCLUDING CHILDREN:
local s2 = Shape(s1, {includeChildren = true})
World:AddChild(s2) -- adds copied Shape to the World

Functions

Converts Block coordinates from model space to local space.

Converts Block coordinates from model space to world space.

Removes the shape baked lighting and frees up any memory used. It could be an optimization step for scenes pooling a large amount of shapes.

Client.OnStart = function()
  Map.Palette[1].Light = true

  -- refresh baked lighting for existing blocks
  Map:ComputeBakedLight(function() print("Map baked lighting done!") end)
end

Computes the shape baked lighting. It is a combination of a white ambient light and all blocks that were set as light sources. Other shapes entering inside this shape's bounding box will be affected by its baked lighting.

This is an efficient way of applying lighting to shapes without affecting performance. The baked lighting of a shape is cached to speed up subsequent loads.

Once a shape has baked lighting, it will be automatically maintained when changing its blocks.

However, directly changing the transparency or light properties of shape's Palette entries of _existing_ blocks will not be reflected on the shape immediately, and will require another call to this function.

You may want to call this function only if:
- activating baked lighting on a shape for the first time
- setting light property i.e. shape.Palettei.Light = true/false of _existing_ shape blocks
- setting transparency i.e. shape.Palettei.Color.A = newValue of _existing_ shape blocks

You _do not_ need to call this function if:
- ANY blocks, including light and transparent blocks, are added/removed at runtime
- setting light or transparent property of an unused palette entry first, before adding blocks using that entry

Computes and returns the smallest axis-aligned box that encompasses all of Shape's blocks, in local space.

Computes and returns the smallest axis-aligned box that encompasses all of Shape's blocks, in world space.

nil FitToScreen ( Camera camera, number screenRatio optional, boolean spherize optional )

Fits the Shape to the given Camera's view'. This function moves the shape back until it fits on the camera view.

Optional parameters:
- screenRatio indicates the percentage of the screen that should be covered by the target.
- spherize switches between box fit (false) and sphere fit (true), spherize can be useful if the function is used every frame on a moving object, for smoother motion, but the fit will be wider.

Block GetBlock ( Number3 coordinates )

Gets a Block from the Shape.
Returned Block is read-only because Shape is immutable, unlike MutableShape.
Returns nil if there is no Block at those coordinates (i. e. if it's "air").

Converts a point from local space to model space.

Converts a point from world space to model space.

Inherited from Object

Hide

nil AddChild ( Object child, boolean keepWorld optional )

Adds given Object as a child. Object extensions like Shape or MutableShape are naturally accepted too.

The keepWorld optional parameter, false by default, dictates whether to maintain the child's world or local position and rotation. Keeping world will ensure the object doesn't move in the scene, adjusting its local position/rotation accordingly; keeping local will have the object move in the scene in order to maintain an equivalent local position/rotation relative to its new parent.

local o = Object()
local myShape = Shape(Items.someuser.someitem)
o:AddChild(myShape)
nil RemoveChild ( Object child, boolean keepWorld optional )

Unsets parent/child relationship with child parameter. The child ends up being deleted if it has no other references.

The keepWorld optional parameter, false by default, dictates whether to maintain the child's world or local position and rotation. Keeping world will ensure the object doesn't move in the scene, adjusting its local position/rotation accordingly; keeping local will have the object move in the scene in order to maintain an equivalent local position/rotation relative to its new parent.

o:RemoveChild(someChildObject)
nil RemoveChildren ( boolean keepWorld optional )

Unsets parent/child relationship with all children. Individual children end up being deleted if they have no other references.

The keepWorld optional parameter, false by default, dictates whether to maintain the child's world or local position and rotation. Keeping world will ensure the object doesn't move in the scene, adjusting its local position/rotation accordingly; keeping local will have the object move in the scene in order to maintain an equivalent local position/rotation relative to its new parent.

o:RemoveChildren()
nil GetChild ( integer index )

Get child Object at index.

if o.ChildrenCount > 0 then
  print(o:GetChild(1)) -- prints first child
end

Get Shape's parent.

print(myObject:GetParent())
nil SetParent ( Object parent, boolean keepWorld optional )

Sets parent/child relationship with parent parameter. nil can be used to remove the Object from its parent.

The keepWorld optional parameter, false by default, dictates whether to maintain the child's world or local position and rotation. Keeping world will ensure the object doesn't move in the scene, adjusting its local position/rotation accordingly; keeping local will have the object move in the scene in order to maintain an equivalent local position/rotation relative to its new parent.

It's also a good practice to set child/parent relationships before setting positions.

local o = Object()
o:SetParent(Map) -- o is now a child of the map
-- (Map is an extension of Object)
nil RemoveFromParent ( boolean keepWorld optional )

Removes the Shape from its parent. Doesn't do anything if the Shape has no parent.

The keepWorld optional parameter, false by default, dictates whether to maintain the child's world or local position and rotation. Keeping world will ensure the object doesn't move in the scene, adjusting its local position/rotation accordingly; keeping local will have the object move in the scene in order to maintain an equivalent local position/rotation relative to its new parent.

o:RemoveFromParent()

Converts a local position to world coordinate system.

local p = Number3(1, 2, 3)
local pInWorldCoords = myObject:PositionLocalToWorld(p)

Converts a world position to local coordinate system.

local p = Number3(1, 2, 3)
local pInLocalCoords = myObject:PositionWorldToLocal(p)

Rotates the Shape in its own coordinates system.

o = Object()
-- rotate with provided Euler angle
o:RotateLocal({0, 0, math.pi / 2.0})

-- rotate along specified axis
o:RotateLocal(o.Forward, math.pi / 2.0)

Rotate the Shape in the World coordinates system.

o = Object()
-- rotate with provided Euler angles
o:RotateWorld({0, 0, math.pi / 2.0})

-- rotate along specified axis
o:RotateWorld(o.Forward, math.pi / 2.0)
-- same as o:RotateLocal({0, 0, 1}, math.pi / 2.0)

Converts a rotation from local to world relative to this object.

Converts a rotation from world to local relative to this object.

Returns true if the two Objects may collide with each other.

nil ApplyForce ( Object self, Number3 value )

Apply a force to Object, taking into account its Mass.

Resets to Shape's original collision box. For example, Player and Shape objects will revert to fitting their model bounding box.

Properties

integer BlocksCount read-only

The number of blocks in Shape's model.

Box BoundingBox read-only

The bounding box represents the bounds of the Shape in model space.

It is the smallest axis-aligned box that encompasses all of Shape's blocks.

Number3 Center read-only

The center of the Shape's BoundingBox.

number Depth read-only

Returns Shape's depth, measured in blocks.

number Height read-only

Returns Shape's height, measured in blocks.

Whether or not inner faces between blocks of different colors should be drawn for this shape, true by default.

Whether or not the Shape should ignore scene lighting, false by default.

Original item name of this shape. If it was created programmatically, item name is nil.

Integer or table of integers between 1 and 12. Cameras only render shapes corresponding to their layers, and lights only affect shapes in matching layers.

Number3 Max read-only

The maximum point of the Shape's BoundingBox.

Number3 Min read-only

The minimum point of the Shape's BoundingBox.

Palette is an array of BlockProperties, with each entry corresponding to a style of block used by the Shape's model. Each of the Shape's block use a palette index, indicating which entry to use to draw that block.

If Shape.Palette is set, the shape will start using the new palette in place. Each of its block's palette index will then point to the BlockProperties of that new palette. This can be used to share a single palette between multiple shapes, for example to create effects by changing color on a whole group of shapes at once.
Note that if you would like to keep the original colors of the shape while assigning another palette, you should use the Palette.Merge function instead.

Shape's pivot is a local point that acts as a reference for its transformations:
- translation is applied from its parent's pivot to its own pivot
- rotation is applied around the pivot

It is set by default to Shape's geometric center.

You can override it with any point, even outside of the Shape's bounding box, as a way to modify how transformations are applied.
Note that setting the pivot to zero effectively means you are using the Shape's model origin as reference point for transformations.

-- set it to any arbitrary point
myShape.Pivot = { 2.3, 5.0, 1.5 }
-- set it to a specific block, it will use block's center (*)
myShape.Pivot = myShape:GetBlock(1, 1, 1)
-- doing this resets pivot to its default value (*)
myShape.Pivot = { myShape.Width * 0.5, myShape.Height * 0.5, myShape.Depth * 0.5 }
-- (*) both these use-cases are valid only if myShape is not mutable or is mutable but has not been changed,
-- otherwise, it is still possible: pivot must first be set to zero, then convert with myShape:BlockToLocal

Whether or not the shape should cast shadows. Light objects set as shadow casters will affect all shapes in matching layers.

Number3 Size read-only

Returns Shape's model bounding box size, measured in blocks. Equivalent to Number3(shape.Width, shape.Height, shape.Depth).

number Width read-only

Returns Shape's width, measured in blocks.

Inherited from Object

Hide

Shape's constant acceleration in world coordinates per second squared.

⚠️ Acceleration will only affect Shape's position while Shape.Physics is true.

-- Acceleration can be used to compensate gravity: 
myObject.Acceleration = -Config.ConstantAcceleration
-- myObject's acceleration is now the invert of 
-- Config.ConstantAcceleration, cancelling it.

Collision groups the Shape belongs to.

⚠️ It doesn't mean the Shape will collide with other Objects in these groups.

If the Shape belongs to group number 3 for example, it means all Objects that have group number 3 in their Object.CollidesWithGroups property will collide with it.

By default:
- Objects collide with the Map and other Objects
- Players collide with the Map only

That can all be configured differently depening on your needs.

local object1 = Object()
local object2 = Object()
-- It's not mandatory to set Physics to true
-- An object with Physics set to false contributes to the
-- physics simulation as a static item (can't be moved)
object1.Physics = true
object2.Physics = true

-- making sure 2 objects collide with each other
-- NOTE: by default:
-- Map.CollisionGroups == {1},
-- Player.CollisionGroups == {2},
-- Object.CollisionGroups == {3}
object1.CollisionGroups = {5}
object2.CollisionGroups = {5}
object1.CollidesWithGroups = {1, 5} -- collides with Map + objects in group 5
object2.CollidesWithGroups = {1, 5} -- collides with Map + objects in group 5

-- would also work this way if you don't 
-- remember Map's group (which can be changed too by the way)
object1.CollidesWithGroups = Map.CollisionGroups + {5}

-- making an object collides with the Map and Players
local object = Object()
object.CollidesWithGroups = Map.CollisionGroups + Player.CollisionGroups

-- for Player (local player) to collide with other players and the Map
Player.CollidesWithGroups = Map.CollisionGroups + Player.CollisionGroups

Collision groups the Shape collides with.

By default:
- Objects collide with the Map and other Objects
- Players collide with the Map and the Objects

That can all be configured differently depending on your needs.

local object = Object()

-- It's not mandatory to change Physics value.
-- (default value is PhysicsMode.Static)
-- An object with Physics set to PhysicsMode.Static contributes 
-- to the physics simulation as a static item (can't be moved)
object.Physics = PhysicsMode.Dynamic

-- making an object collide with the Map and Players
object.CollidesWithGroups = Map.CollisionGroups + Player.CollisionGroups

-- for an Object to collide with other objects only
-- (won't collide with the map)
object.CollidesWithGroups = object.CollisionGroups

-- for Player (local player) to collide with other players and the Map
Player.CollidesWithGroups = Map.CollisionGroups + Player.CollisionGroups

-- making sure 2 objects collide with each others
-- NOTE: by default:
-- Map.CollisionGroups == {1},
-- Player.CollisionGroups == {2},
-- Object.CollisionGroups == {3}
local object1 = Object()
local object2 = Object()
object1.CollisionGroups = {5}
object2.CollisionGroups = {5}
object1.CollidesWithGroups = {1, 5} -- collides with Map + objects in group 5
object2.CollidesWithGroups = {1, 5} -- collides with Map + objects in group 5

-- would also work this way if you don't 
-- remember Map's group (which can be changed too by the way)
object1.CollidesWithGroups = Map.CollisionGroups + {5}

Sets the simulation mode for this object, it can be one of the following:
- PhysicsMode.Disabled: excluded from all physics features.
- PhysicsMode.Trigger: Shape's collision box is available for casts and collision callbacks, and is passed through by other dynamic objects.
- PhysicsMode.TriggerPerBlock: if Shape is a Shape, its model blocks are available for casts and collision callbacks, and is passed through by other dynamic objects.
- PhysicsMode.Static: Shape's collision box is available for casts, collision callbacks, and acts as an obstacle for other dynamic objects.
- PhysicsMode.StaticPerBlock: if Shape is a Shape, its model blocks are available for casts, collision callbacks, and act as obstacles for other dynamic objects.
- PhysicsMode.Dynamic: Shape's world-aligned collision box is available for casts, collision callbacks, may act as obstacles for other dynamic objects, and is itself fully simulated.

By default, objects are set to PhysicsMode.Static.

You may use Dev.DisplayColliders to visualize each object's collision settings.

⚠️ When set to PhysicsMode.Disabled, Shape.Velocity & Shape.Motion are set to {0,0,0}.

nil by default. Can be set to a function that will be triggered when this object begins a collision with another object.

The function is called with 3 parameters:
- the object the callback was set for,
- the other actor in the collision,
- the world normal of the hit surface.

Note: it's not necessary to use all 3 parameters.

object.OnCollisionBegin = function(self, other, normal)
  print("collision began between", self, " and ", other, " with world normal ", normal)
end

nil by default. Can be set to a function that will be triggered every frame where this object remains in contact with another object.

Like OnCollisionBegin, this function has 3 arguments: self, other, normal.

nil by default. Can be set to a function that will be triggered when the Shape ends colliding with another Object.

The function is called with 2 parameters: the object the callback was set for and the other actor in the collision.

object.OnCollisionEnd = function(self, other)
  print("collision ended between", self, "and", other)
end

Executed when the Pointer is dragged (moved while down). Receives a PointerEvent parameter, just like Pointer.Drag.

(nil by default)

myObject.OnPointerDrag = function(pointerEvent)
  print("dx:", pointerEvent.DX, "dy:", pointerEvent.DY)
end

Position of the Shape in the world.

local o = Object()
-- places the object where the local player is
o.Position = Player.Position
boolean IsOnGround read-only

true when the Shape is not falling.

⚠️ IsOnGround only makes sense when Shape.Physics is true.

Can be set to true for the Shape to be hidden recursively, meaning Shape and all of its children are hidden.

Nothing else changes, the Shape remains in the scene and it keeps being affected by the simulation (collisions, etc.).

Can be set to true for the Shape to be hidden individually.

Nothing else changes, the Shape remains in the scene and it keeps being affected by the simulation (collisions, etc.).

Size in world units of the shadow cookie projected under the Shape, default is 0.0 (disabled).
The shadow cookie, also called blob shadow, is a square texture acting as a cheap alternative to projected shadows.

If this value is strictly positive, shadow cookies will be displayed when:
- the scene has no light source,
- the scene has light sources, but they are disabled because the client is using lower quality settings

Shadow cookies can be used as a fallback to your scene shadows for players with low quality settings, of course, you can also use them instead of shadows as a design choice.

Local position of the Shape relative to its parent.

All of Shape's ancestors local transformations are combined to obtain the Shape "world position" (Object.Position), the Object's final position.

Rotation of the Shape in the world (as seen on screen).

While it usually works for simple operations (like Rotation.X = Rotation.X + someAngle), we advise you to use Number3.Rotate to rotate an object around X, Y & Z axis.

You can also set unit vectors like Shape.Up, Shape.Right or Shape.Forward to orient your object.

local o = Object()
o.Rotation = {0, math.pi, 0}
-- o revolved half a turn on Y axis

-- another way to rotate the object:
o.Forward:Rotate({0, 0, math.pi / 2})
o.Forward = Camera.Forward

Tick is a function executed ~30 times per second when set (nil by default). Provides the Shape and elapsed time in seconds as parameters.

-- executed ~30 times per second on each user device
myObject.Tick = function(object, dt)
  print("elapsed:", dt, "seconds")
end

Local rotation of the Shape relative to its parent.

All of Shape's ancestors local transformations are combined to obtain the "world rotation" (Object.Rotation), the Object's final rotation.

Velocity of the Shape in world coordinates per second.

⚠️ Velocity will only affect Shape's position while Shape.Physics is true. Whenever it is set to false, Velocity is set to {0,0,0}.

-- makes myObject jump:
myObject.Velocity.Y = 100

Be aware, this Motion property is a hack regarding laws of physics. (sorry Isaac)

But it's very practical to move objects without worrying about forces at play.

This is what's being used by default when you're moving around with your avatar (see Client.DirectionalPad). It's the reason why you can stop moving horizontally while in the air.

Basically, Motion is an instantaneous displacement that contributes to moving Shape every frame, without changing Shape.Velocity directly.

Motion is expressed in world coordinates per second.

⚠️ Motion will only affect Shape's position while Shape.Physics is true. Whenever it is set to false, Motion is set to {0,0,0}.

local speed = 10
myObject.Motion = Camera.Forward * speed
-- myObject will move in the same direction the camera is currently facing.
-- If the Camera rotates after this, it won't change where myObject is heading.

Scale of the Object, in its parent.

Nested Object local scales are combined to obtain the "world scale" (Object.LossyScale), the Object's final scale.

myObject.LocalScale = 2 -- the Object is now 2 times bigger
topLevelObject.LocalScale = 2
local o = Object()
o.LocalScale = 0.5
topLevelObject:AddChild(o) -- o becomes a child of topLevelObject
-- o ends up being displayed with a scale of 1
number LossyScale read-only

Convenience property that attempts to match the actual world scale as much as it can. Note that Objects that have multiple levels of nested rotations and scales will return a skewed lossy scale.

The mass of the Object determines how much a given force can move it and whether or not another object can be pushed by it. It cannot be zero, a neutral mass is a mass of 1.

The combined friction of 2 Objects in contact represents how much the moving Object will be able to slide along the colliding Object.

It is a rate between 0 (full slide, no friction) and 1 (maximum friction). Values equal to or lower than 0 will keep or increase momentum, like sliding on ice. Values higher than 1 means a faster stop, up to a value of 2 to ensure a full stop on contact regardless of the colliding Object's own friction.

[Object.Friction] can be set per-face by providing a table with any combination of the following keys : right, left, front, back, top, bottom, other.
For example, to set the friction on the bottom face of an object's collider to 0 and 0.2 on every other faces, you could set, object.Friction = { bottom=0, other=0.2 }.

The combined bounciness of 2 Objects in contact represents how much of the moving Object's velocity is produced after being in contact with the colliding Object, it is a rate between 0 (no bounce) and 1 (100% of the velocity bounced). Values higher than 1 are allowed and will create an increasing momentum at each bounce (try at your own risk).

[Object.Bounciness] can be set per-face by providing a table with any combination of the following keys : right, left, front, back, top, bottom, other.
For example, to set the bounciness on the side faces of an object's collider to 0.2 and 0 on top and bottom faces, you could set, object.Bounciness = { top=0, bottom=0, other=0.2 }.

All Objects have a collision box that represents the space occupied in the scene with regards to collisions. For Shapes and Players, the collision box is updated with their bounding box. For Objects, it is a 1-cube by default after physics was enabled for the first time.

Returns number of child Objects.

Up is a unit vector (vector with a length of 1). It determines which direction is "up" for the Shape.

Setting it is a way to rotate the Shape.

Right is a unit vector (vector with a length of 1). It determines which direction is "right" for the Shape.

Setting it is a way to rotate the Shape.

Forward is a unit vector (vector with a length of 1). It determines which direction is "forward" for the Shape.

Setting it is a way to rotate the Shape.

Left is a unit vector (vector with a length of 1). It determines which direction is "left" for the Shape.

Setting it is a way to rotate the Shape.

Down is a unit vector (vector with a length of 1). It determines which direction is "down" for the Shape.

Setting it is a way to rotate the Shape.

Backward is a unit vector (vector with a length of 1). It determines which direction is "backward" for the Shape.

Setting it is a way to rotate the Shape.