Reconnecting
Reconnecting...
Your session has timed out. Reload to continue.
Your session has timed out. Reload to continue.

Welcome to Mixiply!

In this tutorial we are going to cover all of the basics for creating AR and VR projects that will run in the Mixiply app. This is designed for people that are new to Mixiply or who haven't tried out the code aspect yet. Once you have gone through this tutorial, you should be able to take these skills and use them to create your own AR and VR projects and games!

There is a lot to cover. So, we won't be building a specific game or project, we are just going to cover the concepts, have a go in the code in some way and then try the next thing. If you would like to see all of the concepts running in the app then launch this project in the Mixiply app. You can also find some of our other tutorials and awesome demo projects either in the Tutorials and demos section of the Help and about, or the Featured group.

As you make your way through this tutorial, we encourage you to experiment as much as possible with the concepts before moving on. This will help you to build a strong understanding of how these concepts work in the app.

There is a lot covered by this tutorial, but there are some things that won't be covered. Most of what is covered and any extras can be found in the API documentation. This can be a good place to go for a quick reminder of how to do something once you have got a good grasp of the concepts in this tutorial.

Before we start...

It will be helpful to have a few assets ready to go before you start the tutorial, even if you don't know what they're for just yet. You can find links in the Resources section of the Help and about to places where you can find these assets. You can upload these files into your assets in Mixiply or use a link to an external file - it needs to be a link to a file, rather than a link to a hosted video on, say Youtube.

You will need:

  • 1 or more 3D model files
  • 1 or more images
  • an audio file
  • a video file

Supported file formats:

  • for 3D models are .obj, .gltf and .glb files.
  • for images are .jpg / .jpeg and .png files.
  • for audio are mp3, .ogg and .wav files.
  • for video are .mp4 files.

Making a shape

The first thing that we want to do is get something to look at in our virtual space. Let's start with some shapes!

The Primitive class is used to make basic 3D shapes. So lets get one rendered.

When you create an object in your code, you need to store it in a variable so that you can access it in different areas of your code. A variable is a container that can store information and that information can change. If you are creating something that you won't need to access anywhere else in the code, then you can create it locally inside the function that will be using it.

We want to use our shape throughout the code so, we will create a variable at the very top of our code, above the setup() function. When naming variables, it is important to call them something specific that describes what it is (so, not something like shape1, shape2, etc.). This makes it easier to refer to it again later and it makes your code more readable to others.

We'll call our first variable box but you can name yours what you like.

In your code you will find a function called start(). This function runs once, after the setup(), and it puts everything in it's starting position as well as some other things that we will cover later. This is where we are going to create our shape.

Inside the start() function (between the curly brackets {}) store a cube in our box variable using Primitive.cube();

Save and launch your project in the Mixiply app to see the cube in AR. The cube will be rendered right where you are standing (0, 0, 0) so you may need to move around a bit to see it.

There are a range of shapes that the Primitive class can make. Other shapes include:

  • sphere
  • cylinder
  • capsule
  • quad - a 2-dimensional square.
  • plane - a plane is used to represent a flat surface.
  • floor - will create a plane to act as a floor. When you create a floor, you need to give it a number for the size and a number for the height.

Change your cube to be a different shape, or add some more shapes to your project.

Remember, if you want to be able to change the object in other parts of your code, then create a new variable at the top of the code. Otherwise, you can make the new variable right in the start function.

From here on, we will be working with the cube stored within the box variable. But it will be helpful if you have a range of shapes so you can see how things apply differently to the different shapes.

Changing a shape

Now that we have a shape in our project, let's make some changes to it. The shapes made with the Primitive class are an instance of the MixiplyObject class which has a range of functions that can be used to change the object. These methods can be used with all objects, including assets, which we will look at later.

Tip: When you create an object, you can set a range of attributes at the same time by chaining the methods together, one after the other, using what is called dot notation. We will show this in the examples as we go.

Position

You may have noticed that when you added another object, it rendered in the exact same place as the cube and they overlapped each other. We probably don't want that which is where position comes in.

The position refers to the spot within the 3-dimensional space that the object will be placed.

When working in 3D we will be referring to 3 dimensions: x, y and z which represent width (left and right), height (up and down) and depth (forwards and backwards).

See the diagram below.

To set the position of an object, we use a function called .setPosition(). This position can be set using coordinates or a vector, but for now we will use coordinates.

When we call this function, we need to include 3 numbers inside the brackets (called arguments) that will represent the coordinate for each of the 3 dimensions or axes. These numbers can be both positive and negative.

When you launch the project, you / the camera will be at the position (0, 0, 0). So, based on your starting point:

  • Positive numbers will move the object right, up and forward
  • Negative numbers will move the object left, down and backward

Use the .setPosition(x, y, z) method on your cube to see what happens in the app. Try both positive and negative numbers.

Don't forget to save each time you change something.

Another way to change the position of your object is the .move() function. Like .setPosition(), we can use coordinates or a vector as the arguments.

How .move() differs is that the object is moved based on its current position, rather than placing it in a specific spot. This is helpful for when you want to move an object a certain distance rather than to a specific place.

We will use this function later when we look at the update() and onClick() functions.

Scale

We can scale our object up or down in three ways.

Firstly, we can use .setScale(), which uses coordinates or a vector to change the size of our object. Each coordinate scales the shape in that direction. For example, if the coordinates were (3, 1, 1), the object would be 3 units along the x axis, and 1 unit along the y and z axes. This function can be good to use if you want to make an irregular shape.

The next is .scaleToFit() which again, uses either coordinates or a vector. This will scale the object to fit within a box the size of the coordinates or vector that you give to the function. This function will keep the object's proportions between the 3 axes the same, so can be good for when you are resizing an asset but don't want to change the way it looks.

Then there is .scaleToFill(). This works similarly to .scaleToFit() in that it will scale the object to fill up the specified box, but it will ignore the object's size ratio and change the proportions to fill the space.

Change the scale of your cube to (5, 5, 5) using one of the three functions. What happens if you set each coordinate to a different value?

With the cube, it might be hard to tell the difference between how the three functions work. Try them on a shape such as the cylinder or capsule.

We also have a function called .changeScale(). Like move, this changes the scale of the object based on its current scale. This is helpful if you want to change the scale by a certain amount instead of trying to figure out the exact size you want it to be.

We will use this function later when we look at the update() and onClick() functions.

Size

The .setSize() function is another way to change the scale of an object. This function takes a single number as the argument, which will determine the scale of all 3 axes.

This function is good to use if you want to resize your object equally in all three directions.

Rotation

Rotation changes the way that your object is facing. You can rotate it around the 3 axes that we have been using for all of our movement and scale - x, y and z. Similarly to position, we can use both positive numbers and negative numbers to change the direction that our object will rotate in.

  • Positive numbers will rotate the object forwards, right, and up
  • Negative numbers will rotate the object backwards, left, and down

The function .setRotation() uses either coordinates or a vector to determine the position that the object will face. Objects can rotate around an axis between 0 and 360 degrees or 0 and -360 - 0 being no rotation and 360 or -360 being one full rotation.

Change to rotation of your cube using .setRotation(). Try using both negative and positive numbers. It will be worth trying rotation on a shape such as cylinder or capsule so that the changes are easier to follow.

We can also use the .rotate() function. This rotates the object based on the direction it is currently facing. This is helpful for when you want to rotate an object a certain amount rather than to a specific direction.

We will use this function later when we look at the update() and onClick() functions.

Tip: We can use the .lookAt() function to rotate the object so that it is looking at a given point in space. You can also make it so that it looks at another object or even the player. If you put it in the update() function with the player position, then the object will look at you wherever you go.

Colour

We can change the colour of an object using the .setColor() function. The colour can be set using the Color class or with an RGB or RGBa value.

To use the Color class we type the class name followed by a dot and the name of the colour that we want. For example Color.red. There are a limited range of pre-determined colours. These include:

  • white
  • black
  • red
  • green
  • blue
  • grey or gray
  • yellow
  • cyan
  • magenta
  • clear - which will make the object transparent.

RGB stands for Red, Green, and Blue. Each parameter defines the intensity of the color with a value between 0 and 1 and colours are made based on the mix of these 3 colour values. The same colours from above look like this in RGB format:

  • white (1, 1, 1)
  • black (0, 0, 0)
  • red (1, 0, 0)
  • green (0, 1, 0)
  • blue (0, 0, 1)
  • grey or gray (0.5, 0.5 ,0.5)
  • yellow (1, 1, 0)
  • cyan (0, 1, 1)
  • magenta (1, 0, 1)

Online there are a range of colour pickers where you can visually choose a colour and get the RGB value to use in your code. Here is one example.

RGB colours are often represented using values between 0 and 255. If you want to use these colours in Mixiply you will need to divide each value by 255 and use the result.

For example aquamarine's rgb value is rgb(127, 255, 212). To use aquamarine in Mixiply, we need to divide each value by 255.

  • 127 / 255 = 0.49804
  • 255 / 255 = 1
  • 212 / 255 = 0.83137

So, we can make a shape aquamarine by using the result of the division - .setColor(0.49804, 1, 0.83137) - or we can put the division as the values and it will be figured out for us - .setColor(127/255, 255/255, 212/255).

RGBA color values are an extension of RGB color values with an Alpha channel - which specifies the opacity for a color (and so the opacity of the whole shape). The alpha parameter is a number between 0.0 (fully transparent) and 1.0 (not transparent at all).

Change the colour of your cube using the .setColor() method. Try the different ways of doing it to see which you prefer.

Texture

Another way we can change the way a 3D object looks is by adding a texture, which is basically wrapping a 2D image around the 3D object.

We do this by using the .texture("imageUrl") function and putting the link to our image in the quotation marks.

Take one of your image assets and add it to the cube as a texture. The texture will apply differently to different shapes. Try adding it to a range of shapes and see how it's different.

Note: if you have a colour set, the image will be tinted to that colour. So, you may want to delete the .setColor().

Tip: By combining Primitive.plane() and a texture, you can create objects that look like the floor or walls.

There is also a function called .textureTiling(x, y) which will scale the texture image up or down to fill that size. This means that you can scale your image down and it will repeat multiple time over your shape (like tiles).

Text

As well as shapes, we can create text in our project. We use the built-in UI class to create and manipulate text.

To create some text in our project we use UI.text("text"). This creates a new text object. The argument it takes is the text that you want to display and that goes in-between the quotation marks.

Just like the shapes, we need to create a variable to store this object in. You can do this at the top of the code (meaning you can access it in other parts of your code) or inside the function (meaning you can only access inside that function).

Create your variable and then in the start() function create some text using UI.text("text").

You can move, rotate and rescale the text in the same way that you would with the shapes. You can also chain them together at the same time as you create the text, just like we did with the shapes.

The UI class has some change functions that can be used to update a UI object that already exists. These are helpful for when you want something about the text to change after an event.

The change methods in UI include:

  • UI.changeText(objectName, "new text") Updates the text to what you have entered in-between the quotation marks.
  • UI.changeColor(objectName, Color.newcolor) Changes the colour of the text to the colour you have given.
  • UI.changeFontSize(objectName, size) Changes the text to the font size number you have given. Can also be done using object.setScale(x, y, z).

The first argument of each of these functions is the name of the UI object that you want to change. In the example we want to change the greeting object.

When we are using the UI class, we are unable to chain the functions together like we do with the MixiplyObject methods. So, each one needs to be written separately.

Experiment with your text object. Move it around, change the rotation, scale or font size, and the colour.

Assets

Now that we have learned how to make and manipulate objects and text, let's get some of our external assets into the project.

Assets refer to any media files in the project. This could be 3D models, images, audio or video.

When we include an asset, we need to load it in the setup() using Asset.load() and then create an instance of it somewhere else in the code using Asset.create(). All assets are loaded and created in the same way.

Asset.load("url", "assetName") takes two parameters. In the first pair of quotation marks, you need a URL for the asset and in the second pair of quotation marks, you need and a name for your asset.

  • The URL could be a link to an asset you have uploaded in Mixiply or an external URL.
  • The asset name will be what you use to refer to the asset later when you create an instance of it. So, to make things easier, try to name it something that describes the asset.

In the setup() function, load your 3D model. Here is an example:

That model is now loaded and ready to be used in our project. Asset.create("assetName") takes one parameter - the name that you gave the asset when you loaded it.

Just like before, we need to create a variable to store this object in.

Create a variable at the top of your code or inside the function and then create an instance of your asset. Be sure to name the variable something meaningful.

Assets are also instances of the MixiplyObject class. So, we can use all of the functions that we learned above with our 3D model.

Experiment with your 3D model in the same way we did with the shapes - change its position, scale, rotation. You could even try to change its colour and texture to see what happens.

Images work much the same as 3D models, except that they are 2-dimensional. You can use the same functions to manipulate an image as you would with a shape or 3D model.

Load and create an instance of your image and make a range of changes to see how it looks in the 3-dimensional space.

We load and create an instance of audio and video assets in the same way, but they work slightly differently and have some other methods that we use to get them to play.

Let's load and create an instance of our audio and video files, just to see what they look like.

The audio file probably wasn't visible and you might have seen a small play bar for the video. You can use the same functions that we used earlier to move, rotate and rescale the video player to how you want it to be. The video player can be a 2-dimensional square or a cube.

Both audio and video have media player functions to play, pause and stop the file. These functions take one argument, which is the name of the object that you want to play, pause or stop.

In order to use these functions, we have to use the Audio or Video class with the function after it, rather than adding them to our object like we did with the position, scale and rotation.

Let's get our audio and video files playing.

Pretty cool right? You might have noticed that the audio file only plays once and then stops. You can make the audio loop by using Audio.loop(objectName).

The video however, loops automatically and so you may wish to use Video.stop(objectName) or Video.pause(objectName). You can also use Audio.stop(objectName) or Audio.pause(objectName) for the audio file.

The Video class also has a function which returns how far through the video is as a number between 0 (start) and 1 (end) - Video.getProgress(objectName) - and a function which sets the video at the given point using a number between 0 (start) and 1 (end) - Video.setProgress(objectName, progress).

Parent and child objects

In Mixiply we can connect objects using the idea of a parent and children.

A parent object is like the lead object for that group of objects and a parent can have multiple children.

A child object can only have one parent at a time. The attributes of a child object can be changed using its global orientation (just like how we normally set an object) or its local orientation (which will be in relation to its parent).

We use the .setParent(parentObject) function to give a parent to an object. The argument we need to pass is the name of the object that we want to be the parent. We also have a .newParent(newParentObject) function which will change the parent to something new.

Once an object has some children, there are some functions and properties that can be helpful to know:

  • parentObject.detachChildren() Removes all of the children from this object. Note: this only removes the connection between the objects, it does not destroy any of the objects.
  • parentObject.getChild(indexNumber) Returns the child of this MixiplyObject at the given index.
  • parentObject.setAllColor() Sets the colour of the MixiplyObject and its children. Can use Color.color, rgb or rgba values.
  • parentObject.childCount Returns the number of children this MixiplyObject has.
  • childObject.isChildOf(parentObject) Tests whether this object a child of the given parent.

Also, you can use some local functions to make changes to the children objects that will change in relation to the parent object. These functions are called in the same way as the global functions and can use either x, y, z coordinates or a vector.

  • .setLocalPosition()
  • .setLocalRotation()
  • .setLocalScale()

This can be really handy for when you want to keep objects grouped together or you want to position something based on another object.

This is what was done in the getting started demo project. You might notice that each shape has some text describing what it is doing. This text is the child of the object and the position is set using the .setLocalPosition() function. Doing that made it a lot easier to place the text within the 3-dimensional space because we didn't need to know the exact location we wanted it to be, we can set it in relation to the parent object.

Let's give our cube some children.

Now, try experimenting with the position, rotation, and scale of the parent and children to see what happens.

What happens to the children when you change the parent? What is the difference if the change one child locally and one globally?

You can change the colour of each object individually or you can use the function parent.setAllColor(), which changes the colour of the parent and all of its child objects. It accepts the same arguments as the setColor() function.

Vectors

In Mixiply, Vectors are used to hold information related to 3D space like position, rotation, scale and direction. The Vector class has a range of properties that can be helpful for interacting with your objects.

We might want to move a range of objects all by the same amount. Instead of writing the coordinates for each one, we can create a new vector that holds the value and reuse it for each object.

To create a new vector we use the new keyword. A vector can take x, y, z coordinates or another vector as its argument. In the second example, we use cube.size which is a property of the cude that returns a vector. We talk more about properties in the next section.

We can also change our objects using some of the built-in vector functions which include:

  • .up Returns a Vector (0, 1, 0).
  • .down Returns a Vector (0, -1, 0).
  • .right Returns a Vector (1, 0, 0).
  • .left Returns a Vector (-1, 0, 0).
  • .forward Returns a Vector (0, 0, 1).
  • .back Returns a Vector (0, 0, -1).
  • .zero Returns a Vector (0, 0, 0).
  • .one Returns a Vector (1, 1, 1).

Once you have created a vector, you can pass it to most of the methods that we have been using so far, rather than using coordinates.

Vectors have their own functions as well. Some helpful functions include:

  • .add(vectorA, vectorB) Adds two vectors together and returns the result.
  • .subtract(vectorA, vectorB) Subtracts one vector from another vector and returns the result.
  • .multiply(vectorA, factor) Multiplies each component of a vector by a number.
  • .divide(vectorA, factor) Divides each component of a vector by a number.
  • .equals(vectorA, vectorB) Returns true if all the components have the same value. Otherwise false.
  • .scale(vectorA, vectorB) Multiples a vector by another vector.
  • .dot(vectorA, vectorB) Calculates the dot product of two vectors which can be used to figure out if two objects are facing a similar direction or facing opposite directions.
  • .cross(vectorA, vectorB) Calculates the cross product of two vectors which returns a third vector relative to the initial two vectors.
  • .distance(vectorA, vectorB) Calculates the distance between two points.
  • .angle(vectorA, vectorB) Returns the angle in degrees between two vectors.

There are more functions that can be found in the API documentation under Vector.

Try making a new vector and using it in one of your functions instead of the coordinates and then try using one of the vector properties. Also, try some of the vector functions. How do you think you could use them in your own project?

Properties

We use properties to both read and write an object's data. Properties are things that define an object, like the common attributes that any objects of that type would have. For example, a cube's properties would include a name, position, rotation, scale, and colour, and so all cubes will have these properties - they might have different values, but they would all have those properties. When we used the set.Position() function on our shapes and assets, we were writing their position property.

We can get the properties of an object by first using the object's name followed by the property that we want. Like anything else, the information needs to be stored. We could save this in a variable, make a new vector, or we can use these properties inside of a function call.

Note: we don't need to add brackets after the name of the property. This is only something we do with functions. Here are some examples:

Properties are great because you don't need to know the value of the an object's property. Like in the above example, we want the fireball to render in the same place as the box. But instead of looking in the code to find the cube and copying its position value, we can just use the box's position property.

Some properties are used by almost all object types, such as position, rotation, and scale. However, some objects will have attributes unique to only them. Here are some of the unique properties that can be accessed:

MixiplyObject properties

MixiplyObjects represent the objects that are shown in the world. This includes primitive shapes, assets, planes, etc.

  • .name The name of the MixiplyObject.
  • .tag The name of the tag attached to the MixiplyObject.
  • .color The colour of the MixiplyObject.
  • .parent The parent MixiplyObject of this MixiplyObject.
  • .forward The direction pointing forwards of the MixiplyObject. Note: this property is read only.
  • .back The direction pointing backwards of the MixiplyObject. Note: this property is read only.
  • .up The direction pointing upwards of the MixiplyObject. Note: this property is read only.
  • .down The direction pointing downwards of the MixiplyObject. Note: this property is read only.
  • .right The direction pointing right of the MixiplyObject. Note: this property is read only.
  • .left The direction pointing left of the MixiplyObject. Note: this property is read only.
  • .rotation The global rotation of the MixiplyObject in the world.
  • .scale The global scale of the MixiplyObject in the world.
  • .size The global size of the MixiplyObject in the world.
  • .localPosition The local position of the MixiplyObject when compared to its parent.
  • .localRotation The local rotation of the MixiplyObject when compared to its parent.
  • .localScale The local scale of the MixiplyObject when compared to its parent.
  • .localSize The local size of the MixiplyObject when compared to its parent.
  • .visible The visibility of the MixiplyObject. Note: this property is read only.

Asset properties

  • .loadingCount Returns the number of assets that are currently loading. Note: this property is read only.
  • .loadedCount Returns the number of assets that have been loaded. Note: this property is read only.

Vector properties

As well as the properties used above in the Vector section, there are these:

  • .this[0, 1, or 2] 0: the x component of the Vector, 1: the y component of the Vector, 2: the z component of the Vector.
  • .x Returns the x component of the Vector.
  • .y Returns the y component of the Vector.ween 0
  • .z Returns the z component of the Vector.
  • .magnitude Returns the length of the Vector. Note: this property is read only.
  • .sqrMagnitude Returns the squared length of the Vector. Note: this property is read only.
  • .normalized Returns this Vector with a magnitude of 1. Note: this property is read only.

Color properties

Beyond the built-in colours that can be accessed there are some other properties about the colours that can be used.

  • .this(0, 1, 2, or 3) Index 0: a value between 0 and 1 that represents the red component of the RGBA format, index 1: a value between 0 and 1 that represents the the green component of the RGBA format, index 2: a value bet and 1 that represents the the blue component of the RGBA format, index 3: a value between 0 and 1 that represents the the apha component of the RGBA format.
  • .r Returns the red component of the RGBA format as a number between 0 and 1.
  • .g Returns the green component of the RGBA format as a number between 0 and 1.
  • .b Returns the blue component of the RGBA format as a number between 0 and 1.
  • .a Returns the alpha component of the RGBA format as a number between 0 and 1.
  • .gamma Returns a version of the colour that has had the gamma curve applied.
  • .greyscale Returns the greyscale value of the colour. Note: this property is read only.
  • .linear Returns a linear value (sRGB) of the colour.
  • .maxColourComponent Returns the maximum colour component value: Max(r, g, b).

Functions

We have been talking a lot about functions, but what is a function?

In programming, a function is a block of code that performs a task. The function might need you to pass some information to it (arguments), it could send information back, or it could just perform a stand-alone task without needing any information.

Some functions we have some across include .setPosition(x, y, z) which takes the coordinates and then it moves the object to that position. Others we have used include setup(args) and start(args).

The .setPosition() function is a part of the MixiplyObject class and so it can only be used by something that is of the MixiplyObject type. Whereas setup() and start() are global functions which means that they effect everything within the project.

You may have notices that everything we have done so far just happens once and then we have to change it again in the code. What if we want something to change after the project has started?

update()

In your code you will find a global function called update(). This function runs at every frame or every game step. So, anything inside this method will occur continuously or until you stop it.

This is where we can start using those functions we talked about earlier that change something based on the object's current position, rotation or scale.

Inside the update() function, we can make our cube spin by 1 each frame using the .rotate() function.

That's cool. But, what happens if you make the number bigger? Or negative? Or put it on the x or the z axis? Or make a different shape rotate?

Experiment with different parts of the .rotate() function.

Now let's try moving the object. Move your cube away from the camera by 1 each frame using .move().

I'm guessing that your cube ran away and never came back which is a problem. We will come back to that problem later.

For now, have a go at moving the object in different directions (don't forget to try negative numbers) and different amounts, try decimals as well.

What about scale? Try changing the scale of your cube by 1 each frame using .changeScale().

Again, try the different axes, differrent size numbers, and negative numbers.

onClick()

The update() function is great, but we don't always want our objects to change with every frame. That's where input comes in.

Mixiply recognises different inputs depending on the device that you are using, which can include mouse clicks, screen taps, keyboard presses and motion controllers.

Probably the most common inputs are mouse click and screen tap, which is what we will look at here.

There are a range of click functions that we can use. While all of these functions use the word click, they also work for taps on a mobile device.

We have:

  • onClick(hitInfo) Called after a full click/tap
  • onClickDown(hitInfo) Called when you click down or start a tap (start touching the screen)
  • onClickHeld(hitInfo) Called when you continue holding down the mouse button or tap (keep touching the screen)
  • onClickUp(hitInfo) Called when you release the mouse or end the tap (stop touching the screen)

Each function is passed an argument called hitInfo which gives us the properties of the input.

The properties we can get from the hitInfo are:

  • hitInfo.didHitObject Whether or not an object was clicked/tapped (true or false)
  • hitInfo.origin Gives a vector of where the click/tap was located: (x, y, z)
  • hitInfo.hitObject The object that was clicked/tapped. This can then be used to get information about the object itself or to make changes to the object
  • hitInfo.point The point in space that the hit took place - if an object was hit (x, y, z)
  • hitInfo.distance The distance between the click/tap origin and the object that was hit, if one was hit (x, y, z)
  • hitInfo.direction Gives a vector of the direction that the click/tap was heading towards: (x, y, z)
  • hitInfo.tapDirection Gives a vector of the position 1 unit of distance in front of where the click/tap originated: (x, y, z)
  • hitInfo.normal Gives a vector of the normal of the hit (x, y, z). The normal can be used to calculate reflection

Add the below code to the end of your project. This is an onClick() function. We are going to write some code inside that function.

We already know how to change our objects in a range of ways. The MixiplyObject class has some other functions that we haven't talked about yet that will work well with the onClick() function:

  • MixiplyObject.destroy(objectName) Removes the object from the project
  • MixiplyObject.copy(objectName) Creates a copy of the object in the same position and with the same attributes
  • objectName.setVisible(true or false) Sets the visibility of the object

In the example, we are going to store the hitInfo.hitObject in a variable so that it is easier to pass to the functions. We will make the variable locally (inside the function) because we can only use the hitInfo when the onClick() function is called anyway.

We are also going to use an if statement. This will check if something is true or not. If it is true, it will run whatever is inside the statement. This is often paired with an else statement which will run when the if statement is false. If you want to learn more about these coding concepts, check out some of the learning resources for javascript (the scripting language used by Mixiply) in Help and about.

Let's start by moving the object that is clicked.

Try changing the object.move() to one of the other functions we have already used - .changeScale(), .rotate(), .setColor(). Or have a go at one of the new functions mentioned above.

In the example below, we make a copy of our object, but because the .copy() function places the new object in the same place as the original you will need to use .move() to place it somewhere else.

We also use the Random class to get a random value between -3 and 3. We talk more about the Random class later in the tutorial.

Math.floor() is a built-in javascript function that rounds a number down to the nearest whole number, which we used to remove any decimals that we might get from the Random.range() function.

Have a go at using the other onClick() methods, such as onClickHold(hitInfo) or onClickUp(hitInfo).

Writing your own functions

So far all of the functions we have used have been built-in functions, but we can write our own functions too.

Writing a function follows this pattern:

  • Use the 'function' keyword
  • Give the function a name. Try to give it a name that explains what it does
  • () Define the arguments that it needs inside the brackets. Your function might take a range of arguments that will be used by the actions inside the function, or it could take none.
  • {} Curly braces which hold the actions that the function will perform
  • Write the steps or actions that the function will perform. Your function might return a result (such as in the add example below) or it might perform a stand-alone task (like the skyboxOn example).

You can do just about anything inside a function. Here are some simple examples:

If you want to learn more about how to write your own functions in javascript (the scripting language used by Mixiply), have a look at the learning resources in the Help and about.

Object functions

You might have noticed that the onClick() function effects any object that you click or tap. This is because it is a global function. This means that anytime you click or tap inside the project, this method will be called.

So, if we add multiple actions to this function, all of them will happen every time you click an object. You may want this, but often it's not that helpful.

We can get around this by writing an onClick() function for an individual object. This means that the function will only be called if that particular object is clicked.

To do this we need to go back to where we created our objects. Also, we don't have to use the if statement to check if an object was clicked, because this will only run when that specific object is clicked.

Notice the formatting when we do this. It's the same pattern as the global functions but it goes inside of the onClick() brackets.

Give this a go. Write an onClick() for multiple objects and make each object do something different.

Debugging

This is probably a good point to talk about debugging. Debugging is the process of finding and fixing errors in your code.

There will be times when you write some code and it doesn't work or you want to check that a value or property is what you want it to be. These are things that we can use the debugger for.

Firstly, if there are any errors that occur when you try to run your project, they will be shown in the log on the desktop apps or in the debugger console on the code tab of your project if you launch the mobile app in debugger mode.

Secondly, anything you put into the debug(output) function will also be shown. The output could be a string or it could be a property of an object or the result of a function.

What you put into the debugger depends on what you want to find out.

If you want to check if a certain point in your code is reached, then you could just input a string. When you write a string, it needs to be surrounded by quotation marks. For example:

If you want to know what a value of something is, then you can get that property from an object or you can call a function and output the result.

Note: you may need to add the .toString() method after the property to see the actual value.

You can also combine a string and other output.

Try to display something in the debugger now. Try both a string and the value of an object or result of a function.

Effects

Mixiply has an Effects class with some built-in digital effects. These effects include:

  • Effects.explosion(spawnPosition)
  • Effects.flare(spawnPosition)
  • Effects.smoke(spawnPosition)
  • Effects.fireball(spawnPosition)
  • Effects.laserimpact(spawnPosition)
  • Effects.laserbeam(spawnPosition, spawnRotation) The rotation controls the direction the laserbeam is fired in
  • Effects.lightning(start, end)

To use these effects, we need to write Effects before the effect we want to use. We also need to pass in a vector.

You can create a new vector if you want the effect to spawn in a particular place (look back to the vectors section if you can't remember how), but you might just want it to spawn where the user clicks or in the place of an object.

We are going to add it to our onClick() function so we can get the origin from the hitInfo. We could also add it to the onClick() method we wrote for our cube so that the effect will only spawn when we click the cube.

Have a go with all of the effects so you get a sense of what they look like in the Mixiply app. Remember to save after each change you make before you launch it.

Forces

In Mixiply, you can apply a force in a certain direction to cause an object to move as well as set forces to objects which will effect the way that they move.

To cause an object to move, we have two possibilities:

  • .applyImpulse()
  • .applyForce()

.applyImpulse() adds an impulse or short force to the object, where .applyForce() adds a constant force to the object.

Both functions can take are either coordinates (x, y, z) or a vector and these parameters determine the direction and the amount of force that is applied along that particular axis.

Let's add one of these functions in to our onClick() method. We could enter particular coordinates, but in the example we are going to use the hitInfo. Let's try a few different things to see the difference.

Forces that you can apply to change the way the object moves include:

  • .setMass(number) Changes the mass of the object with 0 being no mass.
  • .setDrag(number) Changes the drag of the object with 0 being no drag.
  • .setGravity(true or false) Turns gravity on or off for that object.
  • .applyAcceleration(x, y, z) Adds an acceleration force to the object. Can use coordinates or a vector. The larger the number the more the object will accelerate along that axis
  • .applyVelocityChange(x, y, z) Changes the velocity of the object. Can use coordinates or a vector. The larger the number the faster the object will travel along that axis

Mass - changes the resistance an object has to acceleration. So, something with greater mass will move slower than something with less mass.

Drag - is a force that opposes the motion of an object. Something with greater drag will slow down and come to a stop faster than something with less drag. An object with no drag will not come to a stop on its own.

Both of these forces can be seen when an oject is pushed with .applyImpulse() or .applyForce().

Let's apply mass and drag to our cube. Try higher and lower numbers and try each force by itself.

Try setting the gravity to true and watch what happens to the object. Put a plane or other object underneath it. What happens then?

Have a go at changing the acceleration and the velocity. These might be best done when you click on the object.

Collisions

In Mixiply, it is possible for objects to collide with one another. How they react depends on the forces you have applied and on what you tell it to do within the onCollision() function.

All objects are set to be collidable by default when you create them, but you can change this using .setCollidable(true or false), true = collidable, false = not collidable.

The onCollision() function needs to be attached to an object and it will be called when the object collides with something else. When onCollision() is called it is passed information about the object that it collided with in the hitObj.

To try this you will need more than one object. Go back to the earlier 'Make a shape' section if you can't remember how to do this.

Make an object non-colliadable to see what happens when you push an object into it (you will need to use .applyImpulse() in the object's onClick() or the global onClick() function to get the objects moving when you click them).

Now add an .onCollision(hitObj) function for one of your objects. Be creative! What could you make happen when two objects collide (it doesn't have to happen to those objects either, it could be somewhere else)?

One more forces method that is worth knowing about is .setKinematic(true or false). When enabled, forces and collisions will not affect the object. This could be helpful for when you want a visible object that can't be touched.

Behaviour

The Behaviour class allows you to create your own custom scripts that can easily be reused and reapplied across multiple projects.

If you want to create your own behaviours, it is recommended to write the behaviour functions in a separate file outside of main.js.

When you want to include a behaviour in your project, you will need to copy a link to the file in the includes.txt in your project's code tab.

Mixiply has a range of behaviours that have been pre-made and can be found in the code resources section of Help and about.

You have to create an instance of the behaviour in order to use it in your code. To do this you use the function Behaviour.create(). The arguments that you pass to the function are different depending on the behaviour you are using.

Here are a few examples:

Try adding a behaviour to your project. The three behaviours in the example are a good place to start, but have a look at the other behaviours in the code resources as well.

Broadcasting

We can have objects communicate with each other using the Event class and broadcasting. The event can be triggered in a range of ways, such as when an object is clicked, an object reaches a certain position, or a value reaches a certain number.

The Event class has three functions:

  • .subscribe("eventName", listener) Have a listener do something when an event called "eventName" is triggered. The listener will often be a function that will run when the event is called and it could also be an object.
  • .broadcast("eventName", payload) Triggers the event called "eventName". Payload can be any arguments that you want to be give the subscribed listeners - string, number, object, etc.
  • .unsubscribe("eventName", listener) Have the listener no longer do anything then the event called "eventName" triggers.

Here is an example:

Plane detection

The mobile app has the ability to detect planes, which would be flat surfaces in the real world, such as a table. For this to happen you need to turn the plane detector on. Remember, this will only work in the mobile app.

Add line 3 and 4 of the below code to the start function of your project and launch it in the mobile app to see what it looks like. Check out the 3D explorer project which demonstrates this feature.

When the plane detection is working, you can attach an object to the planes that are found. This function is called .anchor().

The Plane class has a few properties that we can access beyond .position, .rotation, and .shape.

  • .forward The direction pointing forwards of the Plane. Note: this property is read only.

  • .planeObject Returns the MixiplyObject that the plane is stored as.

Have a go at anchoring an object to the planes that are detected in the mobile app.

Other helpful classes

Mixiply has a range of classes for different things. We have talked about some already, like Primitive, MixiplyObject, Asset, Vector, Effect and more. These are some other classes that we haven't mentioned that are helpful to know about.

Mixiply

The Mixiply class handles utility features and functionality. Part of this includes handling the time that has passed, the platform that the project is currently running on and some other features of the project.

The properties that we can access from the Mixiply class:

  • Mixiply.currentTime Returns the time elapsed since the project launched. Note: this property is read only
  • Mixiply.deltaTime Returns the time elapsed since the last frame rendered. Note: this property is read only
  • Mixiply.platform Returns a string describing what platform is currently being used. Note: this property is read only

Functions included in the Mixiply class:

  • .sky(true or false) Turns the skybox on or off.
  • .reset() Restarts the current project.
  • .whileLoading(function) Adds a function to run while the project is loading.
  • .openURL("url") Opens the given URL in a browser. Needs to include "https://" for mobile devices.

In the example below, we use the Mixiply.currentTime property to hide our cube after a certain amount of time has passed.

Random

The Random class is a helper class that we can use to get some random numbers and vectors.

The available methods include:

  • .value() Returns a random value between 0.0 [inclusive] and 1.0 [inclusive].
  • .range(min, max) Return a random float number between min [inclusive] and max [inclusive].
  • .rotation() Returns a random rotation.
  • .insideCircle(raduis) Returns a random point inside a circle with the specified radius. This is referring to a 2-dimensional circle and so the y value of the vector will be 0.
  • .insideSphere(radius) Returns a random point inside a sphere with the specified radius.
  • .onSphere(radius) Returns a random point on the surface of a sphere with the specified radius.

Below are some ways that you could use the Random class.

Try changing the colour, position or rotation of your cube using the Random class.

Player

In Mixiply we can use the Player class to access some useful properties information about you (the player). This can be helpful when you want objects to be placed or rotated in relation to the player, as well as many other uses.

The properties that the Player class contains includes many of the properties common with MixiplyObject and one other for the camera:

  • .camera Returns the camera of the player as an object. Note: this property is read only.
  • .position Returns the current position of the plater as a vector.
  • .rotation Returns the current rotation of the player as a vector.
  • and the directions which return a vector pointing to that direction of the player: .forward, back, .up, .down, .right, .left.

One good example of when you can use the Player properties is the .lookAt() method. As you may have seen in an earlier tip, we can pass the Player.position to the .lookAt() function and this will rotate the boject to face the player. Put it in the update() function and the object's gaze will follow the player wherever they go. Try it out!

Menu and MenuItem

With these two classes we are able to create custom menu items.

The Menu class handles the editing of the in-app menu while running a project and the MenuItem class represents one item of the in-app menu inside a project. The in-app menu is found at the bottom of the screen for the mobile apps, and on the left controller for the mixed reality app.

The Menu class has one property - Menu.menu - this returns an instance of the in-app menu as an object so you can customise it.

Before we start creating menu items, there are a range of optional properties that a MenuItem can take when it is created. There are:

  • .key("iconKey") This is used to identify the menu item and can be any string you want it to be. Try to name it something meaningful.
  • .icon("iconUrl") Changes the icon of the menu item.
  • .color(colour) Changes the colour of the menu item. Can be a colour from the Color class (Color.colour) or an RGB value.
  • .text("text") Changes the text of the menu item.
  • .textColor(Color.colour) Changes the text colour of the menu item. Can be a colour from the Color class (Color.colour) or an RGB value.
  • .action(function()) Adds an action to the menu item when it is triggered. This can be a function that you have already written somewhere else in your code, or you can write the function inside the brackets just like we did with the onClick() function.

There are two ways that you can create a new menu item and it really up to personal preference.

  • We can use Menu.add("key") which takes the key as an argument and then we can set all of the properties by stringing them together just like we did when we changed our primitive shapes.
  • We can also use Menu.setMenuItem("key", "iconUrl", color, "text", textColor, actionFunction) which can accepts all of the properties as arguments. You can pass all, some or none of these arguments to the function.

Let's make a menu item that turns the skybox on when clicked. We won't use an icon in the example, but you should experiment with icons to see how they look.

Once our menu and menu items are created, we have some functions that we can use to edit them. These are part of the Menu class and so we will need to attach them to our menu instance.

An error has occurred. This application may no longer respond until reloaded. Reload 🗙