Une histoire de pizzas : les étapes

Après une petite pause, voici le sixième épisode de ma série d’articles retraçant la conception d’un mini-jeu vidéo. Comme d’habitude, vous êtes invité·es à lire les articles précédents pour vous y retrouver.

Aujourd’hui, on va faire simple : on va afficher la liste des étapes que le joueur devra suivre pour avancer dans le jeu. Le gros du travail se fera dans l’article suivant.

Pour ce faire, on va commencer par déclarer les étapes en JavaScript :

// On déclare les étapes dans un objet...
const steps = [
    { id: 'STEP_ROLL_OUT_DOUGH', label: 'Étaler la pâte avec les doigts' },
    { id: 'STEP_GRAB_TOMATO', label: 'Aller chercher la sauce tomate sur l’étagère' },
    { id: 'STEP_SPREAD_TOMATO', label: 'Verser la sauce tomate sur la pizza' },
    { id: 'STEP_GRAB_MOZZA', label: 'Aller chercher la mozzarella dans le frigo' },
    { id: 'STEP_SPREAD_MOZZA', label: 'Disposer la mozzarella sur la sauce tomate' },
    { id: 'STEP_GRAB_PIZZA_1', label: 'Prendre la pizza' },
    { id: 'STEP_PUT_PIZZA_IN_OVEN', label: 'Mettre la pizza au four' },
    { id: 'STEP_BAKE_PIZZA', label: 'Cuire 5 secondes' },
    { id: 'STEP_GRAB_PIZZA_2', label: 'Prendre la pizza' },
    { id: 'STEP_DELIVER_PIZZA', label: 'Emporter la pizza jusqu’au passe-plat' },
    { id: 'STEP_FINISH' },
];

const app = new Vue({
    el: '#app',
    data: {
        size: BOARD_SIZE,
        store: gameStore,
        // ... que l'on passe ensuite à data pour pouvoir y accéder depuis la vue
        steps,
    },

    // ...
});

C’est tout bête, rien de bien méchant ici. Il nous faut désormais afficher cette liste dans le HTML.

<div id="app">
    <div class="steps">
        <div class="steps-title">Recette</div>

        <transition v-for="(step, index) in steps" :key="step.id">
            <div
                v-if="step.label"
                :class="['steps-item', { current: step.id === currentStep }]"
            >
                <div class="steps-item-index">{{ index + 1 }}</div>
                <div class="steps-item-label">{{ step.label }}</div>
            </div>
        </transition>
    </div>

    <!-- ... -->
</div>

Vous remarquerez peut-être que je déclare une class .current pour indiquer quelle est l’étape en cours. Néanmoins, je fais appel à une variable currentStep que nous n’avons pas encore déclarée. Il s’agit d’une valeur qui va évoluer au fil du temps à travers des actions liées aux clics du joueur, c’est-à-dire dans notre système onClickSystem. Cette valeur doit donc être déclarée dans le store du jeu. Retour dans le JavaScript :

let gameStore = [
    /*
        On ajoute une nouvelle entité au store pour mémoriser l'étape
        courante. C'est cette valeur qui va permettre d’avancer dans le jeu
        plus tard.
    */
    { id: 'currentStep', value: 'STEP_ROLL_OUT_DOUGH' },

    // ...
];

const app = new Vue({
    // ...

    computed: {
        // On déclare une donnée "computed" : il s'agit d'une donnée qui
        // est calculée depuis une autre donnée déjà stockée dans data
        // (ici, le store). Il s'agit juste de simplifier le code du
        // template HTML.
        currentStep() {
            return getEntity(this.store, "currentStep").value;
        },
    },
});

Avec ça, on a quasiment terminé pour cette fois-ci, on va juste ajouter un peu de CSS pour rendre le tout un poil plus joli.

/* Du CSS pour afficher le bloc des instructions à gauche de la zone de jeu */
#app {
    display: flex;
    justify-content: center;
}

/*
   Et du CSS pour styler les instructions elles-mêmes. Ironiquement, il y a
   besoin de plus de CSS pour cette partie que pour la zone de jeu.
*/
.steps {
    width: 30%;
    margin-right: 1rem;
    padding: .5rem 1rem;

    font-family: sans-serif;

    background-color: #eee;
    border-radius: .5rem;
}

.steps .steps-title {
    margin-bottom: 1rem;
    padding-bottom: .25rem;

    text-align: center;

    border-bottom: 1px solid #ccc;
}

.steps .steps-item {
    display: flex;
    padding: .25rem .5rem;

    align-items: baseline;

    color: #666;
    font-size: .8rem;

    border: .25rem solid transparent;
}

.steps .steps-item.current {
    color: #000;
    font-weight: bold;

    border-color: #00dbcb;
    border-radius: .5rem;
}

.steps .steps-item .steps-item-index {
    display: flex;
    width: 1.25rem;
    height: 1.25rem;
    margin-right: .25rem;

    flex-shrink: 0;
    align-items: center;
    justify-content: center;

    color: #fff;

    background-color: #666;
    border-radius: 50%;
}

.steps .steps-item.current .steps-item-index {
    color: #000;

    background-color: #00dbcb;
}

Avant de finir cet article, je veux juste pointer une petite différence vis-à-vis du jeu initial. J’ai fait le choix ici d’afficher toutes les instructions pour simplifier légèrement le code et ne pas rentrer dans des détails inutiles d’implémentation. Dans le jeu des Ergogames, seulement deux instructions sont affichées à la fois : l’étape courante et l’étape suivante. Si le détail technique n’est pas important, il l’est cependant d’un point de vue utilisabilité. Cette partie a beaucoup évolué avec les retours des utilisateurs et utilisatrices, notamment pour satisfaire la contrainte de l’écran réduit sur mobile. Ce n’est d’ailleurs même pas moi qui aie fait les derniers changements.

Il ne vous reste plus qu’à tester le résultat du code de cet article ici. Il n’y a rien de plus à faire qu’à regarder puisque nous n’avons pas encore implémenté les actions qui vont permettre d’avancer dans le jeu. Ce sera l’objet du prochain article.

Revenir à la série