working version with camera and telegram
This commit is contained in:
parent
cc6d42c512
commit
38e74bf8d0
181
game.js
181
game.js
|
@ -1,6 +1,9 @@
|
|||
const { QLog, undefinedOrNull } = require('quanto-commons');
|
||||
const player = require('node-wav-player');
|
||||
const { Telegraf } = require('telegraf')
|
||||
const TelegramBot = require('node-telegram-bot-api');
|
||||
const fs = require('fs');
|
||||
const { exec } = require("child_process");
|
||||
|
||||
if(process.platform !== 'darwin') var gpio = require('rpi-gpio');
|
||||
|
||||
const telegramBotToken = '5472909337:AAGH269wNGa9u99ekJqHqXEHfi0knpV7IFU';
|
||||
|
@ -15,10 +18,14 @@ TelLog.enableLogs(['warn']);
|
|||
GlobalLog.headPadding = 30;
|
||||
TelLog.headPadding = 30;
|
||||
|
||||
const bot = new Telegraf(telegramBotToken);
|
||||
// const bot = new Telegraf(telegramBotToken);
|
||||
const bot = new TelegramBot(telegramBotToken, {polling: true});
|
||||
|
||||
// debounce der buttons in ms
|
||||
const bounceMS = 400;
|
||||
const bounceMS = 800;
|
||||
|
||||
// Game Reset Start after ms
|
||||
const startReset = 4000;
|
||||
|
||||
// ist an wenn im kind mode (erw LED is aus)
|
||||
const childLED = 37;
|
||||
|
@ -31,22 +38,27 @@ const failSwitch = 35;
|
|||
|
||||
// warte auf spielstart wenn auf HIGH
|
||||
const startButton = 32;
|
||||
const startButton_GPIO = 12;
|
||||
// beende spiel wenn auf HIGH
|
||||
// const finishButton = 31;
|
||||
const finishButton = 22;
|
||||
const finishButton_GPIO = 25;
|
||||
// faile spiel wenn auf HIGH
|
||||
// const failButton = 29;
|
||||
const failButton = 21;
|
||||
const failButton_GPIO = 9;
|
||||
// wechsle kind/erwachen Modus + LED
|
||||
const toggleButton = 33;
|
||||
const toggleButton_GPIO = 13;
|
||||
|
||||
// wird je nach modus gesetzt und abgespielt wenn start
|
||||
const backgroundGrown = "northsouth.wav";
|
||||
const backgroundGrown = "jaws.wav";
|
||||
const jeopardy = "jeopardy.wav";
|
||||
const backgroundChild = "northsouth.wav";
|
||||
// wird zufallig zu zufaelligen momenten abgespielt (erw mode)
|
||||
const erschreckSounds = [ "ziege.wav", "scream.wav", "lough.wav" ];
|
||||
const erschreckSounds = [ "ziege.wav", "scream.wav", "laugh.wav", "cavallerie.wav", "gulp.wav" ];
|
||||
// wird nach fester zeit + random oder spaeter nach der besten zeit abgespielt (erw mode)
|
||||
const stresserSound = "sharks.wav";
|
||||
// const stresserSound = "sharks.wav";
|
||||
// wird bei fail abgespielt (zonk)
|
||||
const failSound = "zonk.wav";
|
||||
// hurra wird bei finish abgespielt
|
||||
|
@ -72,44 +84,35 @@ var STATE = STATES.FINISH;
|
|||
var MODE = GROWN;
|
||||
var GAME = {};
|
||||
|
||||
var botCTX;
|
||||
var chatId;
|
||||
|
||||
async function sendBotGroupMsg(id,msg) {
|
||||
if(botCTX) {
|
||||
botCTX.telegram.sendMessage(id,msg);
|
||||
}
|
||||
function sendBotGroupImg(chat_id, photo, caption) {
|
||||
GlobalLog.info( chat_id, photo);
|
||||
bot.sendPhoto(chat_id, photo, {
|
||||
caption: caption
|
||||
});
|
||||
}
|
||||
async function sendBotGroupImg(chat_id, caption, photo) {
|
||||
if(botCTX) {
|
||||
botCTX.telegram.sendPhoto( chat_id, photo, caption );
|
||||
}
|
||||
}
|
||||
async function sendBotMsg(msg) {
|
||||
if(botCTX) {
|
||||
botCTX.reply(msg);
|
||||
}
|
||||
}
|
||||
async function sendBotImg(img) {
|
||||
if(botCTX) {
|
||||
botCTX.replyWithPhoto({ source: img});
|
||||
function sendBotMsg(msg) {
|
||||
if(chatId) {
|
||||
bot.sendMessage(chatId, msg);
|
||||
}
|
||||
}
|
||||
|
||||
async function setup() {
|
||||
GlobalLog.start('Running');
|
||||
bot.start((ctx) => {
|
||||
let message = `Bot aktiv und beobachtet. Benutze /stats um die Bestenliste zu sehen`;
|
||||
ctx.reply(message);
|
||||
TelLog.note('Bot started');
|
||||
botCTX=ctx;
|
||||
});
|
||||
bot.command('stats', async (ctx) => {
|
||||
await ctx.replyWithPhoto({ source: '/root/hotwire-js/img/bestgrown.png' });
|
||||
await ctx.reply(`Bester Erwachsener mit nur ${best.grown} sek`);
|
||||
await ctx.replyWithPhoto({ source: '/root/hotwire-js/img/bestchild.png' })
|
||||
await ctx.reply(`Bestes Kind mit nur ${best.child} sek`);
|
||||
});
|
||||
bot.launch();
|
||||
function setup() {
|
||||
|
||||
// bot.start((ctx) => {
|
||||
// let message = `Bot aktiv und beobachtet. Benutze /stats um die Bestenliste zu sehen`;
|
||||
// ctx.reply(message);
|
||||
// TelLog.note('Bot started');
|
||||
// botCTX=ctx;
|
||||
// });
|
||||
// bot.command('stats', async (ctx) => {
|
||||
// await ctx.replyWithPhoto({ source: '/root/hotwire-js/img/bestgrown.png' });
|
||||
// await ctx.reply(`Bester Erwachsener mit nur ${best.grown} sek`);
|
||||
// await ctx.replyWithPhoto({ source: '/root/hotwire-js/img/bestchild.png' })
|
||||
// await ctx.reply(`Bestes Kind mit nur ${best.child} sek`);
|
||||
// });
|
||||
// bot.launch();
|
||||
|
||||
GlobalLog.note('Setting up GPIOs');
|
||||
|
||||
|
@ -135,10 +138,18 @@ async function setup() {
|
|||
gpio.output(erwLED, false);
|
||||
});
|
||||
|
||||
gpio.setup(finishButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(toggleButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(startButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(failButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(finishButton, gpio.DIR_IN, gpio.EDGE_FALLING, () => {
|
||||
exec(`raspi-gpio set ${finishButton_GPIO} pu`);
|
||||
});
|
||||
gpio.setup(toggleButton, gpio.DIR_IN, gpio.EDGE_FALLING, () => {
|
||||
exec(`raspi-gpio set ${toggleButton_GPIO} pu`);
|
||||
});
|
||||
gpio.setup(startButton, gpio.DIR_IN, gpio.EDGE_FALLING, () => {
|
||||
exec(`raspi-gpio set ${startButton_GPIO} pu`);
|
||||
});
|
||||
gpio.setup(failButton, gpio.DIR_IN, gpio.EDGE_FALLING, () => {
|
||||
exec(`raspi-gpio set ${failButton_GPIO} pu`);
|
||||
});
|
||||
|
||||
gpio.on('change', (channel, value) => {
|
||||
if(bounce[channel] === true) return;
|
||||
|
@ -189,11 +200,14 @@ function start(value) {
|
|||
STATE = STATES.STARTED;
|
||||
// set all params for next game, then start counter and event timer
|
||||
if(MODE === GROWN) {
|
||||
GAME.events.push({ sound: backgroundGrown, start: 0});
|
||||
GAME.events.push({ sound: stresserSound, start: 30+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 20+getRandomInt(10) });
|
||||
if(getRandomInt(7) > 2) {
|
||||
GAME.events.push({ sound: jeopardy, start: 1});
|
||||
} else {
|
||||
GAME.events.push({ sound: backgroundGrown, start: 1});
|
||||
}
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 15+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 30+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 50+getRandomInt(10) });
|
||||
GAME.mode = GROWN;
|
||||
GAME.fail = failSound;
|
||||
GAME.finish = finishSound;
|
||||
|
@ -201,8 +215,7 @@ function start(value) {
|
|||
}
|
||||
if(MODE === CHILD) {
|
||||
GAME.events.push({ sound: backgroundChild, start: 0});
|
||||
GAME.events.push({ sound: stresserSound, start: 40+getRandomInt(10)});
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10)});
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 30+getRandomInt(10)});
|
||||
GAME.mode = CHILD;
|
||||
GAME.fail = failSound;
|
||||
GAME.finish = finishSound;
|
||||
|
@ -221,26 +234,38 @@ async function finish(value) {
|
|||
if(STATE === STATES.STARTED) {
|
||||
GlobalLog.note('You made it in', GAME.runTime, 'seconds');
|
||||
GlobalLog.note(GAME);
|
||||
player.stop();
|
||||
playSound(GAME.finish);
|
||||
STATE = STATES.FINISH;
|
||||
clearInterval(GAME.countTimer)
|
||||
GAME.events = [];
|
||||
await sendBotImg('/tmp/img.png');
|
||||
await sendBotMsg(`Gewinner in nur ${GAME.runTime} Sekunden!`);
|
||||
await sendBotGroupImg(groupid, `Gewinner in nur ${GAME.runTime} Sekunden!`, '/tmp/img.png');
|
||||
if(MODE === GROWN) {
|
||||
if(GAME.runTime < best.grown) {
|
||||
await sendBotMsg(`Neue Bestzeit bei den Erwachsenen!`);
|
||||
best.grown = GAME.runTime
|
||||
// todo copy best img
|
||||
GlobalLog.note('Getting new image!')
|
||||
exec(`raspistill -t 1000 -st -o /tmp/last.png`, (err) => {
|
||||
if(err) {
|
||||
GloblLog.error('Could not get image', err);
|
||||
}
|
||||
} else {
|
||||
if(GAME.runTime < best.child) {
|
||||
await sendBotMsg(`Neue Bestzeit bei den Kindern!`);
|
||||
best.child = GAME.runTime
|
||||
// todo copy best img
|
||||
GAME.events = [];
|
||||
var msg;
|
||||
var img;
|
||||
if(MODE === GROWN) {
|
||||
if(GAME.runTime < best.grown) {
|
||||
best.grown = GAME.runTime;
|
||||
msg = `Gewinner in nur ${GAME.runTime} Sekunden!\nNeue Bestzeit bei den Erwachsenen!`;
|
||||
fs.copyFile('/tmp/last.png', '/tmp/bestgrown.png', (err) => {});
|
||||
} else {
|
||||
msg = `Gewinner in nur ${GAME.runTime} Sekunden!`;
|
||||
}
|
||||
} else {
|
||||
if(GAME.runTime < best.child) {
|
||||
sendBotMsg(`Neue Bestzeit bei den Kindern!`);
|
||||
best.child = GAME.runTime
|
||||
msg = `Gewinner in nur ${GAME.runTime} Sekunden!\nNeue Bestzeit bei den Kindern!`;
|
||||
fs.copyFile('/tmp/last.png', '/tmp/bestchild.png', (err) => {});
|
||||
} else {
|
||||
msg = `Gewinner in nur ${GAME.runTime} Sekunden!`;
|
||||
}
|
||||
}
|
||||
}
|
||||
sendBotGroupImg(groupid, '/tmp/last.png', msg);
|
||||
});
|
||||
} else {
|
||||
GlobalLog.warn('FINISH not in state', STATE);
|
||||
}
|
||||
|
@ -253,6 +278,7 @@ function fail(value) {
|
|||
STATE = STATES.FAIL;
|
||||
clearInterval(GAME.countTimer)
|
||||
GAME.events = [];
|
||||
player.stop();
|
||||
} else {
|
||||
GlobalLog.debug('FAIL not in state', STATE);
|
||||
}
|
||||
|
@ -274,15 +300,36 @@ function toggle(value) {
|
|||
}
|
||||
}
|
||||
|
||||
function playSound(file){
|
||||
function playSound(file, runTime){
|
||||
if(!file) { GlobalLog.error('Sound not defined.'); return; }
|
||||
GlobalLog.info("Play sound : ", file);
|
||||
if(GAME.playing) {
|
||||
GlobalLog.debug("Stopping old soundfile", GAME.playing);
|
||||
player.stop();
|
||||
}
|
||||
GAME.playing = file;
|
||||
// Do not stop background sound
|
||||
if(GAME.runTime > 1) {
|
||||
GAME.playing = file;
|
||||
}
|
||||
player.play({ path: `wav/${file}`, sync: true }).then(() => { delete GAME.playing })
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
TelLog.start('Starting bot...');
|
||||
bot.on('message', function (msg) {
|
||||
const chatId = msg.chat.id;
|
||||
const resp = msg;
|
||||
TelLog.info(`${chatId}: ${resp.text}`);
|
||||
if(resp.text === '/stats') {
|
||||
TelLog.info(`Dump stats to channel ${groupid}`);
|
||||
if (fs.existsSync('/tmp/bestchild.png')) {
|
||||
sendBotGroupImg(groupid, '/tmp/bestchild.png', `Bestes Kind mit ${best.child} Sekunden.`);
|
||||
}
|
||||
if (fs.existsSync('/tmp/bestgrown.png')) {
|
||||
sendBotGroupImg(groupid, '/tmp/bestgrown.png', `Bester Erwachsener mit ${best.grown} Sekunden.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
218
game.js-2
218
game.js-2
|
@ -1,218 +0,0 @@
|
|||
|
||||
if(process.platform !== 'darwin') var gpio = require('rpi-gpio');
|
||||
|
||||
const player = require('node-wav-player');
|
||||
|
||||
// debounce der buttons in ms
|
||||
const bounceMS = 400;
|
||||
|
||||
// ist an wenn im kind mode (erw LED is aus)
|
||||
const childLED = 37;
|
||||
// ist and wenn im erwachsenen Mode (kind LED ist aus)
|
||||
const erwLED = 38;
|
||||
// status : ist an wenn in ruhe position, blinkt, wenn gestartet, ist aus bei fail
|
||||
const statusLED = 40;
|
||||
// setze auf HIGH wenn fail (klingel relais)
|
||||
const failSwitch = 35;
|
||||
|
||||
// warte auf spielstart wenn auf HIGH
|
||||
const startButton = 32;
|
||||
// beende spiel wenn auf HIGH
|
||||
const finishButton = 31;
|
||||
// faile spiel wenn auf HIGH
|
||||
const failButton = 29;
|
||||
// wechsle kind/erwachen Modus + LED
|
||||
const toggleButton = 33;
|
||||
|
||||
// wird je nach modus gesetzt und abgespielt wenn start
|
||||
const backgroundGrown = "jeopardy.wav";
|
||||
const backgroundChild = "northsouth.wav";
|
||||
// wird zufallig zu zufaelligen momenten abgespielt (erw mode)
|
||||
const erschreckSounds = [ "ziege.wav", "scream.wav", "lough.wav" ];
|
||||
// wird nach fester zeit + random oder spaeter nach der besten zeit abgespielt (erw mode)
|
||||
const stresserSound = "sharks.wav";
|
||||
// wird bei fail abgespielt (zonk)
|
||||
const failSound = "zonk.wav";
|
||||
// hurra wird bei finish abgespielt
|
||||
const finishSound = "kidscheering.wav";
|
||||
|
||||
const GROWN=1;
|
||||
const CHILD=2;
|
||||
|
||||
const STATES = {
|
||||
STARTED: 'started',
|
||||
FINISH: 'finshed',
|
||||
FAIL: 'failed'
|
||||
};
|
||||
|
||||
const bounce = {};
|
||||
|
||||
var STATE = STATES.FINISH;
|
||||
var MODE = GROWN;
|
||||
var GAME = {};
|
||||
|
||||
function setup() {
|
||||
console.log('Setting up GPIOs');
|
||||
|
||||
if(process.platform === 'darwin') {
|
||||
setTimeout(start, 500);
|
||||
setTimeout(fail, 3500);
|
||||
setTimeout(start, 4000);
|
||||
setTimeout(finish, 9000);
|
||||
setTimeout(fail, 10000);
|
||||
setTimeout(finish, 11000);
|
||||
return;
|
||||
}
|
||||
gpio.setup(failSwitch, gpio.OUT, () => {
|
||||
gpio.output(failSwitch, false);
|
||||
});
|
||||
gpio.setup(statusLED, gpio.OUT, () => {
|
||||
gpio.output(statusLED, true);
|
||||
});
|
||||
gpio.setup(childLED, gpio.OUT, () => {
|
||||
gpio.output(childLED, true);
|
||||
});
|
||||
gpio.setup(erwLED, gpio.OUT, () => {
|
||||
gpio.output(erwLED, false);
|
||||
});
|
||||
|
||||
gpio.setup(finishButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(toggleButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(startButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(failButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
|
||||
gpio.on('change', (channel, value) => {
|
||||
if(bounce[channel] === true) return;
|
||||
console.log('Change',channel, value);
|
||||
bounce[channel] = true;
|
||||
setTimeout(() => { bounce[channel] = false; console.log('Debounced', channel); }, bounceMS);
|
||||
switch(channel) {
|
||||
case startButton:
|
||||
start(value);
|
||||
break;
|
||||
case finishButton:
|
||||
finish(value);
|
||||
break;
|
||||
case failButton:
|
||||
fail(value);
|
||||
break;
|
||||
case toggleButton:
|
||||
toggle(value);
|
||||
break;
|
||||
default:
|
||||
console.log('Alert! Unknown button change',channel);
|
||||
}
|
||||
});
|
||||
console.log('Done. Game logic started. Waiting for input');
|
||||
}
|
||||
|
||||
function gameTimer() {
|
||||
console.log('game timer called');
|
||||
GAME.events.forEach((el) => {
|
||||
if(el.start === GAME.runTime) {
|
||||
console.log('Event :', el);
|
||||
playSound(el.sound);
|
||||
}
|
||||
});
|
||||
GAME.runTime++;
|
||||
}
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
function start(value) {
|
||||
GAME = {
|
||||
events: [],
|
||||
runTime: 0
|
||||
};
|
||||
if(STATE === STATES.FINISH || STATE === STATES.FAIL) {
|
||||
STATE = STATES.STARTED;
|
||||
};
|
||||
if(STATE === STATES.FINISH || STATE === STATES.FAIL) {
|
||||
STATE = STATES.STARTED;
|
||||
};
|
||||
if(STATE === STATES.FINISH || STATE === STATES.FAIL) {
|
||||
STATE = STATES.STARTED;
|
||||
// set all params for next game, then start counter and event timer
|
||||
if(MODE === GROWN) {
|
||||
GAME.events.push({ sound: backgroundGrown, start: 0});
|
||||
GAME.events.push({ sound: stresserSound, start: 30+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 20+getRandomInt(10) });
|
||||
GAME.mode = GROWN;
|
||||
GAME.fail = failSound;
|
||||
GAME.finish = finishSound;
|
||||
GAME.runtime = 0;
|
||||
}
|
||||
if(MODE === CHILD) {
|
||||
GAME.events.push({ sound: backgroundChild, start: 0});
|
||||
GAME.events.push({ sound: stresserSound, start: 40+getRandomInt(10)});
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10)});
|
||||
GAME.mode = CHILD;
|
||||
GAME.fail = failSound;
|
||||
GAME.finish = finishSound;
|
||||
GAME.runtime = 0;
|
||||
}
|
||||
console.log('Starting new game', JSON.stringify(GAME, 2, null));
|
||||
console.log(GAME);
|
||||
GAME.countTimer = setInterval(gameTimer, 1000);
|
||||
} else {
|
||||
console.log('START not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function finish(value) {
|
||||
console.log('Finish');
|
||||
if(STATE === STATES.STARTED) {
|
||||
console.log('You made it in', GAME.runTime, 'seconds');
|
||||
playSound(GAME.finish);
|
||||
STATE = STATES.FINISH;
|
||||
clearInterval(GAME.countTimer)
|
||||
GAME.events = [];
|
||||
} else {
|
||||
console.log('FINISH not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
console.log('Fail');
|
||||
if(STATE === STATES.STARTED) {
|
||||
console.log('You failed after', GAME.runTime, 'seconds');
|
||||
playSound(GAME.fail);
|
||||
STATE = STATES.FAIL;
|
||||
clearInterval(GAME.countTimer)
|
||||
GAME.events = [];
|
||||
} else {
|
||||
console.log('FAIL not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(value) {
|
||||
if(STATE === STATES.FINISH || STATE === STATES.FAIL) {
|
||||
console.log('Toggle');
|
||||
if(MODE === CHILD) {
|
||||
MODE = GROWN;
|
||||
// set all values for GROWN mode
|
||||
}
|
||||
if(MODE === GROWN) {
|
||||
MODE = CHILD;
|
||||
// set all values for CHILD mode
|
||||
}
|
||||
} else {
|
||||
console.log('Toggle not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function playSound(file){
|
||||
console.log("Play sound : ", file);
|
||||
if(global.GAME.playing) {
|
||||
console.log("Stopping old soundfile", global.GAME.playing);
|
||||
player.stop();
|
||||
}
|
||||
global.GAME.playing = file;
|
||||
player.play({ path: `wav/${file}`, sync: true }).then(() => { delete global.GAME.playing })
|
||||
}
|
||||
|
||||
setup();
|
209
game.js-global
209
game.js-global
|
@ -1,209 +0,0 @@
|
|||
|
||||
if(process.platform !== 'darwin') var gpio = require('rpi-gpio');
|
||||
|
||||
const player = require('node-wav-player');
|
||||
|
||||
// ist an wenn im kind mode (erw LED is aus)
|
||||
const childLED = 37;
|
||||
// ist and wenn im erwachsenen Mode (kind LED ist aus)
|
||||
const erwLED = 38;
|
||||
// status : ist an wenn in ruhe position, blinkt, wenn gestartet, ist aus bei fail
|
||||
const statusLED = 40;
|
||||
// setze auf HIGH wenn fail (klingel relais)
|
||||
const failSwitch = 35;
|
||||
|
||||
// warte auf spielstart wenn auf HIGH
|
||||
const startButton = 32;
|
||||
// beende spiel wenn auf HIGH
|
||||
const finishButton = 31;
|
||||
// faile spiel wenn auf HIGH
|
||||
const failButton = 29;
|
||||
// wechsle kind/erwachen Modus + LED
|
||||
const toggleButton = 33;
|
||||
|
||||
// wird je nach modus gesetzt und abgespielt wenn start
|
||||
const backgroundGrown = "jeopardy.wav";
|
||||
const backgroundChild = "northsouth.wav";
|
||||
// wird zufallig zu zufaelligen momenten abgespielt (erw mode)
|
||||
const erschreckSounds = [ "ziege.wav", "scream.wav", "lough.wav" ];
|
||||
// wird nach fester zeit + random oder spaeter nach der besten zeit abgespielt (erw mode)
|
||||
const stresserSound = "sharks.wav";
|
||||
// wird bei fail abgespielt (zonk)
|
||||
const failSound = "zonk.wav";
|
||||
// hurra wird bei finish abgespielt
|
||||
const finishSound = "kidscheering.wav";
|
||||
|
||||
const GROWN=1;
|
||||
const CHILD=2;
|
||||
|
||||
global.STATES = {
|
||||
STARTED: 'started',
|
||||
FINISH: 'finshed',
|
||||
FAIL: 'failed'
|
||||
};
|
||||
|
||||
const bounce = {};
|
||||
|
||||
global.STATE = STATES.FINISH;
|
||||
global.MODE = GROWN;
|
||||
global.GAME = {};
|
||||
|
||||
function setup() {
|
||||
console.log('Setting up GPIOs');
|
||||
|
||||
if(process.platform === 'darwin') {
|
||||
setTimeout(start, 500);
|
||||
setTimeout(fail, 3500);
|
||||
setTimeout(start, 4000);
|
||||
setTimeout(finish, 9000);
|
||||
setTimeout(fail, 10000);
|
||||
setTimeout(finish, 11000);
|
||||
return;
|
||||
}
|
||||
gpio.setup(failSwitch, gpio.OUT, () => {
|
||||
gpio.output(failSwitch, false);
|
||||
});
|
||||
gpio.setup(statusLED, gpio.OUT, () => {
|
||||
gpio.output(statusLED, true);
|
||||
});
|
||||
gpio.setup(childLED, gpio.OUT, () => {
|
||||
gpio.output(childLED, true);
|
||||
});
|
||||
gpio.setup(erwLED, gpio.OUT, () => {
|
||||
gpio.output(erwLED, false);
|
||||
});
|
||||
|
||||
gpio.setup(finishButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(toggleButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(startButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(failButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
|
||||
gpio.on('change', (channel, value) => {
|
||||
if(bounce[value] === true) return;
|
||||
console.log('Change',channel, value);
|
||||
bounce[value] = true;
|
||||
setTimeout(() => { bounce[value] = false; console.log('Debounced', value); }, 1000);
|
||||
switch(channel) {
|
||||
case startButton:
|
||||
start(value);
|
||||
break;
|
||||
case finishButton:
|
||||
finish(value);
|
||||
break;
|
||||
case failButton:
|
||||
fail(value);
|
||||
break;
|
||||
case toggleButton:
|
||||
toggle(value);
|
||||
break;
|
||||
default:
|
||||
console.log('Alert! Unknown button change',channel);
|
||||
}
|
||||
});
|
||||
console.log('Done. Game logic started. Waiting for input');
|
||||
}
|
||||
|
||||
function gameTimer() {
|
||||
console.log('game timer called');
|
||||
global.GAME.events.forEach((el) => {
|
||||
if(el.start === global.GAME.runTime) {
|
||||
console.log('Event :', el);
|
||||
playSound(el.sound);
|
||||
}
|
||||
});
|
||||
global.GAME.runTime++;
|
||||
}
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
function start(value) {
|
||||
global.GAME = {
|
||||
events: [],
|
||||
runTime: 0
|
||||
};
|
||||
if(global.STATE === global.STATES.FINISH || global.STATE === STATES.FAIL) {
|
||||
global.STATE = global.STATES.STARTED;
|
||||
// set all params for next game, then start counter and event timer
|
||||
if(global.MODE === GROWN) {
|
||||
global.GAME.events.push({ sound: backgroundGrown, start: 0});
|
||||
global.GAME.events.push({ sound: stresserSound, start: 30+getRandomInt(10) });
|
||||
global.GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: getRandomInt(10) });
|
||||
global.GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10) });
|
||||
global.GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 20+getRandomInt(10) });
|
||||
global.GAME.mode = GROWN;
|
||||
global.GAME.fail = failSound;
|
||||
global.GAME.finish = finishSound;
|
||||
global.GAME.runtime = 0;
|
||||
}
|
||||
if(global.MODE === CHILD) {
|
||||
global.GAME.events.push({ sound: backgroundChild, start: 0});
|
||||
global.GAME.events.push({ sound: stresserSound, start: 40+getRandomInt(10)});
|
||||
global.GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10)});
|
||||
global.GAME.mode = CHILD;
|
||||
global.GAME.fail = failSound;
|
||||
global.GAME.finish = finishSound;
|
||||
global.GAME.runtime = 0;
|
||||
}
|
||||
console.log('Starting new game', JSON.stringify(global.GAME, 2, null));
|
||||
console.log(global.GAME);
|
||||
global.GAME.countTimer = setInterval(gameTimer, 1000);
|
||||
} else {
|
||||
console.log('START not in state', global.STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function finish(value) {
|
||||
console.log('Finish');
|
||||
if(global.STATE === global.STATES.STARTED) {
|
||||
console.log('You made it in', global.GAME.runTime, 'seconds');
|
||||
playSound(global.GAME.finish);
|
||||
global.STATE = global.STATES.FINISH;
|
||||
clearInterval(global.GAME.countTimer)
|
||||
GAME.events = [];
|
||||
} else {
|
||||
console.log('FINISH not in state', global.STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
console.log('Fail');
|
||||
if(global.STATE === global.STATES.STARTED) {
|
||||
console.log('You failed after', global.GAME.runTime, 'seconds');
|
||||
playSound(global.GAME.fail);
|
||||
global.STATE = global.STATES.FAIL;
|
||||
clearInterval(global.GAME.countTimer)
|
||||
global.GAME.events = [];
|
||||
} else {
|
||||
console.log('FAIL not in state', global.STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(value) {
|
||||
if(global.STATE === global.STATES.FINISH || global.STATE === global.STATES.FAIL) {
|
||||
console.log('Toggle');
|
||||
if(global.MODE === CHILD) {
|
||||
global.MODE = GROWN;
|
||||
// set all values for GROWN mode
|
||||
}
|
||||
if(global.MODE === GROWN) {
|
||||
global.MODE = CHILD;
|
||||
// set all values for CHILD mode
|
||||
}
|
||||
} else {
|
||||
console.log('Toggle not in state', global.STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function playSound(file){
|
||||
console.log("Play sound : ", file);
|
||||
if(global.GAME.playing) {
|
||||
console.log("Stopping old soundfile", global.GAME.playing);
|
||||
player.stop();
|
||||
}
|
||||
global.GAME.playing = file;
|
||||
player.play({ path: `wav/${file}`, sync: true }).then(() => { delete global.GAME.playing })
|
||||
}
|
||||
|
||||
setup();
|
209
game.js~
209
game.js~
|
@ -1,209 +0,0 @@
|
|||
|
||||
if(process.platform !== 'darwin') var gpio = require('rpi-gpio');
|
||||
|
||||
const player = require('node-wav-player');
|
||||
|
||||
// ist an wenn im kind mode (erw LED is aus)
|
||||
const childLED = 37;
|
||||
// ist and wenn im erwachsenen Mode (kind LED ist aus)
|
||||
const erwLED = 38;
|
||||
// status : ist an wenn in ruhe position, blinkt, wenn gestartet, ist aus bei fail
|
||||
const statusLED = 40;
|
||||
// setze auf HIGH wenn fail (klingel relais)
|
||||
const failSwitch = 35;
|
||||
|
||||
// warte auf spielstart wenn auf HIGH
|
||||
const startButton = 32;
|
||||
// beende spiel wenn auf HIGH
|
||||
const finishButton = 31;
|
||||
// faile spiel wenn auf HIGH
|
||||
const failButton = 29;
|
||||
// wechsle kind/erwachen Modus + LED
|
||||
const toggleButton = 33;
|
||||
|
||||
// wird je nach modus gesetzt und abgespielt wenn start
|
||||
const backgroundGrown = "jeopardy.wav";
|
||||
const backgroundChild = "northsouth.wav";
|
||||
// wird zufallig zu zufaelligen momenten abgespielt (erw mode)
|
||||
const erschreckSounds = [ "ziege.wav", "scream.wav", "lough.wav" ];
|
||||
// wird nach fester zeit + random oder spaeter nach der besten zeit abgespielt (erw mode)
|
||||
const stresserSound = "sharks.wav";
|
||||
// wird bei fail abgespielt (zonk)
|
||||
const failSound = "zonk.wav";
|
||||
// hurra wird bei finish abgespielt
|
||||
const finishSound = "kidscheering.wav";
|
||||
|
||||
const GROWN=1;
|
||||
const CHILD=2;
|
||||
|
||||
const STATES = {
|
||||
STARTED: 'started',
|
||||
FINISH: 'finshed',
|
||||
FAIL: 'failed'
|
||||
};
|
||||
|
||||
const bounce = {};
|
||||
|
||||
var STATE = STATES.FINISH;
|
||||
var MODE = GROWN;
|
||||
var GAME = {};
|
||||
|
||||
function setup() {
|
||||
console.log('Setting up GPIOs');
|
||||
|
||||
if(process.platform === 'darwin') {
|
||||
setTimeout(start, 500);
|
||||
setTimeout(fail, 3500);
|
||||
setTimeout(start, 4000);
|
||||
setTimeout(finish, 9000);
|
||||
setTimeout(fail, 10000);
|
||||
setTimeout(finish, 11000);
|
||||
return;
|
||||
}
|
||||
gpio.setup(failSwitch, gpio.OUT, () => {
|
||||
gpio.output(failSwitch, false);
|
||||
});
|
||||
gpio.setup(statusLED, gpio.OUT, () => {
|
||||
gpio.output(statusLED, true);
|
||||
});
|
||||
gpio.setup(childLED, gpio.OUT, () => {
|
||||
gpio.output(childLED, true);
|
||||
});
|
||||
gpio.setup(erwLED, gpio.OUT, () => {
|
||||
gpio.output(erwLED, false);
|
||||
});
|
||||
|
||||
gpio.setup(finishButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(toggleButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(startButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
gpio.setup(failButton, gpio.DIR_IN, gpio.EDGE_RISING);
|
||||
|
||||
gpio.on('change', (channel, value) => {
|
||||
if(bounce[channel] === true) return;
|
||||
console.log('Change',channel, value);
|
||||
bounce[channel] = true;
|
||||
setTimeout(() => { bounce[channel] = false; console.log('Debounced', channel); }, 500);
|
||||
switch(channel) {
|
||||
case startButton:
|
||||
start(value);
|
||||
break;
|
||||
case finishButton:
|
||||
finish(value);
|
||||
break;
|
||||
case failButton:
|
||||
fail(value);
|
||||
break;
|
||||
case toggleButton:
|
||||
toggle(value);
|
||||
break;
|
||||
default:
|
||||
console.log('Alert! Unknown button change',channel);
|
||||
}
|
||||
});
|
||||
console.log('Done. Game logic started. Waiting for input');
|
||||
}
|
||||
|
||||
function gameTimer() {
|
||||
console.log('game timer called');
|
||||
GAME.events.forEach((el) => {
|
||||
if(el.start === GAME.runTime) {
|
||||
console.log('Event :', el);
|
||||
playSound(el.sound);
|
||||
}
|
||||
});
|
||||
GAME.runTime++;
|
||||
}
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * max);
|
||||
}
|
||||
|
||||
function start(value) {
|
||||
GAME = {
|
||||
events: [],
|
||||
runTime: 0
|
||||
};
|
||||
if(STATE === STATES.FINISH || STATE === STATES.FAIL) {
|
||||
STATE = STATES.STARTED;
|
||||
// set all params for next game, then start counter and event timer
|
||||
if(MODE === GROWN) {
|
||||
GAME.events.push({ sound: backgroundGrown, start: 0});
|
||||
GAME.events.push({ sound: stresserSound, start: 30+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10) });
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 20+getRandomInt(10) });
|
||||
GAME.mode = GROWN;
|
||||
GAME.fail = failSound;
|
||||
GAME.finish = finishSound;
|
||||
GAME.runtime = 0;
|
||||
}
|
||||
if(MODE === CHILD) {
|
||||
GAME.events.push({ sound: backgroundChild, start: 0});
|
||||
GAME.events.push({ sound: stresserSound, start: 40+getRandomInt(10)});
|
||||
GAME.events.push({ sound: erschreckSounds[getRandomInt(2)], start: 10+getRandomInt(10)});
|
||||
GAME.mode = CHILD;
|
||||
GAME.fail = failSound;
|
||||
GAME.finish = finishSound;
|
||||
GAME.runtime = 0;
|
||||
}
|
||||
console.log('Starting new game', JSON.stringify(GAME, 2, null));
|
||||
console.log(GAME);
|
||||
GAME.countTimer = setInterval(gameTimer, 1000);
|
||||
} else {
|
||||
console.log('START not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function finish(value) {
|
||||
console.log('Finish');
|
||||
if(STATE === STATES.STARTED) {
|
||||
console.log('You made it in', GAME.runTime, 'seconds');
|
||||
playSound(GAME.finish);
|
||||
STATE = STATES.FINISH;
|
||||
clearInterval(GAME.countTimer)
|
||||
GAME.events = [];
|
||||
} else {
|
||||
console.log('FINISH not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function fail(value) {
|
||||
console.log('Fail');
|
||||
if(STATE === STATES.STARTED) {
|
||||
console.log('You failed after', GAME.runTime, 'seconds');
|
||||
playSound(GAME.fail);
|
||||
STATE = STATES.FAIL;
|
||||
clearInterval(GAME.countTimer)
|
||||
GAME.events = [];
|
||||
} else {
|
||||
console.log('FAIL not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(value) {
|
||||
if(STATE === STATES.FINISH || STATE === STATES.FAIL) {
|
||||
console.log('Toggle');
|
||||
if(MODE === CHILD) {
|
||||
MODE = GROWN;
|
||||
// set all values for GROWN mode
|
||||
}
|
||||
if(MODE === GROWN) {
|
||||
MODE = CHILD;
|
||||
// set all values for CHILD mode
|
||||
}
|
||||
} else {
|
||||
console.log('Toggle not in state', STATE);
|
||||
}
|
||||
}
|
||||
|
||||
function playSound(file){
|
||||
console.log("Play sound : ", file);
|
||||
if(GAME.playing) {
|
||||
console.log("Stopping old soundfile", GAME.playing);
|
||||
player.stop();
|
||||
}
|
||||
GAME.playing = file;
|
||||
player.play({ path: `wav/${file}`, sync: true }).then(() => { delete GAME.playing })
|
||||
}
|
||||
|
||||
setup();
|
BIN
mp3/jeopardy.mp3
BIN
mp3/jeopardy.mp3
Binary file not shown.
Binary file not shown.
BIN
mp3/scream.mp3
BIN
mp3/scream.mp3
Binary file not shown.
BIN
mp3/sharks.mp3
BIN
mp3/sharks.mp3
Binary file not shown.
BIN
mp3/ziege.mp3
BIN
mp3/ziege.mp3
Binary file not shown.
Loading…
Reference in New Issue