Kimtato, a simple physics playground

Kimtato is the name of a simple interactive demo that runs on the Ubanita platform. It is a playground of physical objects which are created by players using touch gestures on the controller. Once created, the objects can be pushed around using the two-finger gesture, we call edge input mode.

The following will discuss the making of this demo using the Ubanita Script API.

get dimensions

To position objects on the 2D scene, it can be useful to known the actual dimensions of that scene. The scene has two properties for the width (pixels) and height respectively. Using this snippet, we assign those property values to global variables W and H.

var W = _get("viewport.width");
var H = _get("viewport.height");

border

To prevent the physical moving objects from leaving the scene, we create a fence around the border of the scene. The border is created using 4 LineSegment sprites. Each LineSegment will share the same physical properties (props). A small margin is added such that the border is a bit smaller. Notice that the LineSegment does not have visual properties; it will be present but not visible.

const margin = 2;
const props = {
    lineWidth: 1,
    elasticity: 1,
    friction: 1
};

function addBorder() {
    //top
    _addLineSegment(0, {
            ax: margin,
            ay: margin,
            bx: W - margin,
            by: margin
        },
        props);
    //right 
    //bottom
    //left
}
addBorder();

let the players join

When players join the game, their controller must be setup with the correct input mode. For the Kimtato demo, the controller will accept draw and edge input. The draw input will recognize gestures using a single touch movement. The edge input is activated by two touches at the same time; an edge will be drawn.

function handlePlayerJoined(event) {
    const id = event.data.playerID;
    const ctr = _controller(id)
	
    // a player can draw shapes and push them around
    ctr.enableInput("draw");
    ctr.enableInput("edge");
	
    _player(id).set("edge.touch.fill",randomColor())
    _player(id).enableOutput("edge");
}

_on("playerJoined", handlePlayerJoined);

translate the gestures

By touching on the controller, the player can produces different gestures. As soon as a gesture is recognized, an event will be triggered. The code below registers a function to handle such events. Inside the function, the event.data.type is inspected for known gestures.

function handlePlayerGesture(event) {
    console.log(event);
    const x = (event.data.left + event.data.right) / 2;
    const y = (event.data.top + event.data.bottom) / 2;
    const w = (event.data.right - event.data.left);
    const h = (event.data.bottom - event.data.top);
    if ("rectangle" == event.data.type) {
        _addRectangle(event,x,y,w,h);
    } else if ("circle" == event.data.type) {
        _addCircle(event,x,y,w,h)
    } else if ("triangle" == event.data.type) {
        _addTriangle(event,x,y,w,h)
    } else if ("zig-zag" == event.data.type) {
        _removeAllSprites(0);
        addBorder();
    }
}

_on("gesture", handlePlayerGesture);

triangle gesture

One of the recognized gestures is the triangle. Use the x and y location of the gesture to add a Triangle sprite. The physical properties are defined by the variable physics.

function addTriangle(event,x,y,w,h) {
    _addTriangle(0, {
        fill: randomColor(),
        stroke: randomColor(),
        lineWidth: 2,
        x: x,
        y: y,
        radius: (Math.min(w, h) / 2) * scaleFactor
    }, physics);
}

main.js

It is a good practice to keep different functionality in separate files. This will help you organize the logic of bigger games and allow for better collaboration with other team members. Using the import function, all scripts are loaded upon startup.

_import("randomColor.js");
_import("border.js");
_import("join.js");
_import("gestures.js");