xxxxxxxxxx
661
let gameRunning = true;
let projectInitialLayout = [];
let project = {
stickers: [],
markers: [],
room: {
layout: [],
rules: []
},
needsRefresh: true,
backgroundId: -1,
backgroundMusicId: -1,
intro: 'new game'
};
let ON = 1,
CLICK = 2,
OFF = 3,
WIN = 1,
LOSE = 2;
let images = {};
let currentWindow;
let bkgds = [];
let songs = [];
let audioOn = true;
let justStarted;
function preload() {
bkgds.push( loadImage('empty-room-background.jpg') );
bkgds.push( loadImage('room-topview.jpg') );
bkgds.push( loadImage('game_background.png') );
bkgds.push( loadImage('game_background2.jpg') );
songs.push( loadSound('audio1.mp3') ); // space
songs.push( loadSound('audio2.mp3') ); // cartoon
songs.push( loadSound('audio3.mp3') ); // fantasy
}
function toggleAudioOn(newValue) {
if (newValue==null)
audioOn = !audioOn;
else
audioOn = newValue;
select('#audioBtn').elt.innerText = (audioOn) ? '|>' : '||';
}
let sNcLogo;
function setup() {
sNcLogo = createImg('sNc_logo_small.jpg');
sNcLogo.hide();
//createCanvas(1000 * 2 / 3, 560 * 2 / 3);
createCanvas(displayWidth * 4 / 5, displayHeight * 4 / 5);
/*
// initialize project
project.stickers.push('A', 'B', 'C', 'D', 'E', 'F');
project.markers.push('a', 'b', 'c');
*/
currentWindow = [width / 12, height / 12,
width * 4 / 5, height * 4 / 5
];
let btn;
btn = createButton('Load');
btn.mousePressed(_ => {
// toggleAudioOn(false);
showPopupLoad();
});
btn.position(width * 5 / 12, 1);
btn.style('color: darkgreen');
btn = createButton('Reset');
btn.position(width * 3 / 12, 1);
btn.style('color: darkgreen');
btn.mousePressed(_ => {
//console.log('before:reset', project.room.layout);
project.room.layout =
JSON.parse(JSON.stringify(projectInitialLayout)); // clone
//console.log('after:reset', project.room.layout);
showPopupRestart();
toggleAudioOn(true);
gameRunning = true;
project.needsRefresh = true;
});
// pause icon or play icon
btn = createButton( (audioOn) ? '|>' : '||');
btn.id('audioBtn');
btn.mousePressed(_ => toggleAudioOn() );
btn.position(width * 7 / 12, 1);
btn.style('color: green; font-weight: 900;');
justStarted = false;
let currentProject = localStorage.getItem('currentProject');
if (currentProject!=null){
currentProject = JSON.parse(currentProject);
currentProject.timeStamp = Date.parse( currentProject.timeStamp);
}
/*
// Debug
console.log(currentProject.project);
console.log(currentProject.timeStamp);
//console.log(new Date()-currentProject.timeStamp);
*/
if ( (currentProject!=null) &&
(new Date()-currentProject.timeStamp<5000) ){
// if the current project is more than 5 second old, do not use it
project = currentProject.project;
// TO DO -> FINISH rebuilding the atlas
atlasData = {
atlasInfo: null,
atlas: null,
images: []
};
atlasData.atlasInfo = project.atlasInfo;
let img = new Image();
img = loadImage(currentProject.atlas, function done() {
atlasData.atlas = img;
console.log(atlasData.atlas.width, atlasData.atlas.height)
let graphics = createGraphics(atlasData.atlas.width, atlasData.atlas.height);
graphics.image(atlasData.atlas, 0, 0);
atlasData.images = [];
atlasData.atlasInfo.forEach((e, i) => {
atlasData.images.push(graphics.get(0, e[0],e[1],e[2]));
});
// replace the stickers A,B,... with the loaded images
atlasData.images.forEach((img, i) => {
let letter = project.stickers[i];
images[letter] = img;
});
// make all measures relative to the current width and height
project.room.layout = project.room.layout.map(elem=>{
//console.log( elem );
let [A,B,C,D,E] = elem;
A = ~~(A/1000*width);
B = ~~(B/1000*height);
C = ~~(C/1000*width);
D = ~~(D/1000*height);
return [A,B,C,D,E];
});
// to do -> set up the initial layout
projectInitialLayout =
JSON.parse(JSON.stringify(project.room.layout));
// reset the localstorage
localStorage.removeItem('currentProject');
project.needsRefresh = true;
});
project.needsRefresh = true;
} else {
justStarted = true; // forces to show the splash screen
}
}
function draw() {
if (justStarted){
if (project.needsRefresh){
project.needsRefresh = false;
showPopupLoad();
}
} else {
mouseDragged = null;
mouseReleased = mouseReleased2;
}
if (project.backgroundMusicId!=-1){
if ((audioOn) &&
(!songs[project.backgroundMusicId].isPlaying()) ) {
songs[project.backgroundMusicId].loop();
}
}
if (audioOn==false){
songs.forEach((song,i)=>{
song.stop();
});
}
if (project.needsRefresh) {
/*
project.room.layout.forEach(e=>console.log(e[4]));
console.log('------');
projectInitialLayout.forEach(e=>console.log(e[4]));
console.log('------');*/
strokeWeight(1);
background(220);
drawRoom();
project.needsRefresh = false;
}
}
let selectedIndex = -1;
function mousePressed(){
/*
//DEBUG
fill('red');
rect(...currentWindow);*/
if (isInside(mouseX, mouseY, currentWindow)) {
let clickedRects = project.room.layout.filter((r) => {
let x = mouseX,
y = mouseY;
x = (x - currentWindow[0]) / (4 / 5);
y = (y - currentWindow[1]) / (4 / 5);
let a = isInside(x, y, r);
//console.log(a);
return a;
});
selectedIndex = -1;
if (clickedRects.length) {
selectedIndex = project.room.layout.indexOf(clickedRects[0]);
}
}
//console.log(selectedIndex, project.room.layout[selectedIndex]);
}
function mouseReleased2() {
if (selectedIndex != -1) {
if (gameRunning) checkAllRules(selectedIndex);
}
selectedIndex = -1;
return false;
}
function isInside(x, y, rectangle) {
if (rectangle == null) return false;
/*
noFill();
stroke('red');
rect(...rectangle);
console.log('rectangle ',rectangle, ' ? ' , x,y);*/
let [rx, ry, rw, rh] = rectangle;
return (x >= rx) && (x <= rx + rw) &&
(y >= ry) && (y <= ry + rh);
}
function drawRoom() {
fill('#F0F0F0');
stroke('#000000');
translate(currentWindow[0], currentWindow[1]);
scale(4 / 5, 4 / 5);
rect(0, 0, width, height);
if (project.backgroundId != -1)
image(bkgds[project.backgroundId],
0, 0, width, height);
project.room.layout.forEach((elem, index) => {
let [x, y, w, h, id] = elem;
if (images[id])
image(images[id], x, y, w, h);
});
}
function checkAllRules(clickedOnIndex) {
for (let i = 0; i < project.room.rules.length; i++) {
let rule = project.room.rules[i];
let M, B, A; // mask,before,after
M = rule[0][clickedOnIndex];
B = rule[1][clickedOnIndex];
A = rule[2][clickedOnIndex];
console.log(M, B, A);
if (M == CLICK) {
console.log('could fire rule ' + (i + 1) + '...');;
if (doAllMatchBefore(rule)) {
console.log('applying the rule ' + (i + 1) + '...');
applyRule(rule);
project.needsRefresh = true;
return;
}
/*else {
console.log('the rule does not match!');
}*/
}
}
}
function doAllMatchBefore(rule) {
for (let i = 0; i < project.room.layout.length; i++) {
let M = rule[0][i];
let B = rule[1][i];
let A = rule[2][i];
if (M != OFF) {
//console.log( 'testing:',B,project.room.layout[i][4]);
if (B != project.room.layout[i][4])
return false;
}
}
return true;
}
function applyRule(rule) {
for (let i = 0; i < project.room.layout.length; i++) {
let M = rule[0][i];
let B = rule[1][i];
let A = rule[2][i];
let anim = rule[4][i];
if (M != OFF) {
project.room.layout[i][4] = A;
if (anim!=null)
animationFunctions[anim](i);
}
}
/*
// DEBUG
//console.log( Object.keys(animationFunctions) );
animationFunctions['wiggle'](0); // 0 is the boy
//animationFunctions['zoomOutIn'](2);
//animationFunctions['upDown'](2); // 2 is the door
animationFunctions['leftRight'](2); // 2 is the door
*/
if (rule[3]==WIN){
toggleAudioOn(false);
setTimeout( _=>{
alert('You WIN the game! (^_^) ');
},1200);
gameRunning = false;
}
if (rule[3]==LOSE){
toggleAudioOn(false);
setTimeout( _=>{
alert('You LOSE the game! \'(o_O) ');
},1200);
gameRunning = false;
}
project.room.layout.forEach(e => console.log(e[4]));
console.log( 'WIN/LOSE?' + rule[3]);
console.log('------');
}
// -------------------------------------
let atlasData;
function showPopupLoad() {
//console.log('Size:', width, height);
popupActive = true;
let transp = createDiv();
transp.style('background-color', color(255, 255, 255, 150));
transp.size(width, height);
transp.position(0, 0);
atlasData = {
bothLoaded: 0,
atlasInfo: null,
atlas: null,
images: []
};
let d = createDiv('<b>--------- Load Stick-N-Click project ---------</b><br><br><br><br><br><br><br><br>');
d.style('background-color', '#AFAFFF'); // F000F0
d.style('border', '5px solid black');
d.size(width*3/4,height*3/4);
d.position(width * 1 / 8, height * 1 / 8);
d.child( sNcLogo );
sNcLogo.size(width*4/16,height*4/16);
sNcLogo.position(width*15/32,height*2/16);
// ****** properties
d.child(createSpan('Select an atlas image (*_atlas.png):'));
d.child(fileSelect1 = createFileInput(gotFile1)); // project1_atlas.png
fileSelect1.style('background-color', 'green');
fileSelect1.style('color', 'white');
fileSelect1.style('font-size', '120%');
d.child(createSpan('<br><br><br><br>Select a *_data.json file:'));
d.child(fileSelect2 = createFileInput(gotFile2)); // project1_data.json
fileSelect2.style('background-color', 'green');
fileSelect2.style('color', 'white');
fileSelect2.style('font-size', '120%');
// ******
let b = createButton('(X)'); // close button
b.position(width * 3 / 4 + width * 1 / 8 - b.size().width - 5, height * 1 / 8 + 5);
b.mouseClicked(_ => {
ok.hide();
b.hide();
d.hide();
transp.hide();
popupActive = false;
justStarted = false;
project.needsRefresh = true;
});
let ok = createButton(' OK '); // submit button
/*ok.position(width * 3 / 4 + width * 1 / 8 - ok.size().width - 5,
height * 3 / 4 + ok.size().height - 5);*/
ok.position(width*3/8-ok.width/2,height*3/4);
ok.size(width*1/4,height*1/12);
ok.style('background-color', 'green');
ok.style('color', 'white');
ok.style('font-size', '150%');
ok.mouseClicked(_ => {
// load atlas and data, get the images
if (atlasData.bothLoaded == 2) {
let graphics = createGraphics(atlasData.atlas.width, atlasData.atlas.height);
graphics.image(atlasData.atlas, 0, 0);
atlasData.images = [];
atlasData.atlasInfo.forEach((e, i) => {
atlasData.images.push(graphics.get(0, e[0],e[1],e[2]));
});
// replace the stickers A,B,... with the loaded images
atlasData.images.forEach((img, i) => {
let letter = project.stickers[i];
images[letter] = img;
});
// make all measures relative to the current width and height
project.room.layout = project.room.layout.map(elem=>{
//console.log( elem );
let [A,B,C,D,E] = elem;
A = (A/1000*width);
B = (B/1000*height);
C = (C/1000*width);
D = (D/1000*height);
return [A,B,C,D,E];
});
projectInitialLayout =
JSON.parse(JSON.stringify(project.room.layout));
gameRunning = true;
showPopupRestart();
toggleAudioOn(true);
}
// then close
ok.hide();
b.hide();
d.hide();
transp.hide();
popupActive = false;
justStarted = false;
project.needsRefresh = true;
});
}
// atlas
function gotFile1(file) {
if (file.type === 'image') {
console.log('loaded: ' + file.name + ' ' + file.type + ' ' + file.size + ' bytes');
let img = createImg(file.data, _ => {
atlasData.atlas = img;
});
img.hide();
atlasData.bothLoaded++;
} else {
alert('select a *_atlas.png image file please!');
}
}
// atlas info
function gotFile2(file) {
if (file.type === 'application') {
console.log('loaded: ' + file.name + ' ' + file.type + ' ' + file.size + ' bytes');
project = JSON.parse(window.atob(file.data.substr(29)));
//console.log(project);
atlasData.bothLoaded++;
// then: load atlas data
atlasData.atlasInfo = project.atlasInfo;
} else {
alert('select a *_data.json file please!');
}
}
function showPopupRestart(){
setTimeout( _=>{
alert( '***Stick&Click***\n' + project.intro );
}, 300);
}
// ****************************
// ** Animations **************
// ****************************
const ease1_0_1 = (t)=> 1-2*(t*(1-t));
const easeSin = (t)=>sin(t*20)/4+1;
const easePMMP = (t)=>{
if (t<1/4) return +1;
if (t<2/4) return -1;
if (t<3/4) return -1;
return +1;
};
let animationFunctions = {
zoomSin: (placeIndex) => {
let elemToAnimate = project.room.layout[placeIndex];
if (elemToAnimate==null) return;
let initialPos = [elemToAnimate[0],elemToAnimate[1]];
let initialSize = [elemToAnimate[2],elemToAnimate[3]];
let anim = (duration)=>{
let t = duration/1000; // t in [0,1]
if (duration>=0){
// do stuff here
const k = easeSin(t);//ease1_0_1(t) + 0.01;
//console.log( t , k );
elemToAnimate[2] = ~~(initialSize[0]*k);
elemToAnimate[3] = ~~(initialSize[1]*k);
// center
elemToAnimate[0] = initialPos[0] +
~~(initialSize[0]-elemToAnimate[2])/2;
elemToAnimate[1] = initialPos[1] +
~~(initialSize[1]-elemToAnimate[3])/2;
setTimeout( ()=>anim(duration-30) , 30);
} else {
// put things back in place
[elemToAnimate[0],elemToAnimate[1]] = initialPos;
[elemToAnimate[2],elemToAnimate[3]] = initialSize;
}
project.needsRefresh = true;
};
anim(1000); // 1 secs
},
zoomOutIn: (placeIndex) => {
let elemToAnimate = project.room.layout[placeIndex];
if (elemToAnimate==null) return;
let initialPos = [elemToAnimate[0],elemToAnimate[1]];
let initialSize = [elemToAnimate[2],elemToAnimate[3]];
let anim = (duration)=>{
let t = duration/1000; // t in [0,1]
if (duration>=0){
const k = ease1_0_1(t) + 0.01;
elemToAnimate[2] = ~~(initialSize[0]*k);
elemToAnimate[3] = ~~(initialSize[1]*k);
// center
elemToAnimate[0] = initialPos[0] +
~~(initialSize[0]-elemToAnimate[2])/2;
elemToAnimate[1] = initialPos[1] +
~~(initialSize[1]-elemToAnimate[3])/2;
setTimeout( ()=>anim(duration-30) , 30);
} else {
// put things back in place
[elemToAnimate[0],elemToAnimate[1]] = initialPos;
[elemToAnimate[2],elemToAnimate[3]] = initialSize;
}
project.needsRefresh = true;
};
anim(1000); // 1 secs
},
wiggle: (placeIndex) => {
let elemToAnimate = project.room.layout[placeIndex];
if (elemToAnimate==null) return;
let initialPos = [elemToAnimate[0],elemToAnimate[1]];
let initialSize = [elemToAnimate[2],elemToAnimate[3]];
let anim = (duration)=>{
let t = duration/1000; // t in [0,1]
if (duration>=0){
// do stuff here
elemToAnimate[0] += random(-8,8);
elemToAnimate[1] += random(-8,8);
setTimeout( ()=>anim(duration-30) , 30);
} else {
// put things back in place
[elemToAnimate[0],elemToAnimate[1]] = initialPos;
}
project.needsRefresh = true;
};
anim(1000); // 1 secs
},
upDown: (placeIndex) => {
let elemToAnimate = project.room.layout[placeIndex];
if (elemToAnimate==null) return;
const SECS = 1000;
let initialPos = [elemToAnimate[0],elemToAnimate[1]];
let initialSize = [elemToAnimate[2],elemToAnimate[3]];
let hStep = 10*elemToAnimate[3]/SECS; // goes up 10%
let anim = (duration)=>{
let t = duration/SECS; // t in [0,1]
if (duration>=0){
// do stuff here
// y wrt h
elemToAnimate[1] += easePMMP(t) * hStep;
setTimeout( ()=>anim(duration-30) , 30);
} else {
// put things back in place
[elemToAnimate[0],elemToAnimate[1]] = initialPos;
}
project.needsRefresh = true;
};
anim(SECS); // 1 secs
},
leftRight: (placeIndex) => {
let elemToAnimate = project.room.layout[placeIndex];
if (elemToAnimate==null) return;
const SECS = 1000;
let initialPos = [elemToAnimate[0],elemToAnimate[1]];
let initialSize = [elemToAnimate[2],elemToAnimate[3]];
let wStep = 10*elemToAnimate[2]/SECS; // goes left 10%
let anim = (duration)=>{
let t = duration/SECS; // t in [0,1]
if (duration>=0){
// do stuff here
// x wrt w
elemToAnimate[0] += easePMMP(t) * wStep;
setTimeout( ()=>anim(duration-30) , 30);
} else {
// put things back in place
[elemToAnimate[0],elemToAnimate[1]] = initialPos;
}
project.needsRefresh = true;
};
anim(SECS); // 1 secs
},
}
// they need to be here, otherwise the click does not work on Touch devices!
function mouseDragged(){
return false;
}
function mouseReleased(){
}