Skip navigation

. Code

Programming in group
The first thing we wanted to be sure about, was to have a clear code that anyone in the group could easily read. Even if we had a leading programmer, each one of us worked on a part of the application. This meant that, in the end, we would have to piece together the code created from three different minds.
The best way to organize ourselves was to have, in the beginning, only one person working on the code and defining the main structure of the script: name of most important variables, where to put what, etc.

///////////////////////////////////////////////////////////////// // MODES //////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// /// NAMING GAME-MODES int MODE_SINGLE_PLAYER = 1; int MODE_TIME_CHALLENGE = 2; int MODE_MULTIPLAYER = 3; int MODE_GALLERY = 4; // NAMING SECTIONS int START_SCREEN = 0; int REGISTRATION = 1; int STORY_01 = 2; int PLAY_OR_GALLERY = 15; int MUSEUM_LOCALIZATION = 3; int MENU_GAME_MODE = 4; int NARRATIVE = 5; ...

To improve the code readability, we put a lot of comments, characterizing them with some hierarchy (bigger box of comments for main sections, for example) that communicates what you’re working on, and describes what each part of the code does.

// ****************************************************************** // ** SINGLE PLAYER ********************************************** // ****************************************************************** void drawSinglePlayer (int sezione, int mode) { // NARRATIVE **************************************************** if(sezione == NARRATIVE) { // IN_THIS_MUSEUM ////////////////////////////////// if(mode == IN_THIS_MUSEUM) { moodSpook = "saluta"; // changes spook's mood in the animation ...

Spook’s code is 3965 lines long, so, to make it less “heavy” to our eyes, we divided everything in different tabs, trying to keep them independent, so we could work separately and, in the end, just add the content of each tab into the main code.
The first tab contains all the variables, classes and functions declarations; there are five other tabs for the main sections of the game: Introduction, Single Player, Time Challenge, Multiplayer and the Gallery. The last tab, called Logic, contains all the commands to be executed when some events happen on the phone.

We used tabs to make the code more readable and to let us work separately

We also gave intuitive names to sections (sezione = SELECT_GAME_MODE), subsections (mode = MUSEUM_LOCALIZATION) and variables. When the code became longer, we could easily find the right line we needed just with the Find… command available in Mobile Processing, by typing in the name of the subsection we had to work on.

Animations and objects
We used some customized functions and classes for the animations.
Spook is actually drawn with a Class. He changes his facial expression and he moves differently during the game. With this method, in the main code we just specified Spook’s mood (happy, sad, surprised, etc) and whether or not we wanted to display the smoky clouds behind him. That made it really easy to make him move and change expression at the same time whenever we wanted to.

class Spook { // draws floating spook in different moods Spook (String mood, int frameAttuale, boolean fumo) { if(frameAttuale%40 < 20) i=i+1; else i=i-1; // draws cloudy smoke behind spook if(fumo==true) image(fumini,0,0); if(mood=="felice") { image(spook_felice, 130, 180+i/2); } else if(mood=="triste") { image(spook_triste, 130, 180+i/2); } else if(mood=="esulta") { image(spook_esulta, 130, 180+i/2); } else if(mood=="saluta") { image(spook_saluta, 130, 180+i/2); } else if(mood=="racconta") { image(spook_racconta, 130, 180+i/2); } else if(mood=="paura") { if(frameAttuale%3==0) k=+1; if(frameAttuale%3==1) k=-1; if(frameAttuale%3==2) k=0; image(spook_paura, 130+k, 180+i/4); } else if(mood=="giravolta") { image(spook_giravolta,k*86,0,86,92,130,180+i/2); ++j; k=j; if(j>8 && j<= 18) k = -9+j; if(j>6 && j<=8) k = 6; if(j>=16 && j<=18) k = 6; if(j>18) k=1; // da qui disegna spook fermo! } else if(mood=="occhei") { image(spook_occhei,k*83,0,83,92,130,180+i/2); if(k<4) { ++k; } } else if(mood=="piange") { image(spook_piange,k*75,0,75,92,130,180); if(frameAttuale%4==0) { if(k==0) j=+1; else if(k==4) j=-1; k = k+j; } } } }
moodSpook = "saluta"; spook = new Spook(moodSpook, frameCount, false);

To make the application more appealing we used many transitions: in horizontal selections, in the main menus, in the text of the final question and in the narrative section. The movements are defined by the easeTo() function (thanks to MasQuest), which gives the impression of deceleration: the closer you get to the final position, the slower the object moves on the screen.

int easeTo(int currentOriginal, int targetOriginal, int speed) { // make values large for math int current = currentOriginal * 1000; // make current value large for math (e.g. 2 becomes 2000) int target = targetOriginal * 1000; // make target value large for math (e.g. 33 becomes 33000) // do math to calculate our next value int change = target - current; // find out how much change there is (e.g. 33000 - 2000 = 31000) int changeLittle = change / speed; // make the change a little change (e.g. 31000 / 4 = 7750) int next = current + changeLittle; // change the current value a little (e.g. 2000 + 7750 = 9750) // make next value small for screen next = next / 1000; // if our little change was so little that we didn't move... if(next == currentOriginal){ next = targetOriginal; // our next step is our target } return next; // return our next value (e.g. 9750 / 1000 = 9, remember that we started with 2) }

In the Time Challenge game, a timer starts when the child enters a room and counts down the passed seconds. If the time finishes before completing the room, the game the game will stop and go in stand-by, waiting for a new room to be visited.
So, in each frame of the draw() function, we checked how much time had passed since the starTime (number of milliseconds counted at the moment the child entered the room). If that value is bigger than the maximum time available (timeMax variable), the current section changes, interrupting the normal game.

void timeCheck(){ if((millis() - starTime) > timeMax){ sezione = TIME_IS_UP; } }

In the end, we added some “explosive” animation whenever something great happens. When the child completes a room, or when he finishes the game, a stream of colored confetti appears behind Spook. In the setup() we create an array of ellipses (named pallino[]) of random colors/sizes/positions, and, with the coriandoli() function we make them appear and move on the screen. When we call the function, we just have to specify how many confetti we want in the animation: the more confetti we call, the more impressing will be the final effect.

// CREATES CONFETTI for(int p=0;p<=100;p++) { //create random coords int randomX = random(0, width); int randomY = random(330, 350); int randomW = random(1,8); int randomT = random(20,255); //randomX = constrain(randomX,0+randomW,width); //randomY = constrain(randomY,0,height-randomW); // store data pallinoX = append(pallinoX, randomX); pallinoY = append(pallinoY, randomY); pallinoW = append(pallinoW, randomW); pallinoT = append(pallinoT, randomT); pallinoTime = append(pallinoTime, random(0,10)); pallinoDirection = append(pallinoDirection, -1); pallinoSpeed = append(pallinoSpeed, random(5,10)); pallinoColor = append(pallinoColor, 100); }
// CONFETTI ANIMATION void coriandoli(int numCoriandoli, String direzione) { // CORIANDOLI for(p=0; p<=numCoriandoli-2; p++) { println("PALLINO"+pallinoX[p]); pallinoTime[p] -= 1; // modifico la X e la Y per farlo mouvere :o if(pallinoTime[p]<=0) { //if(frameCount%2==0) pallinoDirection[p] = random(-5,5); if(frameCount%2==0) pallinoX[p] = pallinoX[p]+pallinoDirection[p]; pallinoX[p] = constrain(pallinoX[p],0+pallinoW[p]+3,width); //if(direzione=="salita") pallinoY[p] -= pallinoSpeed[p]; //random(4,10); //else pallinoY[p] = pallinoSpeed[p]; pallinoColor[p] += 4; } // disegno il pallino solo se ? ancora nello schermo if(pallinoY[p]>-10){ pallino(pallinoX[p],pallinoY[p],pallinoW[p],pallinoT[p],pallinoTime[p],pallinoColor[p]); pallino(pallinoX[p],pallinoY[p],pallinoW[p],pallinoT[p],pallinoTime[p],pallinoColor[p]); } // pioggia infinita di coriandoli if(numCoriandoli==100) { if(pallinoY[p]<=-10) { pallinoY[p] = random(330, 350); pallinoColor[p] = 150; } } } }

Camera
Our application asks the child to take pictures with the phone camera. Again we referred to MasQuest code: we had to import a library, define some variables in the setup() and use a function that controls the camera.

import processing.video.*; Capture myCapture; // to use a capture object void setup() { myCapture = new Capture(this); // to use the camera ...
// CAMERA FUNCTION void showCamera(int x, int y, int w, int h, PImage imageBackground) { noLoop(); myCapture.show(x,y,w,h); image(imageBackground, 0, 0); } void hideCamera() { myCapture.hide(); loop(); }

An (almost) working prototype
Our prototype is almost full working. It does not work with an external database nor with RFID signal, but it’s predisposed for that. You can play with just four paintings in our demo version, but we used arrays just as if we were getting datas from an external database; we stored paintings characteristics (title, authors and data) and, more important, the correct/wrong clues the child could find inside them. We created a double array: the four horizontal lines represent the four paintings, while each single value is referred to a clue (in the same order they appear on screen: skull, food, ship, etc). A 0 value means there’s no instance of that clue in the painting, while the 1 value is for correct answers.

int icons_painting[][] = { {0,0,1,1,0,1,1,0,1}, {0,0,0,0,1,1,0,1,1}, {0,0,0,1,0,1,1,0,1}, {0,0,0,1,0,1,0,1,0} };

In this way, we recall the correct value just by using our main variables: let’s pretend we need to know about jewels in the second painting. At the current screen, we will have this variable values we can work with:

mode = PAINT_2        // which is equal to 1 modeIcon = JEWEL    // which is equal to 4

We just need to call the array icon_paintings[mode][modeIcon] and it will give us the value of jewels in the paint n.2: we will get the value in the second line (because mode = PAINT_2 = 1, remember arrays count starts from 0), at the fifth column (modeIcon = JEWEL = 4).
When the child discovers one correct clue, the value changes to 2, which makes the clue icon disappear on the screen.

if(icons_painting[mode][modeIcon] == 1) { // if the clues is correct totPunti = totPunti + 10; icons_painting[mode][modeIcon] = 2; }

The same system has been used for the final question: we have an array with the correct answers (the correct icon values that the child has to choose in order to get points) and another one with the child choices. In this way we can display exactly the picture that the child chose from the list and, by checking in the correct_answers[] array, giving him points only if he did good.

int correct_answers[] = { // correct answers to final question 0,7,2,6,3}; int given_answers[] = { // given answers to final question 0,0,0,0,0};

Issues and future improvements
Our prototype has a working demo of both Single Player and Time Challenge, other than the Gallery. We developed also two versions of the game: one for museums that allow taking photos, and one for those who forbid that. We also have an English and an Italian version of the game.
Unfortunately we didn’t have time to develop the Multiplayer. It would have meant dealing with bluetooth and, more important, an external server that helped coordinating the game interaction between two or more people.

An important issue is the total size of the application. It takes more than one minute to load on the mobile phone because of the big amount of memory taken by the stored images.. We probably lack some knowledges about file compression and how to distribute the loading phases in different moments of the game. We think that an external server would help in order to avoid the storage of too many data into the phone, maybe by saving somewhere else the pictures taken by the child and downloading them again only when it’s necessary.

Code source
- Spook / photocamera / english (PDF | 73 Kb)
- Spook / photocamera / italian (PDF | 75 Kb)
- Spook / without photocamera / english (PDF | 75 Kb)
- Spook / without photocamera / italian (PDF | 75 Kb)

Spook | the game | graphics | technology | code | process / user studies | downloads | credits