Welcome to Scripting


Scripting gives you the ability to program the behaviors of your scenes and prefabs. To use scripting add the "Script" component to your GameObject. The bulk of behaviors are GameObject based. Below is a list of methods and events that make up the scripting API available at ARC3DE. Methods that begin with an uppercade letter are global. Methods that start with a period and lowercase letter are methods to execute on a GameObject.

The scripting language used at ARC3DE is MiniScript. To better understand the language a full manual for MiniScript can be located here. For a brief one page summary of MiniScript refer to their MiniScript Quick Reference.

The scripting API at ARC3DE is currently in beta.

Scene

A scene is the playable level that lives on the server. It contains all your GameObject and additional information to rebuild your scene.

LoadScene("scene", ["spawn"])


Loads scene from the server and plays it. If a spawn path is specified it will start the player at the spawn path instead of the default.
LoadScene("sw4kcn3nfh")
LoadScene("sw4kcn3nfh", "spawnPts/mountainTop")

InvokeAll("func", [param])


Invokes function, "func", on all active scripts in the scene and player.
InvokeAll("StartRace")
InvokeAll("EndGame", hiScore)

GameObject

GameObject is the base game entity in a scene. GameObjects can have multiple components for various functions such as rendering, animations, audio, collision, physics, and more.

Self()


Returns the GameObject identifier attached to this script.
go = Self()
go.pos([0,0,0])

.get("global")


Returns the global variable on the GameObject's script or null if no variable is found. The global variable can be a string, number, list or map.
self = Self()
car = Find("/car")

Log "The race place of the car is " + car.get("racePlace")

.invoke("func", [param], [delay])


Invokes script function, "func" on gameobject with optional parameter, "param", and delay. Param can be a string, number, list or map.
car = Find("/car")
car.invoke("TurnOnEngine")
car.invoke("TurnOnRadio", "Rock", 3)

.name(["name"])


Optionally assigns name of gameobject and returns name.
go = Self()
Log "my name is "+ go.name()
Log "my new name is "+ go.name("New Name")

.isActive([active])


Optionally assigns active state of gameobject and returns active state.
go = Self()
Log "go active state = "+ go.isActive()
go.isActive(false)

.isRenderable([active], [recursive])


Optionally sets renderable state of gameobject and returns renderable state. If recursive then sets renderable state for hierarchy. The default of "recursive" is false. This uses the Renderer component.
go = Self()
Log "go visible = "+ go.isRenderable()
go.isRenderable(false)

.isCollidable([active], [recursive])


Optionally sets collidable state of gameobject and returns collidable state. If recursive then sets collidable state for hierarchy. The default of "recursive" is false. This uses the Collider component.
go = Self()
Log "go collidable = "+ go.isCollidable()
go.isCollidable(false)

.color([r,g,b,a])


Optionally sets the color of the gameobject and returns the color. The color will be returned as a list of four numbers for red, green, blue and alpha.
go = Self()
Log "The color of go is: "+ go.color()
go.color([1,0,0,1])

.clone(name, pos, rot, [parent], [style])


Clones and returns a GameObject using the supplied name, position, rotation, and optional parent. The optional style dictates the following:
  • 0 - The clone is created local only and not cached (local/temporary) - DEFAULT
  • 1 - The clone is created locally & remotely for all players but is not cached (remote/temporary)
  • 2 - The clone is created locally & remotely and cached so that future players will create also (remote/cached)
Additionally, the clone will be actived (even if cloned from an inactive GameObject. Moreover, the playerID that cloned the GameObject will be assigned and available thru the .playerID() method.
self = Self()
box = Find("/box1")

Log "Clone Box locally..."
newGO = box.clone("box", [0,10,0], [0,0,0])

Log "Clone Box remotely parenting to this GO..."
newGO = go.clone("box2", [0,10,0], [0,0,0], self, 1)

Log "And finally clone and cache for future players..."
newGO = go.clone("box3", [0,10,0], [0,0,0], self, 2)

.destroy()


Destroys GameObject and if not temporary it will be cached so that future players will also destroy on joining.
go = Self()
Log "Destroy self..."
go.destroy()

OnStart()


This event is called when a script object starts.
OnStart = function()
  Log "Script is starting!"
end function

OnTick()


This event is called every second on the script.
time = 10

OnTick = function()
  globals.time--
  Log "Time = " + globals.time
end function

OnUpdate([delta])


This event is called every update loop. This update occurs at variable time steps. You must include the "delta" paramater for this event even if you don't use it. Delta is the time since the last frame.
go = Self()
rotation = 0

OnUpdate = function(delta)
  globals.rotation += 50 * delta
  go.rot([0,globals.rotation,0])
end function

OnFixedUpdate()


This event is called every physics update. This has a fixed time step size and may be called multiple times in the same frame. You should put physics based updates like adding force inside this event for consistent behaviour.
go = Self()
OnFixedUpdate = function()
  if (InputDown("action")) then
    go.addForce([0,10,0])
  end if
end function

Hierarchy

GameObjects reside in a hierarchy along with other GameObjects. These methods will help traverse and get access other GameObjects.

Find("path")


Returns the GameObject in the scene by path relative to this script or returns 0. Note that the path can contain the forward slash to traverse the hierachy, begin with a forward slash to base pathing from the scene root, or use ".." to go up a level (parent) in the hierarchy.
childGO = Find("childname")
siblingGO = Find("../sibling")
rootGO = Find("/tree123")
lhandGO = Find("body/torso/larm/lhand")

.find("path")


Returns the GameObject in the scene by path relative to GameObject or returns 0. Note that the path can contain the forward slash to traverse the hierachy, begin with a forward slash to base pathing from the scene root, or use ".." to go up a level (parent) in the hierarchy.
self = Self()
childGO = self.find("childname")
siblingGO = childGO.find("../sibling")
lhandGO = self.find("body/torso/larm/lhand")

.parent([go])


Optionally assigns and returns the parent GameObject of this GameObject.
go = Self()
newParent = Find("/newParent")

Log "The parent name of this GO is "+ go.parent().name()
Log "Change parent..."
go.parent(newParent)

.childCount()


Return the number of direct children of this GameObject.
go = Self()
Log "This GO has "+ go.childCount() +" children"

.child(index)


Return the child at index of this GameObject
go = Self()
Log "I have "+ go.childCount() +" children and their names are..."
for i in range(0, go.childCount()-1)
  Log "Child "+ i +" name is "+ go.child(i).name()
end for

Transform

Transform methods allow you to control the position, rotation and hierarchy of your GameObjects.

.pose([x,y,z,x,y,z,w])


Optionally assigns and returns the world space position and rotation of a GameObject. The input is a list of 6 or 7 float values with the first 3 for position and the remainder for rotation. If the rotation has 4 floats it will be treated as a quaternion. If only 3 floats are available it will treat the rotation as euler angles. The returned array is a list of 7 floats for quaternion rotation.
go = Self()
Log "Pose GO using quaternion rotation..."
go.pose([0,10,0,0,0,0,1])
Log "Pose GO using euler rotation..."
go.pose([0,10,0,0,90,0])
Log "The pose of GO = " + go.pose()

.localPose([x,y,z,x,y,z,w])


Optionally assigns and returns the local space position and rotation of a GameObject. The input is a list of 6 or 7 float values with the first 3 for position and the remainder for rotation. If the rotation has 4 floats it will be treated as a quaternion. If only 3 floats are available it will treat the rotation as euler angles. The returned array is a list of 7 floats for quaternion rotation.
go = Self()
Log "Pose GO using quaternion rotation..."
go.localPose([0,10,0,0,0,0,1])
Log "Pose GO using euler rotation..."
go.localPose([0,10,0,0,90,0])
Log "The local pose of GO = " + go.localPose()

.pos([x,y,z])


Optionally assigns and returns the world space position of a GameObject.
go = Self()
Log "Position GO at origin..."
go.pos([0,0,0])
Log "The position of GO = " + go.pos()

.localPos([x,y,z])


Optionally assigns and returns the local space position of a GameObject.
go = Self()
Log "Position GO at parent position..."
go.localPos([0,0,0])
Log "The local position of GO = " + go.localPos()

.rot([x,y,z,w])


Optionally assigns and returns the world space rotation of a GameObject. If the rotation has 4 floats it will be treated as a quaternion. If only 3 floats are available it will treat the rotation as euler angles. The returned array is a list of 4 floats for quaternion rotation.
go = Self()
Log "Rotate GO using quaternion rotation..."
go.rot([0,0,0,1])
Log "Rotate GO using euler rotation..."
go.rot([0,90,0])
Log "The rotation of GO = " + go.rot()

.eulerAngles([x,y,z])


Optionally assigns and returns the world space rotation of a GameObject in Euler angles. All angles are wrapped to be in the range -180 to 180.
go = Self()
Log "Rotate GO using euler rotation..."
go.eulerAngles([0,90,0])
Log "The rotation of GO in euler angles = " + go.eulerAngles()

.localRot([x,y,z,w])


Optionally assigns and returns the local rotation of a GameObject. If the rotation has 4 floats it will be treated as a quaternion. If only 3 floats are available it will treat the rotation as euler angles. The returned array is a list of 4 floats for quaternion rotation.
go = Self()
Log "Rotate GO using quaternion rotation..."
go.localRot([0,0,0,1])
Log "Rotate GO using euler rotation..."
go.localRot([0,90,0])
Log "The local pose of GO = " + go.localRot()

.localScale([x,y,z])


Optionally assigns and returns the local scale of a GameObject. The returned array is a list of 3 floats.
go = Self()
Log "The local scale of GO = " + go.localScale()
go.localScale([1,1,5])

.forward()


Return transform forward vector.
go = Self()
Log "forward = "+ go.forward()

.right()


Return transform right vector.
go = Self()
Log "right = "+ go.right()

.up()


Return transform up vector.
go = Self()
Log "up = "+ go.up()

Animations, Particles & Audio

Animations, Particle & Audio have similar playback functions. It's assumed your gameobject will only have one of these components at a time, either Animations, ParticleSystem, or AudioTrack.

.isPlaying()


Returns if component is playing or not.
go = Self()
if (go.isPlaying()) then
  Log "go is playing!"
end if

.play(["name"], [ease])


Plays the component. For animations you can additionally specify which animation to play otherwise it will play the current/default animation clip. Moreover if you specifiy an ease time greater than zero the animation will CrossFade over the ease period.
go = Self()
sound = Find("/sndHit")
particles = Find("/fxHit")
go.play("hitBounce", 0.25)
sound.play()
particles.play()

.isPaused()


Returns if component is paused or not.
go = Self()
if (go.isPaused()) then
  Log "go is paused!"
end if

.pause()


Pauses the component playback.
go = Self()
sound = Find("/sndHit")
particles = Find("/fxHit")
go.pause()
sound.pause()
particles.pause()

.stop()


Stops the component playback.
go = Self()
sound = Find("/sndHit")
particles = Find("/fxHit")
go.stop()
sound.stop()
particles.stop()

.playLength()


Returns the playback length of the component. For Animations is the length of the animation clip. For Audio its the duration of the audio clip, and for particles its the lifetime of the system.
go = Self()
Log "The length of anim is "+ go.playTime() +" seconds"
if (go.playTime() > go.playLength() * 0.5) then
  Log "We played more than half"
end if

.playSpeed([speed])


Returns the playback speed of the component and optionally assigns it. For Animations this is the playback speed and generally 1. For Audio this is the pitch and also generally 1 and changes based on pitch. For particles this value is the playback speed of the system.
engine = Find("sndEngine")
speed = 0
Log "engine speed = " engine.playSpeed()

OnUpdate = function(delta)
  engine.playSpeed(1 + globals.speed * 0.1)
end function

.playTime([time])


Returns the playback time of the component and optionally assigns it. For Animations this is the playback time of the active animation clip. For Audio this is the scrub time. For particles this value is the playback time of the system.
go = Self()
Log "animation time is "+ go.playTime()
Log "restart animation..."
go.playTime(0)
Log "Jump to halfway in animation..."
go.playTime( go.playLength() * 0.5 )

.playVolume([volume])


Returns the playback volume of an Audio Track and optionally assigns it.
go = Self()
Log "audio volume is "+ go.playVolume()
go.playVolume(0.5)
Log "New volume = "+ go.playVolume()

.animLength("name")


Get playback length of specific animation.
go = Self()
Log "animation length or run is "+ go.animLength("run")

.animSpeed("name", [speed])


Optionally assign and return the playback speed of a specific animation.
go = Self()
Log "animation speed of run is "+ go.animSpeed("run")
go.animSpeed("run", 1.5)

.animTime("name", [time])


Optionally assign and return the playback time of a specific animation.
go = Self()
Log "animation time of jump is "+ go.animTime("jump")
go.animTime("jump", 0.5)

.addAnimEvent("name", time, "func")


Adds timely event to specific animation.
go = Self()
go.addAnimEvent("walk", 0.25, "SndFootstep1")
go.addAnimEvent("walk", 0.75, "SndFootstep2")

.clearAnimEvents("name")


Clears all animation events for specific animation.
go = Self()
go.clearAnimEvents("walk")

Animation Events


While keyframing animations you can add animation events to your timeline that let you specify the function to invoke. These will invoke the function on the script at the specified time during the animation. In the following example, OnAnimFootstep and OnAnimDie are animation events added to the walk and die animations respectively.
sndFootstep = Find("sndFootstep")
sndDie = Find("sndDie")

OnAnimFootstep = function()
  sndFootstep.play()
end function

OnAnimDie = function()
  sndDie.play()
end function

Avatar

Avatar methods and event are for avatars only.

.isAvatar()


Return if GameObject is an avatar or not.
OnCollision = function(go)
  if (go.isAvatar()) then
    go.avatarHurt(0.2)
  end if
end function

.avatarPlayerID()


Return network playerID of avatar.
go = Self()
Log "My network playerID = "+ go.avatarPlayerID()

.avatarVars([vars])


Get/Set avatar variables. If "vars" is a "map" it will assign the avatar variable(s). More than one can be assigned per call. If the "vars" is a string it will return the variable for that specific variable. If "vars" is empty it will return a map of all avatar variables. The list of variables available are:
  • animateAllow (true) - if animations are allowed.
  • customizeAllow (true) - if customizations are allowed for avatar.
  • inputAllow (true) - if the user is allowed to control the avatar thru input.
  • inputDelay (0) - delay user input for brief period of time.
  • anim ("idle") - READONLY - current animation avatar is playing.
  • health (1) - READONLY - health of avatar in the range of [0,1].
  • walkSpeed (3) - Movement speed of avatar while walking.
  • runAllow (true) - If avatar can run or not.
  • runSpeed (6) - Movement speed of avatar while running.
  • dashAllow (true) - If avatar can dash or not.
  • dashSpeed (9) - Movement speed of avatar while dashing.
  • dashDelay (2) - Time it takes running to turn into dashing.
  • dashFX (true) - If dashing produces FX clouds on ground.
  • jumpAllow (true) - If jumping is available or not.
  • jumpSpeed (7) - The velocity addition on jump.
  • relaxAllow (true) - If avatar will relax after idling long enough.
  • relaxDelay (5) - Time for idle to turn into relax animation.
  • sleepAllow (true) - If avatar will sleep after relaxing.
  • sleepDelay (20) - Time for relax to turn into sleeping.
  • attackAllow (true) - If avatar can use default attack behaviors.
  • attackHurt (0.4) - Amount of damage done thru attacking.
  • mounted - READONLY - If avatar is currently mounted or not.
  • camDist ([7,5,9]) - A list of the camera's current, near and far distances.
  • grounded - READONLY - True when avatar is touching the ground, otherwise false.
  • groundNormal [0,1,0] - READONLY - Vector of the ground normal if touching.
  • groundHitFX (true) - If a hard ground impact will produce a smoke ring or not.
go = Self()
Log "Avatar jump speed = " + go.avatarVars("jumpSpeed")
Log "assign new jump speed..."
go.avatarVars({"jumpSpeed":12})
Log "now assign camera distances..."
go.avatarVars({"camDist":15,"camNear":5,"camFar":30})
Log "now return all avatar variables..." + go.avatarVars()

.avatarCheckpoint()


Saves the current position of the avatar to be used on the next respawn.
go = Self()
go.avatarCheckpoint()

.avatarTeleport("path")


Teleport avatar to a GameObject located at scene path.
go = Self()
go.avatarTeleport("teleportPt1")

.avatarLaunch(amount)


Launch the avatar upward by amount. The upward vector is local to THIS calling script. So if the script's GameObject is rotated 45 degress the avatar will be launched at 45 degress.
go = Self()
go.avatarLaunch(20)

.avatarHurt(amount, [playerID])


Hurt the avatar by an amount. Life for the avatar is in the range [0,1]. If the avatars life drops to zero or below the avatar will die. The playerID is an optional param of the player that did the hurting that will be passed over to OnHurt event.
OnCollision = function(go)
  if (go.isAvatar()) then
    go.avatarHurt(0.1)
  end if
end function

.avatarHeal(amount, [playerID])


Heal the avatar by an amount. Life for the avatar is in the range [0,1] so healing by 1 will fully restore health. The playerID is an optional param of the player that did the healing that will be passed over to OnHurt event.
OnCollision = function(go)
  if (go.isAvatar()) then
    go.avatarHeal(1)
  end if
end function

.avatarDie([playerID])


This will kill the avatar. The playerID is an optional param of the player that did the killing that will be passed over to OnHurt event.
go = Self()
go.avatarDie()

.avatarEquip("type", amount)


Equip the avatar with type and amount of ammo/fuel. Currently only jetpack is supported.
go = Self()
Log "give avatar jetpack and 10s of fuel..."
go.avatarEquip("jetpack", 10)

.avatarPrompt("func")


This will prompt the avatar with a "contextual" play bubble. The function "func" will be invoked if the player selects the action input. Note that the avatar GameObject will be passed to that function.
go = Self()
Log "Do something..."
go.avatarPrompt("RestoreHealth")

RestoreHealth = function(avatar)
  avatar.avatarHeal(1)
end function

.avatarDismiss()


This is used to dismiss the contextual prompt above. This could be because too much time has passed, another player took the item, or when the player leaves the prompting trigger.
go = Self()
Log "you're too late..."
go.avatarDismiss()

.avatarMount("path", ["pose"])

.avatarMount(GameObject, ["pose"])


This will mount the avatar on the GameObject at "path" and animate the avatar with animation "pose". In addition, if the calling script is a trigger the trigger will be disabled on mount and re-enabled on dismount. This behavior is replicated over the network and if the call originates from a trigger the collider will be disabled on those clients too. This is to prevent two different players from mounting the same object.

However, there can be multiple mounts for the same rigidbody. If you wish to "drive" the rigidbody you should then use the .requestOwnership() method to take networking ownership of this GameObject.

After mounting the OnMount event will be called for the local player only. The local player dismounts with the jump input.
car = Find("..")

OnCollision = function(go)
  if (go.isAvatar()) then
    go.avatarPrompt("EnterVehicle")
  end if
end function

OnCollisionEnd = function(go)
  if (go.isAvatar()) then
    go.avatarDismiss()
  end if

EnterVehicle = function(avatar)
  avatar.avatarMount("../mountPtDriver", "sit")
  Log "avatarMount in this case will disable this trigger for all players..."
end function

OnMount = function(avatar)
  Log "Invoke car to start..."
  car.invoke("StartCar")
end function

.avatarDismount()


Dismount an avatar that is mounted.
avatar = null

OnMount = function(avatar)
  globals.avatar = avatar
end function

OnDismount = function()
  globals.avatar = null
end function

OnUpdate = function(delta)
  if (InputDown("jump")) then
    avatar.avatarDismount()
  end if
end function

OnHurt(playerID)


When the avatar is hurt. The playerID is the player that is passed to avatarHurt().
OnHurt = function()
  Log "I was hurt!"
end function

OnHeal(playerID)


When the avatar is healed. The playerID is the player that is passed to avatarHeal().
OnHeal = function()
  Log "I was healed!"
end function

OnDie(playerID)


When the avatar dies. The playerID is the player that is passed to avatarDie().
OnDie = function()
  Log "I died!"
end function

OnRespawn()


When the avatar respawns.
OnRespawn = function()
  Log "I respawned!"
end function

OnMount(avatar)


When the avatar mounts another GameObject. The avatar GameObject is passed into this function (to later dismount). Note that this event is invoked on the script that calls the avatarMount method and NOT the object that IS mounted. To further initialize the mount you might need to invoke a method on the GameObject that is mounted.
car = Find("..")
avatar = null

OnMount = function(avatar)
  globals.avatar = avatar
  Log "I mounted the driver seat..."
  car.invoke("EnterDriver")
end function

OnDismount()


When the avatar dismounts by pressing the jump input. Like the OnMount event this method is invoked on the script that calls the avatarMount method and NOT on the object that IS mounted.
car = Find("..")

OnDismount = function()
  Log "I jumped out of the vehicle!"
  car.invoke("ExitPassenger")
end function

Camera

Camera methods allow you to control the camera in your scene.

GetCamera()


Return the main camera in this scene.
camera = GetCamera()
camera.fov(60)

ScreenFade("func", [time], [r,g,b])


Fade screen over optional time and optional color invoking callback "func" when color reached.
FadeToGreen = function()
  Log "do stuff..."
end function

ScreenFade("FadeToGreen", 1, [0,1,0])

.ease(go, [ease])


Ease camera pose (position and rotation) to GameObject over "ease" seconds defaulting ease to 1s if omitted.
camera = GetCamera()
camPt1 = Find("/camPts/cam1")
camera.ease(camPt1, 1.5)

.follow(go, "mode", moveSpeed, moveOffset, lookSpeed, lookOffset, [ease])


Changes the camera follow behavior. The camera's position is based on the move speed and offset in relation to the target GameObject. The orientation of the camera is based on a computed look target with movement based on lookSpeed and lookOffset. Use the optional "ease" paramater to ease into this follow behavior. Below are the following modes:
  • "fixed" - the camera is fixed in space but rotates to follow the target GameObject
  • "offset" - the camera follows the target GameObject but from an offset. This is a typical 2D Mario camera style.
  • "cylinder" - This moves the camera to be at a certain distance from the target but allows the camera to orbit so to feel like the camera is on a cylinder around the target.
  • "3rdperson" - this is similar to cylinder with addition behavior to keep the camera behind the player like a typical 3rd person camera.
camera = GetCamera()
Log "Follow the default cylinder..."
camera.follow(avatar, "cylinder", 6, [0,2.5,5], 8, [0,1.5,0])
Log "Follow using 3rd person camera..."
camera.follow(avatar, "3rdperson", 6, [0,2.5,5], 8, [0,1.5,0])
Log "Follow using offset camera..."
camera.follow(avatar, "offset", 6, [0,2.5,-10], 8, [0,2.5,0], 3)

.unfollow()


Stops the follow behavior of the camera. This is typically required for scripted cutscenes that will return to a follow behavior after the cutscene is over.
go = Self()
camera = GetCamera()
camera.unfollow()
self.invoke("StartCutscene1")

.isVR()


Return is the camera is a Virtual Reality camera or not.
camera = GetCamera()
Log "Camera VR state = " + camera.isVR()

.fov([fov])


Optionally assign and return the field of view of the camera.
camera = GetCamera()
Log "The camera FOV = "+ camera.fov()
camera.fov(50)

.isOrtho([active])


Optionally assign and return the camera's orthographic state.
camera = GetCamera()
Log "The camera is orthographic = "+ camera.isOrtho()
camera.isOrtho(true)

.orthoSize([size])


Optionally assign and return the camera's orthographic size used when orthographic.
camera = GetCamera()
Log "The camera's orthographic size = "+ camera.orthoSize()
camera.orthoSize(10.0)

Rigidbody

Rigidbody methods and events allow you to define the physics behaviors of your scripts. To use your GameObject must have both a collider component and Rigidbody component.

Gravity([amount])


Optionally assign and return gravity used in physics. This should be a negative value. The default is -20.
Log "gravity is "+ Gravity()
Gravity(-10)

.isBody()


Return if GameObject has Rigidbody component available.
go = Self()
if (go.isBody()) then
  go.velocity([0,20,0])
end if

.isSleeping()


Return if GameObject has Rigidbody component that is currently sleeping.
go = Self()
if (go.isBody() and go.isSleeping()) then
  go.wakeUp()
end if

.wakeUp()


Wakes a rigidbody component that is currently sleeping.
go = Self()
if (go.isBody() and go.isSleeping()) then
  go.wakeUp()
end if

.velocity([x,y,z])


Optionally assigns and returns the linear velocity of the rigidbody.
go = Self()
Log "go velocity = "+ go.velocity()
go.velocity([0,20,0])

.angVelocity([x,y,z])


Optionally assigns and returns the angular velocity of the rigidbody. The angular velocity is assigned and returned using euler angles (3 floats).
go = Self()
Log "go angVelocity = "+ go.angVelocity()
go.angVelocity([0,20,0])

.drag([amount])


Optionally assign and return the linear drag force on this rigidbody. The more drag the faster it comes to a stop.
go = Self()
Log "go linear drag = "+ go.drag()
go.drag(5)

.angDrag([amount])


Optionally assign and return the angular drag force on this rigidbody. The more drag the faster it stops rotating.
go = Self()
Log "go angular drag = "+ go.angDrag()
go.angDrag(0.5)

.mass([amount])


Optionally assign and return the mass of this rigidbody.
go = Self()
Log "go mass = "+ go.mass()
go.mass(50.0)

.useGravity([active])


Optionally assign and return the use of gravity on this rigidbody.
go = Self()
Log "go gravity = "+ go.useGravity()
go.useGravity(false)

.lockPosition([x,y,z])


Optionally assign and return the lock array for position. This can be used to lock movement to specific axis.
go = Self()
Log "Lock Z movement to allow only X and Y..."
go.lockPosition([0,0,1])
Log "Now lock Y allowing X,Z movement..."
go.lockPosition([0,1,0])
Log "Locking position is now "+ go.lockPosition()

.lockRotation([x,y,z])


Optionally assign and return the lock array for rotation. This can be used to lock rotation to specific axis.
go = Self()
Log "Lock all axis and allow no rotation..."
go.lockRotation([1,1,1])
Log "Now only allow rotation about Z axis..."
go.lockRotation([1,1,0])
Log "Locking rotation is now "+ go.lockRotation()

.centerOfMass([x,y,z])


Optionally assign and return the local center of mass of the rigidbody. For vehicles it is typical to move the center of mass under the vehicle to prevent the car from tipping over on hard turns.
go = Self()
Log "Center of mass = "+ go.centerOfMass()
go.centerOfMass([0,-1,0])

.addForce([x,y,z])


Add impulse force to rigidbody. Forces are generally added in OnFixedUpdate for consistent behavior.
go = Self()

OnFixedUpdate = function()
  go.addForce([0,10,0])
end function

.addTorque([x,y,z])


Add torque force to rigidbody. Forces are generally added in OnFixedUpdate for consistent behavior.
go = Self()

OnFixedUpdate = function()
  go.addTorque([0,10,0])
end function

OnRespawn()


Callback when this rigidbody falls low enough in the world such that it should respawn back to its initial position.
respawnSnd = Find("/sndRespawn")

OnRespawn = function()
  respawnSnd.play()
end function

Collision & Raycast

Collision behaviors allow you to script how your GameObjects will react to each other. For collision events to occur between two GameObjects both must have collider components and at least one of them must have a Rigidbody component. Use the isTrigger option to turn your colliders into triggers in order to get collision events without the physics reacting to the collider.

.contactCount()


Returns the number of collision contact pairs in the last physics tick.
OnCollision = function(go)
  Log "Number on contacts = "+ go.contactCount()
end function

.contactPt([index])


Return the ith contact point.
OnCollision = function(go)
  Log "First contact point = "+ go.contactPt(0)
end function

.contactNormal([index])


Returns the ith contact normal.
OnCollision = function(go)
  Log "First contact normal = "+ go.contactNormal(0)
end function

.averageNormal()


Returns the averaged normal for all contacts.
OnCollision = function(go)
  Log "Average normal = "+ go.averageNormal(0)
end function

.relativeSpeed()


Returns the relative speed between two objects.
OnCollision = function(go)
  if (go.isAvatar()) then
    if (go.relativeSpeed() > 20) then
      go.avatarDie()
    else if (go.relativeSpeed() > 10) then
      go.avatarHurt(0.1)
    end if
  end if
end function

.impulseSpeed()


Returns the impulse speed of the collision.
OnCollision = function(go)
  Log "collision impulse speed = "+ go.impulseSpeed()
end function

OnCollision(go)


The collision event for both triggers and non-triggers when a collision occurs.
OnCollision = function(go)
  Log "collision impulse speed = "+ go.impulseSpeed()
end function

OnCollisionStay(go)


The collision event for every frame that a collision continues to stay colliding for both triggers and rigidbodies.
OnCollision = function(go)
  Log "collision entered!"
end function

OnCollisionStay = function(go)
  Log "collision stayed!"
end function

OnCollisionEnd = function(go)
  Log "collision exited!"
end function

OnCollisionEnd(go)


The collision event when a trigger is exited.
OnCollision = function(go)
  Log "collision entered!"
end function

OnCollisionEnd = function(go)
  Log "collision exited!"
end function

Raycast(pos, dir, [length], [ignore])


Construct ray (pos, dir) to test for a collision in the scene. Ray can have optional length and a list of GameObjects to ignore. Returns a map of raycast hit information if raycast hits a collider or null if nothing was hit. The map of the result will have the following values:
  • go - the GameObject that was hit
  • dist - the ray distance the hit occured from its origin
  • point - the 3D point of the hit in world space
  • normal - the 3D vector of the hit face normal
Raycasting allows you to fire rays that collide with the physical scene. Examples of using Raycast include firing bullets or seeing if player has line of sight with another entity.
self = Self()
pos = self.pos()
dir = self.vectorForward()
hit = Raycast(pos, dir, 100)
if (hit) then
  Log "Raycast Hit "+ hit["go"] +" at point "+ hit["point"]
end if

Log "Use mask to ignore hitting myself..."
mask = [1]
mask[0] = self
hit2 = Raycast(pos, dir, 100, mask)
if (hit2) then
  Log "Do something..."
end if

IgnoreCollision(go1, go2, [ignore])


Ignore collisions between GameObjects go1 and go2. If ignore is specified and false then collisions will be re-enabled.
self = Self()
wall = Find("/wall")
IgnoreCollision(self, wall)
Log "now re-enable collision..."
IgnoreCollision(self, wall, false)

WheelCollider

The methods for WheelCollider allow you to script the behaviors of wheeled vehicles.

.motorTorque([amount])


Optionally assign and return the forward motor force of the wheel.
wheelFL = Find("wheelFL")
Log "wheelFL motor = "+ wheelFL.motorTorque()
wheelFL.motorTorque(500.0)

.brakeTorque([amount])


Optionally assign and return the braking force of the wheel.
wheelFL = Find("wheelFL")
Log "wheelFL braking = "+ wheelFL.brakeTorque()
wheelFL.brakeTorque(500.0)

.steerAngle([amount])


Optionally assign and return the steering angle of the wheel.
wheelFL = Find("wheelFL")
Log "wheelFL steer = "+ wheelFL.steerAngle()
wheelFL.steerAngle(30.0)

.wheelPose()


Get the pose (position and rotation) of the wheel collider.
wheelFL = Find("wheelFL")
tireFL = Find("tireFL")
Log "assign tire model pose from wheel collider pose..."
tireFL.pose( wheelFL.wheelPose() )

.wheelGrounded()


Get if wheel collider is colliding or not.
wheelFL = Find("wheelFL")
Log "wheel grounded = "+ wheelFL.wheelGrounded()

Gui

GUI Methods allow you to script the 2D GUIs for your scene.

.guiText(["text"])


Optionally assign and return the gui text of a GUI object.
score = Find("score")
  Log "score = "+ score.guiText()
score.guiText("1234")

OnGuiDown()


Mouse down or Touch down event on Gui element.
OnGuiDown = function()
  Log "Mouse Down on buttton!"
end function

OnGuiUp()


Mouse up or Touch up event on Gui element.
OnGuiUp = function()
  Log "Mouse Up on buttton!"
end function

OnGuiClick()


Mouse click or Touch click event on Gui element.
form = Find("..")
OnGuiClick = function()
  Log "Button was clicked!"
  form.invoke("DoSomething")
end function

Network

Network methods allow you to script events on other networked players in the same room.

NetInvoke(recipients, "func", [param], [delay])


Invoke function with optional parameter on this script across networked players targeted based on the recipients. The recipients can be:
  • -2 - the master client
  • -1 - other players
  • 0 - all players
  • > 0 - a specific player that matches playerID
Log "Begin countdown for everybody..."
NetInvoke(0, "BeginCountdown")

Log "Tell master client to begin..."
NetInvoke(-2, "BeginRace", 0, 3.0)

Log "Tell specific player a secret..."
NetInvoke(2, "TellSecret", secret)

NetIsMaster()


Return if your client is the master client. The master client is the client in charge of the room and the default owner/controller of animations and rigidbodies. The master client should also do any room decisions that should be determined for all clients. For example if the game was a race the master client should decide when to begin the race, have final say on the race clock, and decide who ultimately wins when finish order is close.
if (NetIsMaster()) then
  Log "I am the master client!"
else
  Log "I am not the master client"
end if

NetGame()


Returns a map of the game/room properties. A networked game may update the room properties on the fly and those properties must change for other clients and be available for new clients. Examples of room variables could be game state, team scores, the current time of a race, and more. To assign and sync game/room properties across the network see the NetSync and NetSyncAll methods below.
Log "The game/room properties are: "+ NetGame()

NetLocalPlayer()


Returns a map of player properties associated with this (local) player. These properties are syned across all clients. You can update your properties using the NetSync and NetSyncAll on the "player" Script in the Game Hierarchy. An example of this map for a player that is signed in:
  • nickname: "VincentMush"
  • pid: 1
  • master: 1
  • active: 1
  • uid: "asd3asd23"
  • id: "asd3asd23"
  • tagline: "This is so awesome!"
  • username: "VincentMush"
  • pic: "https://www.arc3de.com/..."
  • color: "e14938"
  • model: "xy23asd3a,..."
An example of this when a player is not logged in:
  • nickname: "Guest8618"
  • pid: 1
  • master: 1
  • active: 1
  • uid: "fghfgh23-dfgh-3455-sdf2-fghj23sdgvh3"
  • model: "xy23asd3a,..."
Log "The player properties for me are: "+ NetLocalPlayer()

NetPlayers([activeOnly])


Returns a list of maps of player properties for each player in this room. The default of activeOnly is false and will return all the players, including inactive. To return only the active players in the room call NetPlayers(true).
go = Self()
Log "The players in this room are: "+ NetPlayers()

NetPlayer(playerID)


Returns a map of the player properties for the player identified by playerID in this room. This could be you, another player, or null if the player cannot be found.
go = Self()
Log "The player properties for this avatar is "+ NetPlayer( go.avatarPlayerID() )

NetMaxPlayers(max)


Set the maximum number of players allowed in the room. This function must be called from the global block when the script is loaded to override the maximum players before network connection is made.
go = Self()
NetMaxPlayers(8)

OnStart = function()
  Log "Too late - network connection already started..."
end function

NetSync("variable")


This method will sync the global "variable" in this script to all OTHER networked players that have this script. Moreover, this method has special meaning when used with GameObjects in the "game hierarchy". First let us explain the game hierarchy:



The game hierarchy as pictured above is a special hierarchy that encapsulates the logic of your level. The root "game" object should have the logic of your game. The disabled "player" GameObject under "game" will hold the "player" script that will be added to every player that joins the room. Finally the "gui" GameObject under "game" should hold all your GUIs and can be turned on/off with the GUI button in the scene window.

If this game hierarchy is exported as a prefab it could be imported into another scene and with it the same game logic and gui would be included. But there's more that makes this "game hierarchy" special.

Since the root "game" in this hierarchy effectively holds the game/room properties when you call the method NetSync from it we'll also sync the game/room variables available to all players in this room and future players yet to join that call NetGame(). Examples of variables you'd want to sync with the game are the game state, team scores, the race clock and lap count in a race, or the hi score achieved so far in this room.

The same applies to the disabled "player" GameObject. If the NetSync method is called on a "player" GameObject then that variable will also update the local player properties and be available to all networked players who call NetPlayer() including those yet to join. An example of the properties you'd want to update is the number of kills that a player has or the weapon the player is using so when other players join they can equip their avatar with the correct weapon loadout. If this was a racer you'd likely sync the car selected and any color/loadout applied to that vehicle as well as the lap count and finish position.

The event OnNetSync("variable") will be called for all OTHER clients after they have synced the specified global variable on this script.
raceStarted = false
raceTime = 0

OnTick = function()
  if (globals.raceStarted) then
    raceTime++
    NetSync("raceTime")
  end if
end function

OnStartRace = function()
  globals.raceStarted = true
  globals.raceTime = 0
  NetSync("raceStart")
  NetSync("raceTime")
end function

NetSyncAll()


This method will syncs all the global variables in this script to all OTHER networked players that have this script. If this script is attached to the "game" GameObject in the game hierarchy it will update the game/room network variables available to all current and future players in the room that call NetGame(). If this script is attached to the "player" GameObject in the game hierarchy it will update the player properties on the local player and be avilable to all current and future players that call NetPlayer().

The event OnNetSyncAll() will be called for all OTHER clients after they have synced all global variables on this script.
gameState = "lobby"
teamScoreRed = 0
teamScoreBlue = 0

OnBeginMatch = function()
  globals.gameState = "started"
  globals.teamScoreRed = 0
  globals.teamScoreBlue = 0
  NetSyncAll()
end function

.playerID([id])


Optionally assigns and returns network playerID of this GameObject. For example this could be assigned to a newly cloned bomb or bullet to know who to award a kill in a shooter. Use with ".avatarPlayerID()" to get the avatar's player ID. This uses the Script component.
go = Self()
Log "My network playerID = "+ go.avatarPlayerID()

.isMine()


Returns if GameObject is controlled by my client over the network. This would return false for other players or objects controlled by other players.
OnCollision = function(go)
  if (go.isMine()) then
    Log "collided with GO that is mine"
  else
    Log "collided with GO that is NOT mine"
  end if
end function

.requestOwnership()


Request ownership of the networked GameObject. This is typically used for rigidbodies and animations when you want to be in control of those components from a network perspective writing their properties instead of receiving them.
flag = Self()

OnCollision = function(go)
  if (go.isAvatar()) then
    Log "carry flag..."
    flag.requestOwnership()
    flag.invoke("Pickup", go)
  end if
end function

OnNetJoinedRoom()


This event is called when you join a room.
OnNetJoinedRoom = function()
  Log "I entered the room!"
end function

OnNetPlayerEnteredRoom(playerID)


This event is called when another person joins the room. Use NetPlayer(playerID) to get specific player data.
OnNetPlayerEnteredRoom = function(playerID)
  Log "Another player entered the room!"
end function

OnNetPlayerLeftRoom(playerID)


This event is called when a player leaves the room. Use NetPlayer(playerID) to get specific player data.
OnNetPlayerEnteredRoom = function(playerID)
  Log "A player has left the room!"
end function

OnNetRoomProperties()


This event is called when the room properties have changed. Call NetGame() to get the new properties.
OnNetRoomProperties = function()
  Log "Room properties changed!"
end function

OnNetPlayerProperties(playerID)


This event is called when player properties change for a player. Use NetPlayer(playerID) to get specific player data.
OnNetPlayerProperties = function(playerID)
  Log "Player properties for player "+ playerID +" has changed!"
end function

OnNetMasterChanged(playerID)


This event is called when the master client changes. Use NetPlayer(playerID) to get player data for the new master client.
OnNetMasterChanged = function(playerID)
  Log "The master client is player "+ playerID +"!"
end function

OnNetSync("variable")


This event is called when a global variable is synced over the network for this script.
gameClock = 0
gameClockGui = Find("gui/hud/clock")

OnNetSync = function(variable)
  if (variable == "gameClock") then
    Log "Update game clock gui..."
    gameClockGui.guiText(gameClock)
  end if
end function

OnNetSyncAll()


This event is called when all globals variables have synced over the network for this script.
guiHud = Find("gui/hud")
guiPostgame = Find("gui/postgame")

OnNetSyncAll = function()
  Log "Update all guis..."
  guiHud.invoke("UpdateGui")
  guiPostgame.invoke("UpdateGui")
end function

Input

The input methods return the state of inputs from keyboard, mouse, gamepad and virtual (on-screen) inputs.

Input("button")


Returns true for all frames the button is pressed, false otherwise. Available names of buttons are as follows:
  • "jump" - Spacebar or 'A' on the gamepad
  • "action" - Left Mouse, 'B' on gamepad
  • "use" - 'E' on keyboard, Right Mouse, or 'X' on gamepad
  • "special" - 'Return' or NumpadEnter on keyboard, Middle Mouse, or 'Y' on gamepad
  • "left" - Left Shift on keyboard, Left Trigger on gamepad
  • "right" - Right Shift on keyboard, Right Trigger on gamepad
  • "camera" - Tab on keyboard, Right Analog button on gamepad
  • "pause" - Escape on keyboard, Start button on gamepad
  • "bump1" - Left Ctrl on keyboard, Left Bumper button on gamepad
  • "bump2" - Right Ctrl on keyboard, Right Bumper button on gamepad
go = Self()
gas = InputDown("action")
if (Input("special")) then
  go.invoke("ActiveBomb")
end if

InputDown("button")


Returns true on the frame an input is pressed down, false otherwise. See above for names of buttons.
elevator = Find("/elevator1")

OnUpdate = function(delta)
  if (InputDown("select")) then
    elevator.invoke("MoveUp")
  end if
end function

InputUp("button")


Returns true on the frame an input is released from being pressed, false otherwise. See above for names of buttons.
bomb = Find("/bomb1")

OnUpdate = function(delta)
  if (InputUp("action")) then
    bomb.invoke("Detonate")
  end if
end function

InputAnalog1()


Return 2D array of input values from the left analog. This array is affected by the following inputs:
  • Left Analog on gamepad
  • DPAD on gamepad
  • W,A,S,D on keyboard
car = Self()
wheels = [0,0,0,0]
wheels[0] = Find("wheel-FL")
wheels[1] = Find("wheel-FR")
motor = 0

OnUpdate = function(delta)
  analog1 = InputAnalog1()
  globals.wheels[0].steerAngle(analog1[0] * 20)
  globals.wheels[1].steerAngle(analog1[0] * 20)
  globals.motor = analog1[1] * 1000
end function

InputAnalog2()


Return 2D array of input values from the right analog. This array is affected by the following inputs:
  • Right Analog on gamepad
  • Arrow keys on keyboard
analog2 = InputAnalog2()
Log "Analog2.x = "+ analog2[0]
Log "Analog2.y = "+ analog2[1]

InputVibrate(["style"], [duration])


Vibrate gamepads using haptic actuators for the duration in seconds with a default of "both" and a duration of 0.2 seconds. The available styles are:
  • "weak" - to use the weak actuator
  • "strong" - to use the strong actuator
  • "both" - to use the both actuators
InputVibrate()
InputVibrate("weak")
InputVibrate("strong", 0.2)

Logging

Logging gives you insight into your scripts. At runtime your logging will present itself using the room chat.

Log("text")


Log text to the console/room chat.
Log "Starting race..."

Warn("text")


Log warning to the console/room chat.
Warn "You need a key yo open this door!"

Error("text")


Log error to the console/room chat.
Error "An error occurred with this script!"

Player Data

Player data is for saving player data to be used later or between scenes. Common examples of this is saving progress for experiences that span multiple scenes or syncing the player loadout between scenes.

PlayerDataPut("key", value)


Write script value for unique "key". The value can be a number, string, list or map. The key is prepended with the level creator's user identifier to make the key unique per developer while still allowing keys to span scenes.
weapon = "sword"
Log "Save player weapon for next scene."
PlayerDataPut("player.weapon", weapon)
LoadScene("asdfgh345as")

PlayerDataGet("key", default)


Return script value for unique "key" or use default if not available. The default value can be a number, string, list or map and should match the value type used in PlayerDataPut().
weapon = PlayerDataGet("player.weapon", "sword")
Log "The saved player weapon is "+ weapon

PlayerDataClear("key")


Deletes saved script value for unique "key". This could be used to clear progress, completed levels, or player loadout.
Log "clear progress stuff..."
PlayerDataClear("player.weapon")
PlayerDataClear("player.hitpoints")
PlayerDataClear("player.stamina")
PlayerDataClear("player.magic")
PlayerDataClear("player.currentmap")

Float

Float Math

FloatRnd(min, max)


Returns random value between min and max inclusive.
random = FloatRnd(0,100)
Log "Random number is "+ random

FloatMin(f1, f2)


Returns the minimum of f1 and f2.
min = FloatMin(1,100)
Log "Min is "+ min

FloatMax(f1, f2)


Returns the maximum of f1 and f2.
max = FloatMax(1,100)
Log "Max is "+ max

FloatClamp(f, min, max)


Returns clamped value between min and max.
clamp = FloatClamp(12, 0, 10)
Log "Clamped value is "+ clamp

FloatRound(f)


Returns rounded value of f.
round = FloatRound(5.55)
Log "Rounded value is "+ round

FloatFloor(f)


Returns floored value of f.
floor = FloatFloor(5.55)
Log "Floored value is "+ floor

FloatCeil(f)


Returns teh ceiling value of f.
ceil = FloatCeil(5.55)
Log "The ceiling value is "+ ceil

FloatAbs(f)


Returns absolute value of f.
absolute = FloatAbs(-5.55)
Log "Absolute value is "+ absolute

Vector3

Vector3 Math

Vec3Normalize(v)


Makes this vector have a magnitude of 1.
v = [10,20,30]
vector = Vec3Normalize(v)
Log "Normalized vector is "+ vector

Vec3Magnitude(v)


Return length of vector.
vector = [10, 20, 30]
length = Vec3Magnitude(vector)
Log "Length of vector is "+ length

Vec3SqrMagnitude(v)


Return square length of vector as square root is expensive.
vector = [10, 20, 30]
length = Vec3SqrMagnitude(vector)
Log "Square length of vector is "+ length

Vec3Diff(p1, p2)


Return vector that is p1 - p2.
v = Vec3Diff( [10, 20, 30], [0, 0, 10] )
Log "Vector v = "+ v

Vec3Add(p1, p2)


Return vector that is p1 + p2.
v = Vec3Add( [10, 20, 30], [0, 0, 10] )
Log "Vector v = "+ v

Vec3Scale(vector, scale)


Return vector that is vector * scale.
v = Vec3Scale( [10, 20, 30], 3 )
Log "Vector v = "+ v

Vec3Lerp(p1, p2, s)


Linearly interpolates between two points.
v1 = Find("object1").vectorForward()
v2 = Find("object2").vectorForward()
lerp = Vec3Slerp(v1, v2)
Log "lerp of vectors = "+ lerp

Vec3Slerp(p1, p2, s)


Spherically interpolates between two vectors.
v1 = Find("object1").vectorForward()
v2 = Find("object2").vectorForward()
slerp = Vec3Slerp(v1, v2)
Log "slerp of vectors = "+ slerp

Vec3Dot(v1, v2)


Dot Product of two vectors.
v1 = Find("object1").vectorForward()
v2 = Find("object2").vectorForward()
dot = Vec3Dot(v1, v2)
Log "dot of vectors = "+ dot

Vec3Cross(v1, v2)


Cross Product of two vectors.
v1 = Find("object1").vectorForward()
v2 = Find("object2").vectorForward()
cross = Vec3Cross(v1, v2)
Log "cross product = "+ cross

Vec3Dist(p1, p2)


Returns the distance between p1 and p2.
p1 = Find("object1").pos()
p2 = Find("object2").pos()
distance = Vec3Dist(p1, p2)
Log "distance between objects is "+ distance

Vec3SqrDist(p1, p2)


Returns the square distance between p1 and p2.
p1 = Find("object1").pos()
p2 = Find("object2").pos()
squareDistance = Vec3SqrDist(p1, p2)
Log "square distance between objects is "+ squareDistance

Vec3Angle(v1, v2)


Returns the angle in degrees between from and to.
v1 = Find("object1").vectorForward()
v2 = Find("object2").vectorForward()
angle = Vec3Angle(v1, v2)
Log "Angle between vectors is "+ angle

Vec3RotateTowards(current, target, maxRadians, maxMagnitude)


Rotates a vector current towards target.
go1 = Find("object1")
go2 = Find("object2")
newVector = Vec3RotateTowards(go1.vectorForward(), go2.vectorForward(), 0.1, 0.1)

Quaternion

Quaternion Math

QuatIdentity()


Returns the identity quaternion.
newRot = QuatIdentity()
go.rot( newRot )

QuatEuler([x,y,z])


Returns a rotation that rotates z degrees around the z axis, x degrees around the x axis, and y degrees around the y axis; applied in that order.
go = Self()
newRot = QuatEuler([0,0,90])
go.rot( newRot )

QuatLerp(q1, q2, s)


Interpolates between a and b by t and normalizes the result afterwards. The parameter t is clamped to the range [0, 1].
go1 = Find("object1")
go2 = Find("object2")
newRot = QuatLerp(go1.rot(), go2.rot(), 0.5)
go1.rot( newRot )

QuatSlerp(q1, q2, s)


Spherically interpolates between quaternions a and b by ratio t. The parameter t is clamped to the range [0, 1].
go1 = Find("object1")
go2 = Find("object2")
newRot = QuatSlerp(go1.rot(), go2.rot(), 0.5)
go1.rot( newRot )

QuatMult(q1, q2)


Returns quaternion that is q1 multiplied by q2.
go1 = Find("object1")
go2 = Find("object2")
newRot = QuatMult(go1.rot(), go2.rot())
go1.rot( newRot )

QuatDot(q1, q2)


The dot product between two rotations.
go1 = Find("object1")
go2 = Find("object2")
dot = QuatDot(go1.rot(), go2.rot())
Log "Dot of quaternions is "+ dot

QuatAngle(q1, q2)


Returns the angle in degrees between two rotations a and b.
go1 = Find("object1")
go2 = Find("object2")
angle = QuatAngle(go1.rot(), go2.rot())
Log "Angle between objects is "+ angle

QuatLookRotation(forward, [up])


Creates a rotation with the specified forward and upwards directions.
go = Self()
newRot = QuatLookRotation([-1,0,0])
go.rot( newRot )

QuatRotateTowards(from, to, maxRadians)


Rotates a rotation from towards to.
go1 = Find("object1")
go2 = Find("object2")
newRot = QuatRotateTowards(go1.rot(), go2.rot(), 0.1)
go1.rot( newRot )