3 points par GN⁺ 2024-05-21 | 1 commentaires | Partager sur WhatsApp

City In A Bottle – un système de raycasting de 256 octets

  • Introduction

    • Aujourd’hui, présentation d’un petit moteur de raycasting et d’un générateur de ville contenus dans un fichier HTML de 256 octets.
    • Ce programme rassemble plusieurs concepts dans un espace minuscule, qu’on peut comprendre comme en résolvant une énigme.
    • Les principaux composants sont le code HTML, la boucle de mise à jour des frames, le système de rendu, le moteur de raycasting et la ville elle-même.
  • Code complet

    • Ce code n’est pas un simple snippet JavaScript, mais un programme HTML complet.
    • <canvas style=width:99% id=c onclick=setInterval('for(c.width=w=99,++t,i=6e3;i--;c.getContext`2d`.fillRect(i%w,i/w|0,1-d*Z/w+s,1))for(a=i%w/50-1,s=b=1-i/4e3,X=t,Y=Z=d=1;++Z<w&(Y<6-(32<Z&27<X%w&&X/9^Z/8)*8%46||d|(s=(X&Y&Z)%3/Z,a=b=1,d=Z/w));Y-=b)X+=a',t=9)>
      

Code HTML

  • Code HTML
    • La partie HTML se compose d’un simple élément canvas et d’un événement onclick.
    • <canvas style=width:99% id=c onclick=setInterval('',t=9)>
      
    • L’identifiant du canvas est défini sur c, ce qui permet d’y accéder depuis JavaScript.
    • L’événement onclick lance le programme et crée la boucle de mise à jour via un appel à setInterval.

Code JavaScript

  • Code JavaScript

    • Le code JavaScript de 199 octets s’exécute lorsque l’on clique sur le canvas.
    • for(c.width=w=99,++t,i=6e3;i--;c.getContext`2d`.fillRect(i%w,i/w|0,1-d*Z/w+s,1))for(a=i%w/50-1,s=b=1-i/4e3,X=t,Y=Z=d=1;++Z<w&(Y<6-(32<Z&27<X%w&&X/9^Z/8)*8%46||d|(s=(X&Y&Z)%3/Z,a=b=1,d=Z/w));Y-=b)X+=a
      
  • Analyse du code

    • Voici le code décomposé pour le rendre plus lisible.
    • c.width = w = 99
      ++t
      for (i = 6e3; i--;){
        a = i%w/50 - 1
        s = b = 1 - i/4e3
        X = t
        Y = Z = d = 1
        for(; ++Z<w &  (Y < 6 - (32<Z & 27<X%w && X/9^Z/8)*8%46 ||  d | (s = (X&Y&Z)%3/Z, a = b = 1, d = Z/w));) {
          X += a
          Y -= b
        }
        c.getContext`2d`.fillRect(i%w, i/w|0, 1 - d*Z/w + s, 1)
      }
      
  • Explication du code étape par étape

    • c.width = w = 99 : initialise le canvas et définit sa largeur à 99 pixels.
    • ++t : incrémente la variable de temps pour créer l’animation.
    • for (i = 6e3; i--;){} : la boucle détermine la luminosité de chaque pixel.
    • a = i % w / 50 - 1 : calcule la composante horizontale du vecteur caméra.
    • b = s = 1 - i / 4e3 : calcule la composante verticale du vecteur caméra.
    • X = t : utilise la valeur du temps comme position de départ en X.
    • Y = Z = d = 1 : initialise les valeurs Y, Z et d.
    • for(; ++Z<w & ...;) : le système de raycasting boucle jusqu’à détecter une collision.
    • c.getContext2d.fillRect(i%w, i/w|0, 1 - d*Z/w + s, 1) : dessine chaque pixel pour produire l’image finale.

Pour aller plus loin

  • Pour aller plus loin
    • Cette démo a été présentée à la demoparty Revision 2022, et peut être consultée sur Pouet.
    • Une version étendue en shader de 256 octets est disponible sur Shadertoy.
    • Un outil interactif créé par Daniel Darabos permet de manipuler en temps réel différents aspects du programme.

L’avis de GN⁺

  • Points intéressants

    • Ce programme montre comment produire des graphismes complexes avec un code extrêmement compact.
    • Il n’utilise que des bases mathématiques faciles à comprendre, même pour un·e ingénieur·e logiciel débutant·e.
    • C’est un bon exemple d’optimisation du code et de minimalisme, utile dans des compétitions comme le code golf.
  • Regard critique

    • Le code est très compressé, ce qui peut nuire à sa lisibilité.
    • Il convient davantage à des objectifs artistiques et expérimentaux qu’à des applications pratiques.
  • Technologies liées

    • Pour des projets similaires, on peut consulter divers exemples de shaders sur Shadertoy.
    • Il est aussi possible d’explorer d’autres exemples de code minimaliste sur des plateformes comme Dwitter.
  • Points à considérer pour l’adoption

    • Avant d’adopter cette approche, il faut prendre en compte la lisibilité et la maintenabilité du code.
    • Il faut aussi être conscient des difficultés d’optimisation des performances et de débogage lorsqu’on implémente des fonctionnalités complexes avec très peu de code.

1 commentaires

 
GN⁺ 2024-05-21
Avis sur Hacker News

Résumé des commentaires de Hacker News

  • 1K Pinball Game in JavaScript :

    • « C’est impressionnant de voir autant d’informations tenir dans si peu de code. »
    • « C’est vraiment génial, mais pendant que je lisais l’article, la boucle continuait à tourner et mon ordinateur portable a surchauffé. »
    • « Ressources liées : la façon dont le monde de Pitfall sur [Atari 2600] a été construit, la génération procédurale, l’évaluation paresseuse, etc. »
  • Génération procédurale et évaluation paresseuse :

    • « Plusieurs liens vers des ressources sur la génération procédurale sont fournis. »
    • « Observation sur la ressemblance entre l’évaluation paresseuse et les algorithmes de ray tracing. »
  • Autres avis :

    • « Vraiment génial ! Beau travail. »
    • « Le travail comme l’article sont impressionnants. »
    • « Remnants by Alcatraz, similaire aux démos MS-DOS de 256 octets — avec un lien YouTube. »
    • « Le fait que ce soit écrit en JavaScript est encore plus impressionnant. »
    • « Vraiment impressionnant. »
    • « C’est un vrai plaisir à lire. »
    • « Si vous aimez ça, vous aimerez aussi #tweetcart sur Twitter : des programmes de la taille d’un tweet pour la console virtuelle Pico-8. »