EduCode
EduCode
← Retour au site
Blog

Articles & Actualités

Les publications d'EduCode : nouveautés du logiciel, astuces de pseudo-code, retours d'expérience et actualités de l'environnement pédagogique.

19 publications

Cette mise à jour apporte des améliorations majeures au moteur et à l’environnement de développement
Actualité

Version 3.2 : en cours de finalisation !

Cette mise à jour apporte des améliorations majeures au moteur et à l’environnement de développement

Lire l'articleReplier l'article

Performances

Optimisation profonde de l’interpréteur : jusqu’à 30 % de gain sur les tâches intensives (animations, 3D, simulations, boucles lourdes).

Nouveau mot-clé : cliquer

Attendez un clic utilisateur sur une toile et récupérez directement les coordonnées :

tant que choix = 0
    affiche maToile
    cliquer maToile dans x, y

    si clique(x, y, 40, 80, 100, 45) alors
        choix vaut 1
    fin si
    si clique(x, y, 210, 102, 28) alors
        choix vaut 2
    fin si
fin tant que

Affectation directe dans les propriétés d’objet

Fini les variables temporaires :

classe joueur:
    nom est un texte
    score est un nombre
fin classe
demande "Ton nom ? " dans joueur.nom

Nouvelles fonctions intégrées

  • liste_fichiers : remplit un tableau avec les chemins complets des fichiers.
  • clique : vérifie si un clic se situe dans une zone définie de la toile.
maToile est une toile
x, y est un nombre
rectangle(maToile, 40, 80, 100, 45, #1976d2)
cliquer maToile dans  x, y

si clique(x, y, 40, 80, 100, 45) alors

Interface améliorée

  • Correction du positionnement du menu d’auto-complétion.
  • Nouveau panneau Structure du programme : vue hiérarchique, filtre, mise à jour en direct.

Nouveauté : Favoris

Ajoutez vos programmes à vos favoris, retrouvez vos projets en cours en un instant, et organisez votre liste selon vos besoins.

La version 3.2 arrive très bientôt. Préparez-vous à un vrai confort de développement.

EduCode 3.2 - Structure du programme
Nouveauté

EduCode 3.2 : Structure du programme

EduCode 3.2 - Le panneau : Structure du programme

Lire l'articleReplier l'article

Avec la version 3.2, le panneau Structure du programme évolue en profondeur pour devenir un véritable plan de navigation de votre code, digne des grands éditeurs tout en restant simple et lisible.

Une vue hiérarchique, enfin

Fini la liste plate où toutes les variables se mélangeaient. Les variables locales apparaissent désormais indentées sous leur fonction ou procédure, tandis que les variables globales restent au premier niveau. D'un coup d'œil, vous voyez qui appartient à quoi.

Toujours à jour, automatiquement

Le panneau se rafraîchit en direct pendant que vous tapez. Plus de numéros de ligne obsolètes ni d'éléments fantômes : la structure reflète votre code en permanence, sans avoir à fermer et rouvrir le panneau.

Il suit votre curseur

Déplacez-vous dans l'éditeur : l'élément correspondant se surligne automatiquement dans la structure, et le panneau défile pour le garder visible. Vous savez toujours où vous êtes, même dans un long programme.

Recherchez, trouvez, filtrez

Un nouveau champ de filtre en haut du panneau vous permet de retrouver instantanément une fonction, une procédure ou une variable par son nom — ou même par un nom de paramètre.

Les constantes rejoignent la structure

Les constantes sont désormais détectées, quelle que soit la syntaxe utilisée

Ces améliorations seront disponibles pour tout le monde dans EduCode v3.2.
Ouvrez la structure de votre programme, tapez quelques lignes… et regardez-la vivre. Bonne programmation !

Un projet inspiré du jeu Isotiles – Isometric Puzzle Game
Article

ISOTILES - Isometric Puzzle Game

ISOTILES : Quand l’algorithmique façonne un puzzle isométrique intelligent

Lire l'articleReplier l'article

Un projet inspiré du jeu Isotiles – Isometric Puzzle Game (Steam), revisité pour l’apprentissage et l’expérimentation.

ISOTILES – est un moteur de génération de puzzles isométriques conçu pour explorer la logique, l’algorithmique et le game design. Le concept s’appuie sur une idée simple : chaque tuile représente un nombre de passages possibles, et le joueur doit consommer ces passages avant d’atteindre la tuile d’arrivée.

Un système de tuiles basé sur la logique des passages

Chaque couleur correspond à une contrainte précise :

  • Bleu : 1 passage
  • Violet : 2 passages
  • Gris : pont neutre
  • Rouge : départ
  • Jaune : arrivée

L’objectif est de parcourir la carte en optimisant ses déplacements, tout en évitant les situations de blocage. Une fois tous les passages consommés, la tuile d’arrivée devient accessible.

Un générateur de cartes 100 % solvables

Le cœur du projet repose sur un algorithme qui :

  • construit un chemin aléatoire contrôlé,
  • évite les retours inutiles,
  • vérifie que la case d’arrivée n’est visitée qu’une seule fois,
  • calcule le nombre réel de passages par tuile,
  • attribue automatiquement les couleurs,
  • centre la carte dans l’espace isométrique,
  • garantit que chaque puzzle est solvable, sans être trivial.

Ce système permet de produire des cartes uniques, cohérentes et adaptées à un apprentissage progressif.

Un rendu isométrique généré entièrement par code

Le moteur graphique :

  • calcule les coordonnées isométriques,
  • dessine les faces des tuiles (haut, gauche, droite),
  • applique les couleurs et ombrages,
  • affiche un personnage stylisé,
  • met à jour l’affichage en temps réel selon les déplacements.

Le résultat est un environnement visuel propre, lisible et entièrement généré par le programme.

Un outil pédagogique pour comprendre l’algorithmique

ISOTILES – constitue un excellent support pour :

  • enseigner les structures de données,
  • comprendre la génération procédurale,
  • manipuler les coordonnées isométriques,
  • analyser les états de jeu (victoire, blocage),
  • expérimenter la logique de parcours et de contraintes.

Ce projet combine mathématiques, logique, créativité et programmation, et peut servir de base à des ateliers, des cours ou des projets personnels.

Programme :

@ Initialisation du moteur et des variables
graph est une toile
dimension(graph, 600, 500)

jX est un nombre
jY est un nombre
echelle est un nombre
echelle vaut 1.3
action est un nombre

map est un dictionnaire
nbBleu est un nombre
etatJeu est un nombre // 0 = En cours, 1 = Gagné, 2 = Bloqué

minX est un nombre
maxX est un nombre
minY est un nombre
maxY est un nombre
centreMapX est un nombre
centreMapY est un nombre

@ Générateur de cartes complexes et 100% solvables
procédure genererMap()
    map vaut [:]
    nbBleu vaut 0
    etatJeu vaut 0

    longueurChemin est un nombre
    longueurChemin vaut 24

    reussi est un booléen
    reussi vaut faux
    tentatives est un nombre
    tentatives vaut 0

    tant que non reussi et tentatives < 200
        tentatives ajoute 1
        map vaut [:]

        cheminX est un tableau
        cheminY est un tableau
        cheminX ajoute 0
        cheminY ajoute 0

        currX est un nombre
        currY est un nombre
        currX vaut 0
        currY vaut 0

        pasStep est un nombre
        pour pasStep de 1 à longueurChemin
            voisinsX est un tableau
            voisinsY est un tableau

            // Nord (interdit de revenir au départ 0,0)
            si currY - 1 <> 0 ou currX <> 0 alors
                voisinsX ajoute currX
                voisinsY ajoute currY - 1
            fin si
            // Sud
            si currY + 1 <> 0 ou currX <> 0 alors
                voisinsX ajoute currX
                voisinsY ajoute currY + 1
            fin si
            // Ouest
            si currY <> 0 ou currX - 1 <> 0 alors
                voisinsX ajoute currX - 1
                voisinsY ajoute currY
            fin si
            // Est
            si currY <> 0 ou currX + 1 <> 0 alors
                voisinsX ajoute currX + 1
                voisinsY ajoute currY
            fin si

            choixIdx est un nombre
            choixIdx vaut hasard(0, longueur(voisinsX) - 1)

            currX vaut voisinsX[choixIdx]
            currY vaut voisinsY[choixIdx]

            cheminX ajoute currX
            cheminY ajoute currY
        fin pour

        endX est un nombre
        endY est un nombre
        endX vaut currX
        endY vaut currY

        // Vérification que la case d'arrivée n'est visitée qu'à la fin
        nbFinVisites est un nombre
        nbFinVisites vaut 0
        idxStep est un nombre
        pour idxStep de 0 à longueurChemin
            si cheminX[idxStep] = endX et cheminY[idxStep] = endY alors
                nbFinVisites ajoute 1
            fin si
        fin pour

        si (endX <> 0 ou endY <> 0) et nbFinVisites = 1 alors
            reussi vaut vrai

            visites est un dictionnaire
            pour idxStep de 1 à longueurChemin - 1
                kVis est un texte
                kVis vaut convertir_texte(cheminX[idxStep]) + "_" + convertir_texte(cheminY[idxStep])
                si contient(visites, kVis) alors
                    vCount est un nombre
                    vCount vaut visites[kVis]
                    visites[kVis] vaut vCount + 1
                sinon
                    visites[kVis] vaut 1
                fin si
            fin pour

            tabKeysVisites est un tableau
            tabKeysVisites vaut cles(visites)

            iVis est un nombre
            pour iVis de 0 à longueur(tabKeysVisites) - 1
                kVis vaut tabKeysVisites[iVis]
                numPassages est un nombre
                numPassages vaut visites[kVis]

                si numPassages = 1 alors
                    map[kVis] vaut 1 // Bleue (1 passage)
                sinon si numPassages = 2 alors
                    map[kVis] vaut 5 // Violette (2 passages)
                sinon
                    map[kVis] vaut 3 // Grise (Pont / Neutre)
                fin si
            fin pour

            // Arrivée (Jaune = 4)
            cleFin est un texte
            cleFin vaut convertir_texte(endX) + "_" + convertir_texte(endY)
            map[cleFin] vaut 4
        fin si
    fin tant que

    // Départ (Rouge = 2)
    map["0_0"] vaut 2
    jX vaut 0
    jY vaut 0

    // Calcul du nombre de passages et centrage
    tabCles est un tableau
    tabCles vaut cles(map)
    nbBleu vaut 0

    i est un nombre
    pour i de 0 à longueur(tabCles) - 1
        kTmp est un texte
        kTmp vaut tabCles[i]
        tVal est un nombre
        tVal vaut map[kTmp]

        si tVal = 1 alors
            nbBleu ajoute 1
        sinon si tVal = 5 alors
            nbBleu ajoute 2
        fin si

        coords est un tableau
        coords vaut decouper(kTmp, "_")
        cxVal est un nombre
        cyVal est un nombre
        cxVal vaut convertir_nombre(coords[0])
        cyVal vaut convertir_nombre(coords[1])

        si i = 0 alors
            minX vaut cxVal
            maxX vaut cxVal
            minY vaut cyVal
            maxY vaut cyVal
        sinon
            minX vaut minimum(minX, cxVal)
            maxX vaut maximum(maxX, cxVal)
            minY vaut minimum(minY, cyVal)
            maxY vaut maximum(maxY, cyVal)
        fin si
    fin pour

    centreMapX vaut (minX + maxX) / 2
    centreMapY vaut (minY + maxY) / 2
fin procédure

// Génération initiale
appelle genererMap()

@ Boucle principale
tant que vrai
    effacer(graph)
    remplir(graph, #0f172a)

    dx est un nombre
    dy est un nombre
    dx vaut 24 * echelle
    dy vaut 12 * echelle

    sMin est un nombre
    sMax est un nombre
    sMin vaut (minX - 1) + (minY - 1)
    sMax vaut (maxX + 1) + (maxY + 1)

    sSum est un nombre
    gx est un nombre
    pour sSum de sMin à sMax
        pour gx de minX - 1 à maxX + 1
            gy est un nombre
            gy vaut sSum - gx

            si gy >= minY - 1 et gy <= maxY + 1 alors
                txtCleCoord est un texte
                txtCleCoord vaut convertir_texte(gx) + "_" + convertir_texte(gy)

                si contient(map, txtCleCoord) alors
                    typeTuile est un nombre
                    typeTuile vaut map[txtCleCoord]

                    relX est un nombre
                    relY est un nombre
                    relX vaut gx - centreMapX
                    relY vaut gy - centreMapY

                    cx est un nombre
                    cy est un nombre
                    cx vaut 300 + (relX - relY) * dx
                    cy vaut 250 + (relX + relY) * dy

                    hauteurBase est un nombre
                    hauteurBase vaut 10 * echelle

                    cTop est un texte
                    cGau est un texte
                    cDro est un texte

                    si typeTuile = 1 alors
                        cTop vaut #38bdf8 // Bleu (1 passage)
                        cGau vaut #0284c7
                        cDro vaut #0369a1
                    sinon si typeTuile = 2 alors
                        cTop vaut #f87171 // Rouge (Consommé)
                        cGau vaut #dc2626
                        cDro vaut #991b1b
                    sinon si typeTuile = 3 alors
                        cTop vaut #94a3b8 // Gris (Pont / Neutre)
                        cGau vaut #64748b
                        cDro vaut #475569
                    sinon si typeTuile = 4 alors
                        cTop vaut #facc15 // Jaune (Arrivée)
                        cGau vaut #ca8a04
                        cDro vaut #854d0e
                    sinon si typeTuile = 5 alors
                        cTop vaut #c084fc // Violet (2 passages)
                        cGau vaut #9333ea
                        cDro vaut #6b21a8
                    fin si

                    lCY est un nombre
                    lCY vaut cy - hauteurBase

                    ptsFG est un tableau
                    ptsFG ajoute cx - dx
                    ptsFG ajoute lCY
                    ptsFG ajoute cx
                    ptsFG ajoute lCY + dy
                    ptsFG ajoute cx
                    ptsFG ajoute lCY + dy + hauteurBase
                    ptsFG ajoute cx - dx
                    ptsFG ajoute lCY + hauteurBase
                    polygone(graph, ptsFG, cGau)

                    ptsFD est un tableau
                    ptsFD ajoute cx
                    ptsFD ajoute lCY + dy
                    ptsFD ajoute cx + dx
                    ptsFD ajoute lCY
                    ptsFD ajoute cx + dx
                    ptsFD ajoute lCY + hauteurBase
                    ptsFD ajoute cx
                    ptsFD ajoute lCY + dy + hauteurBase
                    polygone(graph, ptsFD, cDro)

                    ptsTop est un tableau
                    ptsTop ajoute cx
                    ptsTop ajoute lCY - dy
                    ptsTop ajoute cx + dx
                    ptsTop ajoute lCY
                    ptsTop ajoute cx
                    ptsTop ajoute lCY + dy
                    ptsTop ajoute cx - dx
                    ptsTop ajoute lCY
                    polygone(graph, ptsTop, cTop)

                    contour(graph, rgba(255, 255, 255, 0.15), 1)

                    // Joueur
                    si gx = jX et gy = jY alors
                        pCY est un nombre
                        pCY vaut lCY - (2 * echelle)

                        pDx est un nombre
                        pDy est un nombre
                        pDz est un nombre
                        pDx vaut 8 * echelle
                        pDy vaut 4 * echelle
                        pDz vaut 14 * echelle

                        ellipse(graph, cx, pCY + pDy, 14 * echelle, 7 * echelle, rgba(0, 0, 0, 0.4))

                        pJG est un tableau
                        pJG ajoute cx - pDx
                        pJG ajoute pCY - pDz
                        pJG ajoute cx
                        pJG ajoute pCY - pDz + pDy
                        pJG ajoute cx
                        pJG ajoute pCY + pDy
                        pJG ajoute cx - pDx
                        pJG ajoute pCY
                        polygone(graph, pJG, #cbd5e1)

                        pJD est un tableau
                        pJD ajoute cx
                        pJD ajoute pCY - pDz + pDy
                        pJD ajoute cx + pDx
                        pJD ajoute pCY - pDz
                        pJD ajoute cx + pDx
                        pJD ajoute pCY
                        pJD ajoute cx
                        pJD ajoute pCY + pDy
                        polygone(graph, pJD, #94a3b8)

                        pJT est un tableau
                        pJT ajoute cx
                        pJT ajoute pCY - pDz - pDy
                        pJT ajoute cx + pDx
                        pJT ajoute pCY - pDz
                        pJT ajoute cx
                        pJT ajoute pCY - pDz + pDy
                        pJT ajoute cx - pDx
                        pJT ajoute pCY - pDz
                        polygone(graph, pJT, #ffffff)

                        contour(graph, #0)

                        polygone(graph, cx + (1 * echelle), pCY - pDz + (2 * echelle), cx + (6 * echelle), pCY - pDz - (0.5 * echelle), cx + (6 * echelle), pCY - (3 * echelle), cx + (1 * echelle), pCY - (0.5 * echelle), #38bdf8)
                    fin si
                fin si
            fin si
        fin pour
    fin pour

    // Interface utilisateur
    rectangle(graph, 0, 0, 600, 65, rgba(15, 23, 42, 0.9))
    label(graph, 12, 18, "ISOTILES - PUZZLE EDUCODE v3.1", #ffffff, 13)

    si etatJeu = 1 alors
        label(graph, 12, 36, "VICTOIRE ! Appuie sur [R] pour la carte suivante.", #4ade80, 12)
    sinon si etatJeu = 2 alors
        label(graph, 12, 36, "BLOQUÉ ! Plus de coup possible. Appuie sur [R].", #f87171, 12)
    sinon
        txtInfos est un texte
        txtInfos vaut "Passages restants : " + convertir_texte(nbBleu)
        label(graph, 12, 36, txtInfos, #38bdf8, 12)
    fin si

    label(graph, 12, 52, "Bleu = 1 pass. | Violet = 2 pass. | Gris = Pont", #94a3b8, 12)

    affiche graph

    appuyer ["z", "s", "q", "d", "r"] dans action

    mvtX est un nombre
    mvtY est un nombre
    mvtX vaut 0
    mvtY vaut 0

    si action >= 1 et action <= 4 et etatJeu = 0 alors
        si action = 1 alors
            mvtY vaut - 1
        sinon si action = 2 alors
            mvtY vaut 1
        sinon si action = 3 alors
            mvtX vaut - 1
        sinon si action = 4 alors
            mvtX vaut 1
        fin si

        cibX est un nombre
        cibY est un nombre
        cibX vaut jX + mvtX
        cibY vaut jY + mvtY

        txtCleCib est un texte
        txtCleCib vaut convertir_texte(cibX) + "_" + convertir_texte(cibY)

        si contient(map, txtCleCib) alors
            typeCib est un nombre
            typeCib vaut map[txtCleCib]

            si typeCib = 1 ou typeCib = 3 ou typeCib = 4 ou typeCib = 5 alors
                jX vaut cibX
                jY vaut cibY

                si typeCib = 1 alors
                    map[txtCleCib] vaut 2
                    nbBleu soustrait 1
                sinon si typeCib = 5 alors
                    map[txtCleCib] vaut 1
                    nbBleu soustrait 1
                fin si

                si typeCib = 4 et nbBleu = 0 alors
                    etatJeu vaut 1
                fin si

                // Test de blocage
                si etatJeu = 0 alors
                    txtNord est un texte
                    txtNord vaut convertir_texte(jX) + "_" + convertir_texte(jY - 1)
                    txtSud est un texte
                    txtSud vaut convertir_texte(jX) + "_" + convertir_texte(jY + 1)
                    txtOuest est un texte
                    txtOuest vaut convertir_texte(jX - 1) + "_" + convertir_texte(jY)
                    txtEst est un texte
                    txtEst vaut convertir_texte(jX + 1) + "_" + convertir_texte(jY)

                    vN est un booléen
                    vN vaut faux
                    si contient(map, txtNord) alors
                        typeN est un nombre
                        typeN vaut map[txtNord]
                        si typeN = 1 ou typeN = 3 ou typeN = 5 ou (typeN = 4 et nbBleu = 0) alors
                            vN vaut vrai
                        fin si
                    fin si

                    vS est un booléen
                    vS vaut faux
                    si contient(map, txtSud) alors
                        typeS est un nombre
                        typeS vaut map[txtSud]
                        si typeS = 1 ou typeS = 3 ou typeS = 5 ou (typeS = 4 et nbBleu = 0) alors
                            vS vaut vrai
                        fin si
                    fin si

                    vO est un booléen
                    vO vaut faux
                    si contient(map, txtOuest) alors
                        typeO est un nombre
                        typeO vaut map[txtOuest]
                        si typeO = 1 ou typeO = 3 ou typeO = 5 ou (typeO = 4 et nbBleu = 0) alors
                            vO vaut vrai
                        fin si
                    fin si

                    vE est un booléen
                    vE vaut faux
                    si contient(map, txtEst) alors
                        typeE est un nombre
                        typeE vaut map[txtEst]
                        si typeE = 1 ou typeE = 3 ou typeE = 5 ou (typeE = 4 et nbBleu = 0) alors
                            vE vaut vrai
                        fin si
                    fin si

                    si non vN et non vS et non vO et non vE alors
                        etatJeu vaut 2
                    fin si
                fin si
            fin si
        fin si
    fin si

    si action = 5 alors
        appelle genererMap()
    fin si

fin tant que
Choisissez la puissance adaptée à vos projets éducatifs, animations et exercices de logique.
Actualité

Matériel recommandé pour une utilisation fluide d’EduCode

EduCode : Du simple projet aux animations avancées, quelle configuration choisir ?

Lire l'articleReplier l'article

Configuration minimale

Pour l’initiation, les projets simples et les petites animations.

  • CPU : Intel Core i3 / i5 (4–6 cœurs) ou AMD Ryzen 3 / 5
  • RAM : 8 Go

Configuration recommandée

Pour un usage fluide, des projets éducatifs intermédiaires et des animations plus complexes.

  • CPU : Intel Core i5 / i7 ou AMD Ryzen 5 / 7
  • RAM : 16 Go
Génération d’une surface 3D Peaks : fonctionnement détaillé du programme
Article

Génération d’une surface 3D Peaks

Génération d’une surface 3D Peaks : fonctionnement détaillé du programme

Lire l'articleReplier l'article

Ce programme construit et affiche une surface 3D statique de type peaks, rendue en projection isométrique, avec facettes pleines, tri de profondeur et trois grilles fixes formant un repère spatial. Voici une analyse complète de son fonctionnement.

Paramétrage de la scène

La toile est définie avec une largeur de 560 px et une hauteur de 520 px. Le centre visuel est légèrement abaissé pour compenser la hauteur du relief :

  • OX = LARG / 2
  • OY = HAUT / 2 + 40

L’angle de vue est une projection iso inclinée, définie par :

  • sinA = 0,34
  • cosA = 0,62

Deux échelles sont utilisées :

  • sXY = 62 pour les axes X et Y
  • sZ = 13 pour la hauteur

La résolution de la grille est fixée à N = 22, avec un domaine allant de xmin = -3 à xmax = 3.

Calcul du relief : la fonction « peaks »

Le programme pré-calcule les hauteurs z pour chaque point de la grille. Pour chaque couple (i, j), il calcule :

  • xx et yy : coordonnées normalisées

Trois composantes du relief :

  • La hauteur finale est : z = g1 + g2 + g3

Toutes les valeurs sont stockées dans un tableau linéaire.

Colormap « jet »

Une fonction dédiée convertit une hauteur normalisée en couleur RGB. Elle reproduit le célèbre colormap jet :

  • Bleu ? Vert ? Jaune ? Rouge selon la valeur de hn (0 à 1).

Cette palette renforce la lisibilité du relief.

Construction du repère 3D

Avant de dessiner la surface, le programme trace trois grilles fixes :

  • Plan XY (sol)
  • Plan XZ (mur arrière gauche)
  • Plan YZ (mur arrière droit)

Chaque grille est dessinée en lignes fines (#dddddd), ce qui crée un repère spatial clair et stable.

Projection 3D ? 2D avec rotation

La procédure dessinerVue(rot) applique une rotation horizontale :

  • cr = cos(rot)
  • sr = sin(rot)

Chaque point (x, y, z) est transformé en coordonnées tournées (xr, yr) puis projeté en 2D via l’angle iso :

  • pX = OX + (xr·sXY – yr·sXY)·cosA pY = OY – z·sZ – (xr·sXY + yr·sXY)·sinA

Cette projection donne l’effet 3D sans utiliser de moteur graphique.

Tri de profondeur : rendu correct des facettes

Pour éviter que les facettes s’affichent dans le mauvais ordre, le programme utilise un tri par bandes de profondeur :

Chaque facette reçoit une valeur de profondeur.
Le programme parcourt les bandes de la plus éloignée à la plus proche.
Il dessine uniquement les facettes appartenant à la bande courante.

Ce tri garantit un rendu propre, sans chevauchements incohérents.

Dessin des facettes

Chaque cellule de la grille est rendue comme un polygone à 4 sommets :

  • Les quatre hauteurs za, zb, zc, zd sont récupérées.
  • Les quatre coins sont projetés en 2D.
  • La couleur est déterminée par la hauteur moyenne.
  • Le polygone est dessiné avec un contour sombre (#0a0a0f).

Le résultat est une surface 3D colorée, continue et lisible.

Résultat final

La toile affiche :

  • Le repère 3D
  • La surface « peaks » entièrement colorée
  • Un titre discret : Surface 3D « peaks »

L’appel final : dessinerVue(0) produit une vue alignée, sans rotation.

Conclusion

Ce programme combine plusieurs techniques graphiques :

  • Calcul de relief paramétrique
  • Projection isométrique
  • Colormap dynamique
  • Tri de profondeur manuel
  • Rendu polygonal optimisé

Il démontre comment produire une surface 3D complète sans moteur 3D, uniquement via calculs géométriques et dessin 2D. Une base solide pour des visualisations scientifiques, des rendus mathématiques ou des démonstrations pédagogiques.

Programme :

// ============================================================
//   SURFACE 3D "peaks" — centrée, statique (sans rotation)
//   Facettes pleines, colormap jet, fond noir, tri de profondeur.
//   INCLUS : 3 Grilles fixes (XY, XZ, YZ) formant le repère.
// ============================================================

LARG est un nombre
LARG vaut 560
HAUT est un nombre
HAUT vaut 520

// ---- Centre de la toile (surface centrée) ----
OX est un nombre
OY est un nombre
OX vaut LARG / 2
OY vaut HAUT / 2 + 40 // légèrement bas pour compenser la hauteur du relief

// ---- Angle de vue iso (inclinaison verticale) ----
sinA est un nombre
cosA est un nombre
sinA vaut 0,34
cosA vaut 0,62

// ---- Échelles ----
sXY est un nombre
sZ est un nombre
sXY vaut 62
sZ vaut 13

// ---- Résolution ----
N est un nombre
N vaut 22

xmin est un nombre
xmax est un nombre
xmin vaut - 3
xmax vaut 3

// ---- Pré-calcul des hauteurs z : index(i,j) = j*(N+1) + i ----
hauteurs est un tableau
j est un nombre
pour j de 0 à N
    i est un nombre
    pour i de 0 à N
        xx est un nombre
        yy est un nombre
        xx vaut xmin + (xmax - xmin) * i / N
        yy vaut xmin + (xmax - xmin) * j / N
        g1 est un nombre
        g2 est un nombre
        g3 est un nombre
        g1 vaut 3 * (1 - xx) * (1 - xx) * puissance(2.71828, -(xx * xx) - (yy + 1) * (yy + 1))
        g2 vaut - 10 * (xx / 5 - puissance(xx, 3) - puissance(yy, 5)) * puissance(2.71828, -(xx * xx) - (yy * yy))
        g3 vaut - 1 / 3 * puissance(2.71828, -((xx + 1) * (xx + 1)) - (yy * yy))
        hauteurs ajoute g1 + g2 + g3
    fin pour
fin pour

// ---- Couleur "jet" selon hauteur normalisée hn (0..1) ----
fonction couleur_jet(hn)
    hnc est un nombre
    hnc vaut limiter(hn, 0, 1)
    rC est un nombre
    gC est un nombre
    bC est un nombre
    rC vaut arrondi(255 * limiter(1.5 - absolue(4 * hnc - 3), 0, 1))
    gC vaut arrondi(255 * limiter(1.5 - absolue(4 * hnc - 2), 0, 1))
    bC vaut arrondi(255 * limiter(1.5 - absolue(4 * hnc - 1), 0, 1))
    retourne rgb(rC, gC, bC)
fin fonction

// ============================================================
//  DESSINE L'IMAGE pour un angle de rotation "rot" (radians)
// ============================================================
procédure dessinerVue(rot)
    Fig est une toile
    dimension(Fig, LARG, HAUT)
    remplir(Fig, #ffffff)

    cr est un nombre
    sr est un nombre
    cr vaut cosinus(rot)
    sr vaut sinus(rot)

    // --- DESSIN DES 3 GRILLES FIXES (XY, XZ, YZ) ---
    zBase est un nombre
    zBase vaut - 6
    zMax est un nombre
    zMax vaut 8

    k est un nombre
    pour k de 0 à 10
        yL est un nombre
        yL vaut xmin + (xmax - xmin) * k / 10
        xL est un nombre
        xL vaut xmin + (xmax - xmin) * k / 10
        zL est un nombre
        zL vaut zBase + (zMax - zBase) * k / 10

        // 1. GRILLE SOL (Plan XY à Z = zBase)
        px1, py1, px2, py2 est un nombre
        px1 vaut OX + (xmin * sXY - yL * sXY) * cosA
        py1 vaut OY - zBase * sZ - (xmin * sXY + yL * sXY) * sinA
        px2 vaut OX + (xmax * sXY - yL * sXY) * cosA
        py2 vaut OY - zBase * sZ - (xmax * sXY + yL * sXY) * sinA
        ligne(Fig, px1, py1, px2, py2, #dddddd, 1)

        px3, py3, px4, py4 est un nombre
        px3 vaut OX + (xL * sXY - xmin * sXY) * cosA
        py3 vaut OY - zBase * sZ - (xL * sXY + xmin * sXY) * sinA
        px4 vaut OX + (xL * sXY - xmax * sXY) * cosA
        py4 vaut OY - zBase * sZ - (xL * sXY + xmax * sXY) * sinA
        ligne(Fig, px3, py3, px4, py4, #dddddd, 1)

        // 2. GRILLE MUR XZ (Arrière-gauche, à Y = xmax)
        px5, py5, px6, py6 est un nombre
        px5 vaut OX + (xL * sXY - xmax * sXY) * cosA
        py5 vaut OY - zBase * sZ - (xL * sXY + xmax * sXY) * sinA
        px6 vaut OX + (xL * sXY - xmax * sXY) * cosA
        py6 vaut OY - zMax * sZ - (xL * sXY + xmax * sXY) * sinA
        ligne(Fig, px5, py5, px6, py6, #dddddd, 1)

        px7, py7, px8, py8 est un nombre
        px7 vaut OX + (xmin * sXY - xmax * sXY) * cosA
        py7 vaut OY - zL * sZ - (xmin * sXY + xmax * sXY) * sinA
        px8 vaut OX + (xmax * sXY - xmax * sXY) * cosA
        py8 vaut OY - zL * sZ - (xmax * sXY + xmax * sXY) * sinA
        ligne(Fig, px7, py7, px8, py8, #dddddd, 1)

        // 3. GRILLE MUR YZ (Arrière-droit, à X = xmax)
        px9, py9, px10, py10 est un nombre
        px9 vaut OX + (xmax * sXY - yL * sXY) * cosA
        py9 vaut OY - zBase * sZ - (xmax * sXY + yL * sXY) * sinA
        px10 vaut OX + (xmax * sXY - yL * sXY) * cosA
        py10 vaut OY - zMax * sZ - (xmax * sXY + yL * sXY) * sinA
        ligne(Fig, px9, py9, px10, py10, #dddddd, 1)

        px11, py11, px12, py12 est un nombre
        px11 vaut OX + (xmax * sXY - xmin * sXY) * cosA
        py11 vaut OY - zL * sZ - (xmax * sXY + xmin * sXY) * sinA
        px12 vaut OX + (xmax * sXY - xmax * sXY) * cosA
        py12 vaut OY - zL * sZ - (xmax * sXY + xmax * sXY) * sinA
        ligne(Fig, px11, py11, px12, py12, #dddddd, 1)
    fin pour

    // --- Passe unique avec tri par profondeur (bandes) pour la surface ---
    bande est un nombre
    pour bande de 40 à 0 pas - 1
        jj est un nombre
        pour jj de 0 à N - 1
            ii est un nombre
            pour ii de 0 à N - 1
                // centre (monde) de la facette
                xc est un nombre
                yc est un nombre
                xc vaut xmin + (xmax - xmin) * (ii + 0.5) / N
                yc vaut xmin + (xmax - xmin) * (jj + 0.5) / N
                // coordonnées tournées pour la surface
                xrc est un nombre
                yrc est un nombre
                xrc vaut xc * cr - yc * sr
                yrc vaut xc * sr + yc * cr
                // profondeur -> bande entière (grand = au fond)
                prof est un nombre
                prof vaut arrondi((xrc + yrc + 6) * 40 / 12)
                si prof = bande alors
                    // Les 4 coins (monde), tournés puis projetés
                    za est un nombre
                    zb est un nombre
                    zc2 est un nombre
                    zd est un nombre
                    za vaut hauteurs[jj * (N + 1) + ii]
                    zb vaut hauteurs[jj * (N + 1) + ii + 1]
                    zc2 vaut hauteurs[(jj + 1) * (N + 1) + ii + 1]
                    zd vaut hauteurs[(jj + 1) * (N + 1) + ii]

                    xa est un nombre
                    ya est un nombre
                    xb est un nombre
                    yb est un nombre
                    xa vaut xmin + (xmax - xmin) * ii / N
                    ya vaut xmin + (xmax - xmin) * jj / N
                    xb vaut xmin + (xmax - xmin) * (ii + 1) / N
                    yb vaut xmin + (xmax - xmin) * (jj + 1) / N

                    // projette un coin (x,y,z) avec rotation
                    xr1 est un nombre
                    yr1 est un nombre
                    xr1 vaut xa * cr - ya * sr
                    yr1 vaut xa * sr + ya * cr
                    pax est un nombre
                    pay est un nombre
                    pax vaut OX + (xr1 * sXY - yr1 * sXY) * cosA
                    pay vaut OY - za * sZ - (xr1 * sXY + yr1 * sXY) * sinA

                    xr2 est un nombre
                    yr2 est un nombre
                    xr2 vaut xb * cr - ya * sr
                    yr2 vaut xb * sr + ya * cr
                    pbx est un nombre
                    pby est un nombre
                    pbx vaut OX + (xr2 * sXY - yr2 * sXY) * cosA
                    pby vaut OY - zb * sZ - (xr2 * sXY + yr2 * sXY) * sinA

                    xr3 est un nombre
                    yr3 est un nombre
                    xr3 vaut xb * cr - yb * sr
                    yr3 vaut xb * sr + yb * cr
                    pcx est un nombre
                    pcy est un nombre
                    pcx vaut OX + (xr3 * sXY - yr3 * sXY) * cosA
                    pcy vaut OY - zc2 * sZ - (xr3 * sXY + yr3 * sXY) * sinA

                    xr4 est un nombre
                    yr4 est un nombre
                    xr4 vaut xa * cr - yb * sr
                    yr4 vaut xa * sr + yb * cr
                    pdx est un nombre
                    pdy est un nombre
                    pdx vaut OX + (xr4 * sXY - yr4 * sXY) * cosA
                    pdy vaut OY - zd * sZ - (xr4 * sXY + yr4 * sXY) * sinA

                    // Couleur selon hauteur moyenne
                    zmoy est un nombre
                    zmoy vaut (za + zb + zc2 + zd) / 4
                    hn est un nombre
                    hn vaut (zmoy + 7) / 14
                    coul est un texte
                    coul vaut couleur_jet(hn)

                    contour(Fig, #0a0a0f, 1)
                    polygone(Fig, pax, pay, pbx, pby, pcx, pcy, pdx, pdy, coul)
                    contour(Fig, #0)
                fin si
            fin pour
        fin pour
    fin pour

    label(Fig, 20, 34, "Surface 3d « peaks »", #1F2937, 18)

    // Affichage direct de la toile finale
    affiche Fig
fin procédure

// ============================================================
//  APPEL : on dessine avec un angle de 0 (aligné)
// ============================================================
appelle dessinerVue(0)
Exploration 2D : une map générée avec obstacles, décor et trésor !
Article

Exploration 2D

Exploration 2D : une map générée avec obstacles, décor et trésor !

Lire l'articleReplier l'article

Un système de déplacement dans une grille 2D permet de traverser différents types de terrains, éviter les obstacles et atteindre un coffre bien caché.

Ce projet peut paraître simple au premier regard, mais la logique derrière lui ouvre la porte à beaucoup plus : génération procédurale, collisions, chemin garanti, décor varié… une vraie base pour la suite.

Décors générés aléatoirement :

La carte contient plusieurs types de cases :

  • Herbe (0) – zones accessibles
  • Mur (1) – obstacles en pierre
  • Forêt (2) – arbres infranchissables
  • Eau (3) – zones bloquantes
  • Trésor (4) – objectif final

Les bords sont des murs, et l’intérieur est rempli aléatoirement pour créer une vraie petite aventure.

Chemin garanti jusqu’au trésor :

Un creusement automatique assure qu’un passage existe toujours entre le joueur et le coffre.
Peu importe la génération, une route sûre mène à la victoire.

Déplacement du joueur :

Le personnage se déplace case par case avec :

  • Z : Haut
  • S : Bas
  • D : Droite
  • Q : Gauche

Les collisions empêchent de traverser murs, arbres ou eau.

Objectif :

  • Atteindre la case du trésor.
  • Quand le joueur arrive dessus : VICTOIRE !

Graphismes simples mais efficaces :

  • Herbe fleurie, forêt dense, eau animée, mur texturé, coffre doré… et un petit personnage rouge avec des yeux expressifs.

Un système parfait pour créer :

  • un jeu d’exploration
  • un labyrinthe dynamique

Programme :

@ Initialisation de la toile et des dimensions
maToile est une toile
dimension(maToile, 320, 320)

tailleTUILE, nbLignes, nbColonnes est un nombre
tailleTUILE vaut 32
nbLignes vaut 10
nbColonnes vaut 10

// Position du joueur et du trésor
joueurX, joueurY est un nombre
joueurX vaut 1
joueurY vaut 1

tresorX, tresorY est un nombre
tresorX vaut nbColonnes - 2
tresorY vaut nbLignes - 2

// Types de décors :
// 0 = Herbe (Passage)
// 1 = Mur (Obstacle)
// 2 = Forêt (Obstacle)
// 3 = Eau (Obstacle)
// 4 = Trésor (Objectif)

grilleJeu est un tableau
i, j, tyAlea, idxActuel est un nombre

@ 1. Génération aléatoire des décors
pour i de 0 à nbLignes - 1
    pour j de 0 à nbColonnes - 1
        // Murs extérieurs de la carte
        si i = 0 ou i = nbLignes - 1 ou j = 0 ou j = nbColonnes - 1 alors
            grilleJeu ajoute 1
        sinon
            // Obstacles aléatoires
            tyAlea vaut hasard(0, 9)
            si tyAlea = 0 ou tyAlea = 1 alors
                grilleJeu ajoute 2 // Forêt
            sinon si tyAlea = 2 alors
                grilleJeu ajoute 3 // Eau
            sinon si tyAlea = 3 alors
                grilleJeu ajoute 1 // Mur
            sinon
                grilleJeu ajoute 0 // Herbe
            fin si
        fin si
    fin pour
fin pour

@ 2. CREUSEMENT DU CHEMIN GARANTI (Path Carving)
curX, curY, idxPath, dirAlea est un nombre
curX vaut joueurX
curY vaut joueurY

// On avance pas à pas du départ vers le trésor en dégageant de l'herbe (0)
tant que curX <> tresorX ou curY <> tresorY
    idxPath vaut curY * nbColonnes + curX
    grilleJeu[idxPath] vaut 0

    // Choix aléatoire de la direction (droite ou bas) vers la cible
    si curX < tresorX et curY < tresorY alors
        dirAlea vaut hasard(0, 1)
        si dirAlea = 0 alors
            curX vaut curX + 1
        sinon
            curY vaut curY + 1
        fin si
    sinon si curX < tresorX alors
        curX vaut curX + 1
    sinon
        curY vaut curY + 1
    fin si
fin tant que

// Placement du trésor à la fin du chemin garanti
idxTresor est un nombre
idxTresor vaut tresorY * nbColonnes + tresorX
grilleJeu[idxTresor] vaut 4

@ 3. Boucle principale de jeu
jeuActif est un booléen
jeuActif vaut vrai

actionClavier, valCase, px, py, nxtX, nxtY, idxCible est un nombre

tant que jeuActif = vrai
    effacer(maToile)
    remplir(maToile, #1a202c)

    @ Affichage du décor
    pour i de 0 à nbLignes - 1
        pour j de 0 à nbColonnes - 1
            idxActuel vaut i * nbColonnes + j
            valCase vaut grilleJeu[idxActuel]
            px vaut j * tailleTUILE
            py vaut i * tailleTUILE

            // 0 : HERBE (Fleuries)
            si valCase = 0 alors
                rectangle(maToile, px, py, tailleTUILE, tailleTUILE, #38a169)
                cercle(maToile, px + 16, py + 16, 2, #f6e05e)

                // 1 : MUR DE PIERRE
            sinon si valCase = 1 alors
                rectangle(maToile, px, py, tailleTUILE, tailleTUILE, #4a5568)
                rectangle(maToile, px + 2, py + 2, tailleTUILE - 4, tailleTUILE - 4, #718096)

                // 2 : ARBRE / FORÊT
            sinon si valCase = 2 alors
                rectangle(maToile, px, py, tailleTUILE, tailleTUILE, #2f855a)
                cercle(maToile, px + 16, py + 16, 11, #276749)
                cercle(maToile, px + 16, py + 16, 7, #48bb78)

                // 3 : EAU
            sinon si valCase = 3 alors
                rectangle(maToile, px, py, tailleTUILE, tailleTUILE, #3182ce)
                rectangle(maToile, px + 4, py + 10, 12, 3, #63b3ed)
                rectangle(maToile, px + 16, py + 20, 12, 3, #63b3ed)

                // 4 : COFFRE AU TRÉSOR
            sinon si valCase = 4 alors
                rectangle(maToile, px, py, tailleTUILE, tailleTUILE, #d69e2e)
                rectangle(maToile, px + 6, py + 8, 20, 16, #744210)
                rectangle(maToile, px + 8, py + 12, 16, 8, #ecc94b)
            fin si
        fin pour
    fin pour

    @ Affichage du Joueur
    px vaut joueurX * tailleTUILE
    py vaut joueurY * tailleTUILE
    cercle(maToile, px + 16, py + 16, 12, #e53e3e)
    cercle(maToile, px + 12, py + 12, 3, #ffffff)
    cercle(maToile, px + 20, py + 12, 3, #ffffff)
    cercle(maToile, px + 12, py + 12, 1, #000000)
    cercle(maToile, px + 20, py + 12, 1, #000000)

    affiche maToile

    @ Entrées clavier
    appuyer ["z", "s", "d", "q", "x"] dans actionClavier

    nxtX vaut joueurX
    nxtY vaut joueurY

    // Mouvements : 1=Z, 2=S, 3=D, 4=Q, 5=X
    si actionClavier = 1 alors
        nxtY vaut joueurY - 1
    sinon si actionClavier = 2 alors
        nxtY vaut joueurY + 1
    sinon si actionClavier = 3 alors
        nxtX vaut joueurX + 1
    sinon si actionClavier = 4 alors
        nxtX vaut joueurX - 1
    sinon si actionClavier = 5 alors
        jeuActif vaut faux
    fin si

    @ Déplacement et Collisions
    idxCible vaut nxtY * nbColonnes + nxtX

    // Autoriser le passage uniquement sur l'herbe (0) ou le trésor (4)
    si grilleJeu[idxCible] = 0 ou grilleJeu[idxCible] = 4 alors
        joueurX vaut nxtX
        joueurY vaut nxtY
    fin si

    // Victoire
    si joueurX = tresorX et joueurY = tresorY alors
        affiche "VICTOIRE ! Vous avez trouvé le trésor !"
        jeuActif vaut faux
    fin si
fin tant que

affiche "Fin de la partie."