MutableShape

MutableShape extends Shape, adding functions and properties to it.

A MutableShape is an Object that carries and displays a set of Blocks. The difference with Shape is that MutableShape Blocks can be modified.

Constructors

Creates a MutableShape with shared Palette colors by default.

The model can be empty, loaded from an imported Item, or copied from an existing Shape or MutableShape.

local s = MutableShape(R.username.itemName)

Functions

Block AddBlock ( Block block )
Block AddBlock ( integer paletteIndex, Number3 position, boolean getBlock optional )
Block AddBlock ( integer paletteIndex, number X, number Y, number Z, boolean getBlock optional )
Block AddBlock ( Color color, Number3 position, boolean getBlock optional )
Block AddBlock ( Color color, number X, number Y, number Z, boolean getBlock optional )

Adds a Block to the MutableShape. You may provide a Block, a palette index to an existing color in MutableShape's Palette, or any color which will be added automatically to the MutableShape's Palette if needed.

Returns created Block (or nil if it fails) by default. You may pass the optional parameter getBlock to false if you do not need the return value, as an optimization.

local block = Block(1, 10, 10, 10)
someMutableShape:AddBlock(block)

-- AddBlock can also be called using
-- block's palette index and coordinates:
someMutableShape:AddBlock(1, 10, 10, 10)

-- created block is returned:
local newBlock = someMutableShape:AddBlock(1, 10, 10, 10)
if newBlock ~= nil then
  -- block successfully created!
end

-- ⚠️
local block = Block(1, 10, 10, 10)
local newBlock = someMutableShape:AddBlock(block)
-- Here `newBlock` is not the same as `block`
-- they both have the same palette index and coordinates
-- but `newBlock` has a parent shape while `block` doesn't.

Gets a Block from the MutableShape.
Returns nil if there is no Block at the given coordinates (i. e. if it's "air").

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 MutableShape'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 MutableShape from its parent. Doesn't do anything if the MutableShape 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)

Object:RotateLocal(number3) -- euler angles
Object:RotateLocal(number3, number) -- axis angle

Object:RotateWorld(number3) -- euler angles
Object:RotateWorld(number3, number) -- axis angle

Converts a local rotation to world coordinate system.

Converts a world rotation to local coordinate system.

Adds a text bubble at Object's position. For a Shape or Player, the text bubble will appear above its bounding box.

You may use a duration of -1 to set a permanent text bubble.

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.

Instantaneously remove any ongoing text bubble.

Inherited from Shape

Hide

Converts Block coordinates from model space to world space.

Converts Block coordinates from model space to local space.

Converts a point from world space to model space.

Converts a point from local space to model space.

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

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

Computes the shape baked lighting. Note that if the shape is then saved, the current baked lighting will be saved with it and used everywhere by default.

This function can also be used to update the shape baked lighting, after changing by code some of the shape's Palette entries properties.

You may want to call this function only if:
- 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

It is NOT necessary to call this function if:
- ANY blocks, including light and transparent blocks, are added/removed at runtime

In other words, only changes to transparency and light properties of _existing_ blocks will require a call to this function in order to see the effects on the shape.

NOTE as of 0.0.47: only the Map can have baked lighting.

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

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

Properties

Inherited from Object

Hide

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

⚠️ Acceleration will only affect MutableShape's position while MutableShape.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 MutableShape belongs to.

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

If the MutableShape 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 MutableShape collides with.

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 object = 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)
object.Physics = true

-- 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}

Turns physic simulation on/off when set.

⚠️ When turned off, MutableShape.Velocity & MutableShape.Motion are set to {0,0,0}.

nil by default. Can be set to a function that will be triggered when the MutableShape collides with another Object.

The function is called with 3 parameters: the object the callback was set for, the other actor in the collision and the Face of the first actor that's in contact.

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

object.OnCollision = function(o1, o2)
  -- `o1` is `object` here
  print("collision detected between", o1, "and", o2)
end

object.OnCollision = function(o1, o2, face)
  -- `o1` is `object` here
  print("collision detected between", o1, "'s", face, "and", o2)
end

nil by default. Can be set to a function that will be triggered when the MutableShape 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(o1, o2)
  -- `o1` is `object` here
  print("collision ended between", o1, "and", o2)
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 MutableShape 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 MutableShape is not falling.

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

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

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

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

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

Local position of the MutableShape relative to its parent.

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

Rotation of the MutableShape 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 MutableShape.Up, MutableShape.Right or MutableShape.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 MutableShape 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 MutableShape relative to its parent.

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

Velocity of the MutableShape in world coordinates per second.

⚠️ Velocity will only affect MutableShape's position while MutableShape.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 MutableShape every frame, without changing MutableShape.Velocity directly.

Motion is expressed in world coordinates per second.

⚠️ Motion will only affect MutableShape's position while MutableShape.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 stop on contact) and 1 (full slide, no friction), values higher than 1 are allowed and will create an increasing momentum, like sliding on ice.

The combined bounciness of 2 Objects in contact represents how much of the moving Object's velocity is produced after being in contact with 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).

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 MutableShape.

Setting it is a way to rotate the MutableShape.

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

Setting it is a way to rotate the MutableShape.

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

Setting it is a way to rotate the MutableShape.

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

Setting it is a way to rotate the MutableShape.

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

Setting it is a way to rotate the MutableShape.

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

Setting it is a way to rotate the MutableShape.

Inherited from Shape

Hide

MutableShape'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 MutableShape's geometric center.

You can override it with any point, even outside of the MutableShape'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 MutableShape'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
number Depth read-only

Returns MutableShape's depth, measured in blocks.

number Height read-only

Returns MutableShape's height, measured in blocks.

number Width read-only

Returns MutableShape's width, measured in blocks.

Box BoundingBox read-only

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

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

Number3 Min read-only

The minimum point of the MutableShape's BoundingBox.

Number3 Center read-only

The center of the MutableShape's BoundingBox.

Number3 Max read-only

The maximum point of the MutableShape's BoundingBox.

integer BlocksCount read-only

The number of blocks in MutableShape's model.

Whether or not MutableShape should have a square shadow projected on the map, default is false.
The size of the shadow is based off MutableShape's collision box.

Integer or table of integers between 1 and 8. Cameras only render objects corresponding to their layers.