Stomazzo

Descrizione

L'app di questo mese è un gioco di magia, ho voluto sfruttare diverse modalità tecnologiche per dare l'illusione che il mago sia in grado di indovinare la carta scelta dello spettatore.

Il contesto d'uso è diverso dei soliti giochi: chi vuole utilizzarla, dopo averla installata nella schermata home, deve necessariamente leggere le istruzioni d'uso che spiegano dettagliatamente il miglior modo di proporla al pubblico.

Vengono usate diverse API Javascript, alcune poco note, e purtroppo non del tutto supportate. Mi perdonino i possessori di iPhone se stavolta ho fatto un'app che è poco compatibile con i loro telefoni.

Come al solito, ecco la scheda tecnica dell'app.

Stomazzo

Url
https://stomazzo.it
Github
https://github.com/polesello/stomazzo
Data di uscita
1 aprile 2024
Caratteristiche
SpeechSynthesis, vibrazione, MediaDevices, web-NFC
Dispositivi
Android
Browser
Chrome

Funzionamento generale

L'app contiene cinque magie diverse, ossia cinque modi tramite i quali il mago fa scegliere una carta allo spettatore per poi indovinarla.

Il processo è il seguente:

  1. Lo spettatore sceglie una carta del mazzo, che poi compare a pieno schermo
  2. Lo spettatore gira il telefono sottosopra e l'appoggia sul tavolo, in modo che lo schermo sia rivolto verso il basso
  3. Il mago indovina la carta scelta, o comunque interagisce con lo spettatore.

Tutte le magie partono dopo 10 secondi che il telefono è stato girato sottosopra, e vengono annullate se il telefono torna in posizione normale.

Per maggiori informazioni su come riconoscere la posizione del telefono si veda l'app Piano in tasca.

Di seguito il codice che si occupa di fare il riconoscimento della posizione sottosopra.

function checkUpsideDown(event) {
    // Controlla se il telefono viene messo a faccia in giù
    // e dopo 10 secondi fa partire la funzione magica

    if (magicFunction) {
        // facedown è un booleano che indica se il telefono è a faccia in giù
        // calcolato in base alle proprietà beta e gamma dell'evento deviceorientation
        // magicTimer è un timeout che fa partire la funzione magica dopo 10 secondi
        const enteringFaceDown = Math.abs(event.beta) > 150 && Math.abs(event.gamma) < 30
        const exitingFaceDown = Math.abs(event.beta) < 130 && Math.abs(event.gamma) > 50
        if (!isFaceDown && enteringFaceDown) {
            isFaceDown = true
            magicTimer = setTimeout(magicFunction, 10000)
        } 
        if (isFaceDown && exitingFaceDown) {
            isFaceDown = false
            clearTimeout(magicTimer)
        }
    }
}

Modalità 2 di picche

Qui c'è poco da dire, dopo 10 secondi la carta scelta dello spettatore viene cambiata sempre con il 2 di picche. Questa modalità è compatibile con tutti i telefoni e funziona tramite questa semplicissima funzione magica.

function changeCard() {
    // Cambia la carta scelta con il 2 di picche
    document.querySelector('#scelta .card').setAttribute('src', 'cards/2S.svg')
}

Modalità annuncio vocale

Dopo 10 secondi una voce sintetizzata annuncia che il giocatore ha scelto la carta, ma non dice quella giusta. Tramite un semplice calcolo mentale, il mago sarà in grado di indovinare la carta scelta.

function sayCard() {
    // faccio dire non il nome della carta scelta, ma una carta diversa
    // tolgo 7 al numero della carta
    // e vado di un seme indietro, secondo l'ordine degli semi Cuori Quadri Fiori Picche
    // Il mago dovrà quindi calcolare la carta scelta veramente dal giocatore
    // aggiungendo 7 e andando di un seme avanti
    const cardId = document.querySelector('#scelta .card').dataset.cardid

    const SUITS = ['H', 'D', 'C', 'S']
    const number = parseInt(cardId)
    const suit = cardId.slice(-1)
    const newNumber = number > 7 ? number - 7 : number + 6
    const newSuit = SUITS[(SUITS.indexOf(suit) + 3) % 4]
    const newCard = document.querySelector('img[src="cards/' + newNumber + newSuit + '.svg"]')

    const frase = localStorage['frase-scelta']
    const msg = new SpeechSynthesisUtterance(frase + ' ' + newCard.getAttribute('alt'))
    window.speechSynthesis.speak(msg)
}

La variabile frase contiene una semplice frase predefinita come "Hai scelto il" che è possibile personalizzare dal menù iniziale.

Viene quindi creato un messaggio vocale tramite l'oggetto SpeechSynthesisUtterance che aggiunge alla frase predefinita il nome della carta, che è contenuto nell'attributo HTML alt.

Anche questa modalità è compatibile con tutti i telefoni.

Modalità vibrazione

In questa modalità viene usata l'API navigator.vibrate per produrre una sequenza di punti e linee (vibrazioni corte e lunghe) che il mago dovrà decodificare per risalire al nome della carta. La tabella di decodifica è nella pagina delle istruzioni, ho cercato di inventare una codifica che minimizzi il numero di vibrazioni emesse ma sia anche facile da imparare.

Questa modalità non è supportata da iOS ma dovrebbe essere disponibile per tutti gli Android.

function vibrateCard() {
    const cardId = document.querySelector('#scelta .card').dataset.cardid
    const pattern = getMorsePattern(cardId)
    navigator.vibrate(pattern)
}

Non è finita qui...

Lo scrittura del manuale d'istruzioni del mago mi ha portato via più tempo del previsto, e quindi non ho ancora completato la parte tecnica, lo farò nei prossimi giorni.

È sempre gradito un riscontro tramite questo modulo.