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");