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

How to code a game in Mixiply

Note: Launch the game from QR code in the Sharing tab up above to play the game.

This tutorial will explain some of the basics of writing a game in Mixiply and incrementally go through different stages of making a game.

When a new project is created, you'll start with three functions:

var gameLoaded;
var fishModel;

function setup(args){
    Asset.load("https://mixiplycontent.blob.core.windows.net/u-damonmurphy/Models/Fish/BarramundiFish.gltf", "fish");
    gameLoaded = true;
}

setup(): Inside setup you can load assets, initialize variables and setup anything which could take a while to load, slowing down your game while it's playing. It will run as soon at the project is launched and before anything starts or is added to the world.

function start(args){
    fishModel = Asset.create("fish")
        .setPosition(0, 0, 1)
        .setScale(0.1, 0.1, 0.1);
}

start(): Start is where you want to add anything to the world or initialize any objects before the main game loop begins. This win run only once after setup has completed.

function update(args){
    fishModel.rotate(0, 1, 0);
}

update(): Update is a function which runs every 16-17 milliseconds. This is where things should be updated while the game is running.


Setting up a basic sphere

Let's load up a basic sphere.

A sphere is one of the primitive objects which are already loaded into Mixiply so we can add it in the world in our start function. All we need is a global (at the top of the page, outside of the functions) variable (var) named sphere which will "point" to our sphere object when we load it into the world.

.setPosition(0, 0, 5)

This sets where in the world the sphere object will be placed. The three parameters are the x, y, z axes. We want the sphere to be in front of us so we'll leave the x axis as 0 and we don't want to it be any higher or lower than us so we'll leave the y axis as 0, however, we do want it to be a little bit further away so we'll set the z axis as 5.

.setScale(0.5, 0.5, 0.5)

Setting the scale is how we make the sphere bigger or smaller, we don't want the sphere to be too big and take up the entire screen or too small and hard to see so we'll set all values to 0.5. If you want the sphere to be wider you could increase the first (x) value, or taller the second (y.) value or longer the third (z) value.

 .setColor(Color.red);

Here we set the color of the sphere to red!


NOTE: It's common for things will be formatted this way to make them easier to read but this could also be written out all in one line like this:

sphere = Primitive.sphere().setPosition(0, 0, 5).setScale(0.5, 0.5, 0.5).setColor(Color.red);


Make the sphere follow you

This sphere would be cooler if it moved, lets make it follow us.

All we need to change is our update function. Here, everytime the function is called, our sphere will look in our direction and move a little bit closer.

.lookAt(Player.position)

Our sphere points in our direction (we're Player.position) so when it moves "forward" it's moving toward us.

TIP: If you wanted the sphere to move to another object in the world, you can also put yourObjectsNameHere.position in the brackets instead of Player.position.

.move(Vector.multiply(Vector.forward, 0.005));

Here the sphere moves a little bit in the "forward" direction we just set. The second parameter (0.005) is the speed it will move, if you want the sphere to move really fast you can increase it or if you want it to move really slow you can decrease it. You can also make the sphere move backward by making this a negative number.


Give the sphere a face

Instead of making the sphere a color we can give it a face. I'll give my sphere a dog eating ramen face I made.

All we needed to change was two things

Remove the setColor(); function on our sphere and replace it with .texture("image url here");

.setColor(Color.Red); ------------> .texture("url");

Add .rotate to our sphere in the update method. This is because sphere textures aren't always drawn from the "forward" position so if we don't rotate it, the sphere won't be looking at us!

.rotate(0, -90, 0);

Rotate works on the same axes as our move method (x, y, z). I only need to rotate my ramendog face on the y axis but you may need to use x and z too.


Lets add game objectives

A game isn't much fun without an objective! Let's add one in.

Add some HP

We'll declare two more global variables at the top of the page, first hitPoints, which is a number (or integer) which we can deduct from when our player is hit and an uninitialized variable, hitPointsUI, which will point to our UI text element when it's created.

As text UI elements are included in Mixiply, we don't need to put anything in our setup function yet. So we'll just add our UI text inside the start() function.

hitPointsUI = UI.text("HP = " + hitPoints.toString())

This makes it so our global variable, hitPointsUI is now pointing to our UI text element, so if we ever need to change it, we can with hitPointsUI which we'll do later. Inside our UI.text() we have a string or text which is what will be shown on the screen. As our hitPoints is a number or integer, we'll also use the toString() method on that.

This means our UI text will now say "HP = 100".

But there's a few other things we need to do to make sure the text is in the right place.

.setParent(Player.camera)

By setting the parent as Player.camera, the text will follow us around as we move, so we can always see the text on the screen!

TIP: We could also give our ramendog sphere a HP which follows it around by putting sphere in the brackets, so it would be .setParent(sphere)

.setLocalPosition(-0.024, 0.054, 0.11)

Before we set our sphere's position (setPosition) which changed where the sphere was rendered in the world. This time we're doing the same thing but it's now in relation to the parent (which is now our camera). So all we need to do is change the position a little bit so the text won't be right in the middle of the screen.

NOTE: When setting LocalPosition, if the third parameter(x, y, z), z axis, isn't set, the object will usually be rendered inside that object and won't be visible. If we don't set the z axis with our camera as the parent, we won't be able to see the text as it will be behind the camera!


Add functionality for a player/sphere interaction

Now that we have HP, lets make a way to lose it!

Now if the ramendog sphere is too close it'll take away our hitpoints.

Inside our update function we've added a conditional if statement. If ramendog is close to us, we reduce the hitpoints by 1 and rerender the UI text. Lets break it down some more.

if(){
}

This means the stuff inside these curly brackets {} will only happen if the stuff inside the regular brackets () is true.

if(today == friday && weather == sunny)

We use the and operator (&&) to test if two things are both true. In the example above, the condition will only be true if it's friday AND sunny, if it's friday and cloudy, nothing will happen. Here we want to make sure we're close to the sphere on both the x and z axis. The stuff inside the brackets will only run if we're close on both at once because we used and (&&).

NOTE: In this game things are only moving horizontally but if you made a game where things were also moving vertically, you may also want to check here for the vertical distance(.y).

Math.abs()

This is an in-built javascript function which returns the ABSolute value. By absolute it means the value won't be negative so if we did Math.abs(-100) it would give us 100.

(sphere.position.x - Player.position.x)

Here we calculate the difference between our position and the sphere's position. Because of the way Mixiply's graphing works, if x = 1 or x = -1 that would be the same distance away from the player, just in a different direction, which is why we need the absolute value.

hitPoints--;

hitPoints (which we made 100) are reduced by one. (same as writing hitPoints -1).

UI.changeText(hitPointsUI, "HP = " + hitPoints.toString());

Just changing our hitPoints won't update the UI so we also need to do that. Here we use the variable which we assigned to our UI text before, hitPointsUI, and give it a new value, so it will now display "HP = 99" and so on.


Extra addition

Make some more interactions, like changing the text color for different HP.

We can also make the HP go down slower with some math magic.

Add an animation

Lets make this look a little bit cooler!


We can use the already made Effects in Mixiply to spawn an effect.

Effect.laserimpact(Player.position);

When ramendog is in range he will now fire a laserimpact directly at the player. Effect.lasterimpact takes one parameters, the impact position of the laser.

NOTE: Effect.lightning exists in Mixiply but right now it will not despawn so to save some rendering power we're using a nice laserimpact.


Make multiple spheres

Now that our sphere is doing what we want, lets make it a bit more challenging and add some more spheres.

Including timer


https://mixiply.com/api/usefulstuffs/content/timer-behaviour


First we're going to need to add a timer behavior. Luckily this has already been made for us so we just include it in our project. To do this, navigate to the </> Code tab and click the includes.txt file as above, then paste the following:

Timer gives us the ability to do things after a set time. E.g.

timer.addAction(3, function(){
         Primitive.sphere()
                .setPosition(0, 0, 5)
                .setScale(0.3, 0.3, 0.3)
                .setColor(Color.yellow);
});

timer.addAction() is the function we need to call to queue something to happen, this takes two parameters. The first (3 in this case) is the amount of time before that action will happen in seconds. The second is a function. If we didn't have function to call we could also create a new function like above. This function renders a sphere. So in this case we can render a sphere after 3 seconds.

We can also put other functions we're made inside, for example if we had a function called createSphere like this:

function createSphere(){
    Primitive.sphere()
           .setPosition(0, 0, 5)
           .setScale(0.3, 0.3, 0.3)
           .setColor(Color.yellow);
}

then we can use this:

timer.addAction(3, createSphere);

this will do the same thing as our earlier code.

Adapting our project to deal with multiple spheres

Adding multiple spheres

Now sphere's will spawn every 5 seconds, forever! Lets go through some of the changes.

var timer;
var maxSpheres = 20;
var spheres = [];

We have a couple of changes at the top. We've added a variable called timer which we talked about above, and changed sphere into spheres which now equals []. This is an empty array, or group of things. We will fill this array with spheres in our code. We've also got maxSpheres to we won't make an infinite amount of spheres.

In our start method we are no longer adding a sphere! Instead we are instantiating our timer to:

timer = Behaviour.create("timer").start();

and then we're calling a function which is this piece of code:

addSphere();

Lets go through that function.

var sphere = Primitive.sphere()
        .setPosition(0, 0, 5)
        .setScale(0.3, 0.3, 0.3)
        .texture("https://mixiplycontent.blob.core.windows.net/u-damonmurphy/ramen%20dog/ramendogxs.png");

This may look familiar, it's the same as the ramendog sphere we were making in start() before.

spheres.push(sphere);

spheres is our new global variable which is an array. Arrays can hold lots of stuff and by using the "push()" function, we're giving it one more thing to hold on to, one of our new sphere's.

if (spheres.length < maxSpheres){
   timer.addAction(5, addSphere);
}

Lastly we're using using that timer feature we just included, this time to add a sphere after 5 seconds. This is sounded by another if statement to ensure we don't make too many spheres. In this case spheres.length will give us the current amount of sphere's our array is holding.

NOTE: this timer call is inside the addSphere function, calling the addSphere function. This is called recursion. Recursive things happen forever unless they're stopped and things happening forever can be bad for programs. It's always a good idea to watch out for recursive actions.

TIP: Decrease the first variable (time in seconds, currently 5) of the timer.addAction() function to make the sphere spawn faster and increase the maxSpheres number to spawn more than 20 spheres.

Updating multiple spheres

Lets look at our update function to see how we're getting all these different spheres to chase us.

Our update() function has changed! Everything is now inside another statement:

spheres.forEach( function(sphere){
  
});

This is a loop, it's going through our spheres array and looking at each element, or sphere, inside. Basically, instead of one sphere updating, we're now looking through our arraying and updating each sphere the same way we used to update one.


Spawning spheres in different places on the map

It would be funner if we didn't know where the ramendog sphere were spawning so lets make this randomised in our code.

Understanding some of the things we've used:

Math.random();

This will return a random number between 0 and 1 e.g. 0.543, 0.199 etc.

var x = Math.random() * 5;
var z = (Math.random() * 5) + 1;

var x and z are now giving us a random position between -5 and 5 with the z position also adding 1 which means the minimum distance a sphere will spawn from the player is 1 to avoid them spawning too close.

if (xSign < 0.5){
    x *= -1;
}


if (zSign < 0.5){
    z *= -1;
}

This code is deciding if the number should be positive or negative (spawn in front or behind, to the left or to the right) as Math.random() < 0.5 has a 50% chance of being true.

x *= -1;

This flips the number to a negative, so if the number were 4.56 it will become -4.56

TIP: We could also use setParent(Player.position) here to ensure spheres spawn within a certain distance of the player.


Using onClickDown to create counterplay.

Now we have lots of spheres coming toward us but nothing to get rid of them, let's create a way to get rid of the spheres

When adding our sphere in the addSphere function we are now doing one more thing before we add the sphere to our spheres array.

.onClickDown(function(hitInfo){
            var hitObj = hitInfo.hitObject;
            hitObj.move(Vector.multiply(Vector.left, 1));
            if (Math.abs(hitObj.position.x) - Math.abs(Player.position.x) > 7 
            || Math.abs(hitObj.position.z) - Math.abs(Player.position.z) > 7){
                removeSphere(hitObj);
            }
        });

This is a on click function attached to our sphere so when we click on it, it will now be pushed back(Vector.left) by 1. By creating a new variable to hold hitInfo.hitObject called hitObj, we can save some unnecessary work. Next all we have to do is work out how far away our sphere is. We do this with an if statement which checks if the x or z axis are greater than 7 away from the player x or z axis. If you want the sphere to disappear at shorter or longer ranges, you can increase or decrease the 7 in the code above.

If the sphere is greater than 7 away, we call a new function, removeSphere() and give it the hitObj (our sphere which is more than 7 away).

Tip: Add an Effect here like Effect.laserimpact(hitObj.position) to turn those clicks into awesome animation

function removeSphere(sphereToRemove){
    const removeAtIndex = spheres.findIndex(sphere => sphere === sphereToRemove);
    if (removeAtIndex !== -1) {
        spheres.splice(removeAtIndex, 1);
        MixiplyObject.destroy(sphereToRemove);
    }
}

This function does two important things. It first removes the sphere from our spheres array. This means when our update() function is called, the sphere will no longer be moved toward the player. Next it calls a function, MixiplyObject.destroy() which takes the sphere as a parameter. This removes the rendered sphere from the game world. We have now succesfully defeated our first sphere!

Let's go into the code a bit more:

const removeAtIndex = spheres.findIndex(sphere => sphere === sphereToRemove);

All items in an array have an index which is where that item is in the array. Arrays start at 0 so if we had three spheres in the world, they would be index 0, index 1 and index 2 in our array. This removeAtIndex is a function which goes through spheres, similar to the forEach in our update() function and finds which position, or index, the sphereToRemove has.

if (removeAtIndex !== -1) {
        spheres.splice(removeAtIndex, 1);
        MixiplyObject.destroy(sphereToRemove);
}

If our removeAtIndex were to be -1 that means we couldn't find sphereToRemove in our array and we shouldn't try to splice (or remove) the object because it's not in spheres.

If removeAtIndex is a different number, we can then splice (remove) the element from the array. spheres.splice() takes two parameters, start index(in this case, the index of our sphereToRemove) and the number to remove, in this case, 1 sphere.

Next all we have to do is remove the game object so it won't be rendered anymore. Here we use MixiplyObject.destroy() which takes one parameters, the object to destroy, our sphereToRemove.

Now that's all done, get out there and destroy some spheres!

Add some world objects

We can add floor and walls with the following:

Add this in to your setup() function to get it working. Primative.plane is a great way to make a flat surface!

Tip: Change the .texture url to another image!

Load in some assets

Now we can add something to the setup function, these assets are loaded before the game starts to help with performance but they aren't place in the world yet so lets do that.

Inside our start() function we can add in our assets! This is the same as adding in our spheres from earlier except we use Asset.create() and give this function the string we called our asset (inside the setup() function at the end of the Asset.load()). setSize() is the same as calling setScale() but will scale all axis with the same amount (so for example setSize(2) is the same as setScale(2, 2, 2).

Making the game re-playable

We've changed a lot here to give the game the ability to replay. Lets have a look at some of the changes.

var restartGameUI;
var restartGameHitBox;

We have two new global variables, one for holding the text text and one to act as a hitbox.

restartGameUI = UI.text("Click to play again.")
                .setPosition(0, 0, 5)
                .setVisible(false);
    
    UI.changeColor(restartGameUI, Color.red);
    
    restartGameHitBox = Primitive.cube()
            .setScale(0,0,0)
            .setParent(restartGameUI)
            .setLocalPosition(0,0,0)
            .setLocalRotation(0,0,0)
            .setVisible(false)
            .onClickDown(function (hitInfo) {						
                return;
            });

In our start() function we're now loading in our text and a sphere. Make sure to use setVisible(false) so they don't show up until we need them.

function update(args){
    if (hitPoints == 0){
        startAgain();
        return;
    }
}

At the beginning of our update function we're now checking if the hitPoints are equal to 0 and if they are, we're using a new function, startAgain();

function startAgain(){
    spheres.forEach(function(sphere){
        removeSphere(sphere);
    });


    restartGameUI.setVisible(true);


    restartGameHitBox.setScale(4,0.5,0.1)
        .onClickDown(function (hitInfo) {						
            if (hitInfo.didHitObject){
                newGame();  
            }  
        });
    restartGameHitBox.setVisible(false);
}

This function removes all the spheres currently in the game and then sets our start again text and hitbox cube to visisble. In our hithox cube we also add an onClickDown function which if clicked takes us to a new function, newGame(): which is where we'll reset things back to the start.

function newGame(){
    hitPoints = 1000;
     
    UI.changeText(hitPointsUI, "HP = " + Math.floor(hitPoints / 10).toString());
    restartGameUI.setVisible(false);
    restartGameHitBox.setScale(0, 0, 0)
        .onClickDown(function(hitInfo){
            return;
        });
    addSphere();
}

newGame() simply puts things back to how they were at the start, resetting the hitpoints, hiding the restart text and hitbox and adding spheres back into the world with the same addSphere function we were using before.


TIP: Add more game functionality such as an option for increased difficulty or decreased difficulty by adding more text and hitboxes which increases or decreases a variable in your code.

Check out an alternative version of the game I created in the </> Code section of this project!


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