Créer un simple autoclicker pour un incremental game

La triche c’est mal m’voyez ? Mais voici quand même un petit script permettant de créer facilement des autoclickers via la console du navigateur.

Cet article est destiné aux débutants, avec une recette simple : créer une fonction de clic, puis la lancer autant de fois que voulu via la console. Vous devez donc savoir ouvrir la console du navigateur et avoir des notions de base d’algorithmie.

Les incremental games

Vous connaissez sûrement le principe de incremental games, mais un petit rappel ne coûte pas cher. (Sinon sautez directement au titre suivant !)

Il s’agît de jeux ou le but principal est d'« augmenter ». En général on augmente un simple nombre comme une réserve d’argent, de ressources, mais il faut parfois augmenter plusieurs types de ressources.

En général, le système de jeu se développe également au fil du jeu, en augmentant le nombre d’éléments de l’interface ou d’actions possibles.

Voici quelques exemples que je trouve sympathiques :

Si vous lisez ceci, c’est que vous avez réussi à vous extirper de ces jeux, bravo ! Moi ça me prend beaucoup trop de temps malheureusement.

Les clickers

Les mécaniques d’un incremental ne sont pas toujours intéressantes. Celles de Swarm Simulator sont très répétitives par exemple, la seule évolution consiste à changer d’unité : passer de 112 à 113 par exemple. En contrepartie, ces jeux prennent peu de temps et continuent généralement d’évoluer hors ligne, quand on ne s’en occupe pas.

Mais il y a une catégorie d'incremental games pire que les autres : les clickers. Dans un clicker, la mécanique principale consiste à cliquer sur un bouton pour gagner des ressources ou faire évoluer un simple nombre. Or il ne s’agît généralement pas d’un choix intéressant comme choisir une nouvelle technologie à développer, ou bien installer plutôt un générateur d’oxygène supplémentaire ou réparer le filtre à eau avec les maigres ressources disponible dans notre station spatiale en ruine. Non, on clique pour ajouter 1 à notre ressource.

De plus, ces jeux sont généralement lents, demandant de cliquer de très, très nombreuses fois au même endroit. Un genre de musculation de l’index quoi. Pauvres de vous si vous y jouez avec un trackpad !

Pour ces jeux, aucune pitié, l’utilisation d’un autoclicker est o-bli-ga-toire afin de profiter des maigres évolutions de gameplay et du scénario (s’il existe).

Autoclicker

Pour clicker à l’infini sur le même bouton, on va donc avoir besoin d’une fonction javascript qui effectue le clic sur ce bouton, et d’une boucle infinie qui répète cette fonction.

Simuler un clic

Commençons par le clic. Il n’est pas toujours facile d’exécuter un évènement javascript sur un élément du DOM, mais voici une méthode qui fonctionne dans de nombreux jeux. Tout d’abord, il faut pouvoir sélectionner l’élément, par exemple via document.getElementById. Ensuite, on peut directement appeler la fonction click ou onclick de cet élément. Avec un peu de chances, l’une des deux fonctionnera.

Voici un simple bouton sur lequel exécuter les tests.

La commande suivante permet d’exécuter un clic depuis la console javascript :

Appel direct

document.getElementById('simple-click').click()

Créer un objet Event

Quand ni click ni onclick n’est disponible, il est possible de créer directement un objet évènement et de le lancer sur le bouton :

var evt = new Event('click', {
  bubbles: true,
  cancelable: true
})
document.getElementById('simple-click').dispatchEvent(evt)

Appeler directement le handler

Enfin, il arrive également que certains jeux appellent une fonction directement dans le code HTML :

<button onclick="addResource()">Click !</button>

Dans ce cas, il est possible d’appeler directement la fonction addResource plutôt que d’utiliser le DOM.

Boucle synchrone

On sait maintenant simuler le clic. Reste à le faire dans une boucle.

On peut se contenter d’une boucle for. La fonction looper permet de créer une boucle répétant n fois notre fonction de clic :

function looper(callback) {
  return function loop(n, i) {
    for (i = 0; i < n; i++) {
      callback(i)
    }
  }
}

Et voici comment on s’en sert :

var loop = looper(function(n){
  document.getElementById('simple-click').click()
})

loop(10) // on lance la boucle 10 fois

Malheureusement, cette version synchrone pose une problème majeur : durant l’exécution, le navigateur est « freezé », et l’exécution du script fait tourner le processeur de votre PC (ou l’un de ses coeurs) à 100%. Le jeu ne répondra pas à la souris ou au clavier et votre navigateur ne permettra pas de recharger ou fermer l’onglet avant la fin de l’exécution (ou avant la fin du temps maximum autorisé – qui est plutôt long).

Impossible donc de lancer une boucle 10 000 fois tout en continuant de jouer, d’autant plus si le jeu exécute lui-même de nombreuses opérations lors d’un unique clic. Et c’est le but, on ne fait pas tout ça pour des clics qui ne font rien !

Boucle asynchrone

Voici une version asynchrone qui relègue chaque itération de la boucle à l’itération suivante de l'event loop du moteur Javascript. Le navigateur se comportera normalement et la boucle agira comme une sorte de tâche de fond.

Le temps entre chaque itération sera beaucoup plus long, et ne pourra de toutes façons pas être inférieur à 4 millisecondes.

Ce n’est généralement pas un problème, et en contrepartie on peut lancer la boucle à l’infini (et au delà) ! Mais si le temps d’exécution est vraiment important, la librairie setImmediate peut remplacer setTimeout pour accélérer les choses.

Vous pouvez essayer cette boucle infinie dans la console sans crainte. Pour l’arrêter il suffit de recharger la page.

looper.async = function(callback, timeout) {
  timeout = timeout || 1
  return function loop(n, i) {
    i = i || 0
    if (i < n){
      setTimeout(function(){
        callback(i)
        loop(n, i + 1)
      }, timeout)
    }
  }
}

var loop = looper.async(function(n){
  document.getElementById('simple-click').click()
})

// N'ayons pas peur et lançons la boucle
// au delà de l'infini :)
loop(Infinity + 1)

Pourquoi pas setInterval

setInterval permet de spécifier un temps entre deux itérations de la boucle. Notre fonction looper.async permet de spécifier un temps entre la fin d’une boucle et le début de la suivante. Cela nous offre plus de contrôle : en laissant 1 par défaut, on exécute chaque boucle dès que la suivante est terminée. Avec setInterval, on perd du temps entre deux boucles si celles-ci s’exécutent plus rapidement que l’intervalle donnée. Mais si cela vous convient, après tout la méthode n’est pas mauvaise en soi !

Conclusion

Voilà, vous savez cliquer en boucle depuis la console. Je vous sauve donc la vie en vous permettant de finir ces jeux beaucoup plus rapidement que prévu, et de passer à autre chose de plus intéressant !