Blog

Page d’exemple

Projets

Subaru Impreza WRC

Dans le cadre du projet Art génératif qui consiste a générer une image en pythona l’aide du module turtle, j’ai réalisé ma voiture favorite, la Subaru Impreza dans un thème néon. Je vous explique dans cet article la rélisation de ce projet

La légendaire Subaru Impreza

L’Impreza est une compacte du constructeur automobile japonais Subaru, apparue en 1992. Icône de la marque grâce à ses succès en championnat du monde des rallyes (trois titres pilotes et trois titres constructeurs), elle en est à sa cinquième génération depuis 2016.Avec un moteur d’une cylindrée de 2 litres et 211 chevaux (94/97) et 217 (98/00) pour la version européenne de première génération sous l’appellation GT, les premières Impreza qui deviendront les WRX peuvent afficher des caractéristiques allant jusqu’à 320 chevaux dans leur version STI. Depuis 2015, La Subaru WRX est devenu un modèle indépendant de la Impreza et suit son propre développement. De ce fait, le nom Impreza disparait peu à peu des références sportives remplacé par la WRX et à moindre mesure par la Subaru BRZ.

Avant meme de realiser

Appel et verification des modules

from turtle import *
from random import randint


try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False
titre = "Bastien.S"
title(titre+" | Subaru Impreza WRC")
setup(1920,1080)
colormode(255)
speed(0)
hideturtle()
flash = True 
if flash:
    wn = Screen()
    wn.tracer(0)

Ici on appelle les fonctions turtle et random ou plutot uniqument randint. On verifie ensuite on verifie si l’utilisateur a bien PIL d’installer s’il ne l’a pas un code d’erreur s’affichera ainsi qu’un lien pour installer le module. On definie le titre de la fenetre ainsi que sa taille,le type de couleurs utiliséeds (ici R,G,B), on cache la tortue, et randons le script instantané.

Un script en calques

Comme pour tout dessin numérique nous avons besoins de differents calques. Un calque est une couche transparente sur laquelle des éléments graphiques peuvent être placés et manipulés indépendamment les uns des autres. Les differentes fonctions représentent nos calques voici les notres :

background()
batiments()
road()
subaru()
logo()

Background()

def background():
    r = 20
    g = 20
    b = 20
    hauteur = 540
    x = 0
    for i in range(50):
        pensize(10),color(r,g,b),penup(),goto(-960,hauteur),pendown(),forward(1920)
        hauteur = hauteur - 8
        b = b + 1
        r = r + 1 
    goto(-960,hauteur)

    for i in range(37):
        pensize(10),color(r,g,b),penup(),goto(-960,hauteur),pendown(),forward(1920)
        hauteur = hauteur - 10
        g = g + 2
        r = r - 1
    goto(-960,hauteur)

    for i in range(90):
        pensize(7),color(35,35,45),penup(),goto(-960,hauteur + 1),pendown(),forward(1950)
        hauteur = hauteur - 7

Nous avons décomposer fond en 3 parties distinctes: degradé noir vers rose puis rose vers vert pour le ciel puis du gris foncé pour la route.

Pour creer nos degradés nous plaçons notre tortue tout en haut a gauche de notre fenetre puis nous la faisons avancer jusqu’a l’extremité droite. Ensuite on retourne a gauche et on va a la ligne du dessous en diminuant la valeur (hauteur), tout ca grace a la fonction goto. On modifie la couleur en augmantant ou diminuant les valeur (R,G,B) et on recommence. Pour creer la route on fait la meme chose mais sans changer la couleur

batiments()

def batiments():   
    pensize(2)
    penup()
    goto(-960,-226)
    pendown()
    forward(100)
    color(20,20,20),forward(360),begin_fill(),left(90),forward(640),right(100),forward(100),right(80),forward(620),end_fill(),left(90),backward(80),begin_fill(),left(90),forward(650),left(90),forward(120),left(90)
    forward(40),right(70),forward(60),left(70),forward(592),end_fill(),backward(2),left(90),begin_fill(),left(90),forward(640),right(100),forward(100),right(80),forward(624),end_fill(),left(90),backward(260),color(30,30,30)
    begin_fill(),left(90),forward(640),left(100),forward(240),left(80),forward(599),end_fill(),left(90),forward(240),begin_fill(),left(90),forward(640),right(100),forward(240),right(80),forward(599),end_fill()
    left(90),forward(350),begin_fill(),left(90),forward(640),left(100),forward(240),left(80),forward(599),end_fill(),left(90),forward(240),begin_fill(),left(90),forward(640),right(100),forward(100),right(80),forward(620)
    end_fill(),color(20,20,20),begin_fill(),left(90),forward(1),left(90),forward(350),right(45),forward(80),right(95),forward(60),left(50),forward(35),left(25),forward(50),right(115),forward(383),end_fill(),begin_fill()
    left(180),color(25,25,25),forward(430),right(100),forward(80),right(80),forward(415),end_fill(),left(90),begin_fill(),color(15,15,15),forward(3),left(90),forward(250),right(90),forward(80),left(45),forward(20),right(45)
    forward(15),left(90),forward(60),right(90),forward(100),right(90),forward(325),end_fill(),left(90),backward(20),color(25,25,25),begin_fill(),left(90),forward(230),right(95),forward(100),left(95),forward(110),right(80)
    forward(100),right(55),forward(10),right(45),forward(342),end_fill(),begin_fill(),left(90),backward(15),left(90),color(10,15,15),forward(300),right(92),forward(120),right(88),forward(20),left(90),forward(20),right(90)
    forward(275),end_fill(),color(25,25,25),left(180),begin_fill(),forward(275),right(90),left(80),forward(20),right(65),forward(200),right(15),forward(100),right(90),forward(360),end_fill(),left(90)

Pour creer ses batiments sombre rien de plus simple et d’aussi long. Nous avons utilisé les fonctions bengin_fill et end_fill, avec differéntes teintes de gris pour créer du relief

road()

def road():
    color(100,100,100),pensize(7)
    for i in range(2):
        liste_longueur_bandes1 = [2,10,6,10,60,150,]
        liste_longueur_bandes2 = [1,4,7,16,75,220]
        liste_longueur_bandes3 = [2,10,10,12,100,200]
        liste_longueur_bandes4 = [1,4,8,15,25,97]
        liste_longueur_distance_bandes = (1,3,6,9,20,40)
        liste_angle_gauche = [15,20,25,30,43,85]
        liste_angle1 = [90,50,45,35,45,85]
        liste_angle2 = [90,135,135,155,155,133]
        liste_angle3 = [90,70,40,20,25,45]
        liste_angle4 = [90,105,140,150,135,97]
        nblb1 = len(liste_longueur_bandes1)
        nblb2 = len(liste_longueur_bandes2)
        nblb3 = len(liste_longueur_bandes3)
        nblb4 = len(liste_longueur_bandes4)
        nbldb = len(liste_longueur_distance_bandes)
        nba = len(liste_angle_gauche)
        nba1 = len(liste_angle1)
        nba2 = len(liste_angle2)
        nba3 = len(liste_angle3)
        nba4 = len(liste_angle4)
        penup(),goto (-540,-226),pendown()  
        for i in range(6):
            right(liste_angle_gauche[i%nba])
            forward(liste_longueur_bandes1[i%nblb1])
            left(liste_angle1[i%nba1])
            forward(liste_longueur_bandes2[i%nblb2])
            left(liste_angle2[i%nba2])
            forward(liste_longueur_bandes3[i%nblb3])
            left(liste_angle3[i%nba3])
            forward(liste_longueur_bandes4[i%nblb4])
            left(liste_angle4[i%nba4])
            forward(liste_longueur_bandes1[i%nblb1])
            penup()
            forward(liste_longueur_distance_bandes[i%nbldb])
            pendown()
            left(liste_angle_gauche[i%nba])

        color(255,255,255)
        pensize(2)

Pour realiser les bandes nous avons creer des listes contenants les differents parametres de celles ci (longueurs, angle, etc)

subaru()

def subaru():
    color(0,150,250)
    pensize(7)
    for i in range(2):
        penup()
        goto(-330,-200)
        pendown()

        #roue arriere
        left(106),forward(95),left(60),forward(30),left(50),forward(30),backward(30),right(50),backward(30),right(60),forward(25),left(85),forward(40),left(65),forward(25),left(2),forward(30),left(10),forward(45),left(24),forward(40),left(90),forward(35),left(62),forward(60),left(45),forward(35),left(90),forward(37),left(37),forward(40)

        #arriere voiture
        right(155),forward(75),right(55),forward(20),left(45),forward(45),right(45),forward(50),right(25),forward(40)

        #aileron
        left(160),forward(30),right(80),forward(30),right(100),forward(60),backward(60),left(100),forward(8),right(100),forward(60),backward(60),left(80),forward(5),left(10),left(90),forward(20),left(90),forward(50),left(90),forward(35),left(20)
        
        #plafond
        forward(20),left(30),forward(80),right(22),forward(65),right(24),forward(85),right(9),forward(185),right(17),forward(70),backward(20)

        #parebrise
        right(165),forward(70),left(5),forward(145),left(112),forward(95)


        #capot
        left(50),forward(140),right(15),forward(35),left(5)

        #phare
        right(55),forward(32),backward(32),right(85),forward(35),left(90),forward(25),left(80),forward(120),left(110),forward(25),left(65),forward(85),right(10)

        #capot
        left(155),backward(35),left(20),backward(140),left(18),forward(150),left(35),backward(10),forward(20),right(35),forward(110),right(50),forward(10),backward(5),left(50),forward(15),right(40),backward(110) ,forward(110),left(23),forward(130),right(20),forward(50),right(35)


        #phare droit
        forward(20),right(10),forward(10),right(100),forward(60),right(100),forward(20),right(75),forward(50),penup(),goto(-330,-200),right(2),pendown()

        #roue arriere
        left(106),forward(95),left(60),forward(30)

        #dessus du peneu
        left(50),forward(30),backward(30),right(50),backward(30),right(60),forward(25),left(85),forward(40),left(65),forward(25)

        #jante
        left(2),forward(30),left(10),forward(45),left(24),forward(40),left(90),forward(35),left(62),forward(60),left(45),forward(35),left(90),forward(37),left(37),forward(40),left(37),forward(70),left(65),forward(55),left(60),forward(70)
        
        #bas de caisse
        right(58),backward(25),forward(190)

        #roue avant
        left(86),backward(45),right(78),forward(33)

        #jante
        penup(),left(85),forward(90),left(170),pendown(),left(10),forward(45),left(24),forward(40),left(90),forward(35),left(62),forward(60),left(45),forward(35),left(90),forward(37),penup(),left(48),forward(84),pendown(),left(96),backward(33),left(78),forward(112)

        #portiere
        left(10),forward(50),right(20),forward(55),left(35),forward(95),left(60),forward(75),left(35),forward(85),left(30),forward(70),left(124),forward(220),backward(140),left(67),forward(100),backward(180),right(140),forward(80),left(73),forward(140)

        #roue avant
        left(86),forward(20),right(22),forward(56),right(67),forward(50),right(67),forward(6),right(94),forward(47),left(47),forward(40),left(26),forward(62),left(27),forward(42),left(64),forward(71),left(60),forward(50),left(125),forward(15),right(77),forward(115)

        #parechock
        backward(20),right(108),forward(215),left(120),forward(40),right(120),forward(140),right(115),forward(38),left(115),backward(110),forward(190)

        #aeration parchock
        backward(45),penup(),right(90),forward(7),pendown(),right(90),forward(190),left(120),forward(10),right(120),penup(),forward(40),pendown(),forward(60),left(95),forward(20),left(85),forward(50),left(55),forward(25),right(55)
        penup(),forward(35),pendown(),right(60),forward(50),left(60),forward(130),left(60),forward(60),left(30),penup(),forward(7),pendown(),right(90),forward(45)
        
        #parechock
        right(90),backward(10),forward(42),right(90),forward(10),right(60),forward(20),right(120),forward(20),right(90),forward(17),right(90),forward(5),left(85),forward(50),right(86),forward(30),forward(160),left(5),forward(170),backward(170),right(5),backward(160),left(86),forward(40),right(25),forward(20),right(60),forward(57),right(50),forward(20),right(30),forward(40),backward(40),left(80),forward(30),right(85),forward(40),backward(25),left(85),forward(210),right(180),color(255,255,255),pensize(2)

Nous avons dit que les batiments etaient longs? Et bien ce n’est rien a coté de cette subaru. Cette subaru a été bètement dessiné

def logo():
    pensize(4)



    def etoile_logo_main():  
        left(10),forward(60),left(60),forward(40),right(140),forward(40),left(60),forward(60),right(160),forward(60),left(60),forward(40),right(140),forward(40),left(60),forward(60),right(160),forward(60),right(10)
    
    
    def etoile_logo():    
        left(10),forward(30),left(60),forward(20),right(140),forward(20),left(60),forward(30),right(160),forward(30),left(60),forward(20),right(140),forward(20),left(60),forward(30),right(160),forward(30),right(10)
    
    color(255,255,0)
    for i in range(2):
        xetoile = [740,760,680,625,710]
        nbx = len(xetoile)
        yetoile = [400,350,350,305,310]
        nby = len(yetoile)
        for i in range(5):
            penup(),goto (xetoile[i%nbx],yetoile[i%nby]),pendown(),etoile_logo(),penup(),goto (560,380),pendown(),etoile_logo_main()
        pensize(2),color(255,255,255)

Afin de réaliser le logo Subaru nous avons créé deux fonction qui sont aussi simple que la subaru etoile_logo_main() qui correspond a la plus grande étoile et etoile_logo() a la plus petite. Avec goto() on a placer les etoiles a différentes coordonées.

Fin de script

if flash:
    wn.update() 

image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')
try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    
    
except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")

exitonclick()

Ce script permet generer l’image final en .ps puis a la convertir en .png avec un nom aléatoir evitant que l’image précdédemment généré soit écrasé.

Script complet

from turtle import *
from random import randint


try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False
titre = "Bastien.S"
title(titre+" | Subaru Impreza WRC")
setup(1920,1080)

speed(0)
hideturtle()
flash = True 
if flash:
    wn = Screen()
    wn.tracer(0)


# ============== MON SCRIPT PYTHON ==============
colormode(255)


def logo():
    pensize(4)



    def etoile_logo_main():  
        left(10),forward(60),left(60),forward(40),right(140),forward(40),left(60),forward(60),right(160),forward(60),left(60),forward(40),right(140),forward(40),left(60),forward(60),right(160),forward(60),right(10)
    
    
    def etoile_logo():    
        left(10),forward(30),left(60),forward(20),right(140),forward(20),left(60),forward(30),right(160),forward(30),left(60),forward(20),right(140),forward(20),left(60),forward(30),right(160),forward(30),right(10)
    
    color(255,255,0)
    for i in range(2):
        xetoile = [740,760,680,625,710]
        nbx = len(xetoile)
        yetoile = [400,350,350,305,310]
        nby = len(yetoile)
        for i in range(5):
            penup(),goto (xetoile[i%nbx],yetoile[i%nby]),pendown(),etoile_logo(),penup(),goto (560,380),pendown(),etoile_logo_main()
        pensize(2),color(255,255,255)



def background():
    r = 30
    g = 30
    b = 30
    y = 540
    x = 0
    for i in range(50):
        pensize(10),color(r,g,b),penup(),goto(-960,y),pendown(),forward(1920)
        y = y - 8
        b = b + 1
        r = r + 1 
    goto(-960,y)

    for i in range(37):
        pensize(10),color(r,g,b),penup(),goto(-960,y),pendown(),forward(1920)
        y = y - 10
        g = g + 2
        r = r - 1
    goto(-960,y)

    for i in range(90):
        pensize(7),color(35,35,45),penup(),goto(-960,y + 1),pendown(),forward(1950)
        y = y - 7
def batiments():   
    pensize(2)
    penup()
    goto(-960,-226)
    pendown()
    forward(100)
    color(20,20,20),forward(360),begin_fill(),left(90),forward(640),right(100),forward(100),right(80),forward(620),end_fill(),left(90),backward(80),begin_fill(),left(90),forward(650),left(90),forward(120),left(90)
    forward(40),right(70),forward(60),left(70),forward(592),end_fill(),backward(2),left(90),begin_fill(),left(90),forward(640),right(100),forward(100),right(80),forward(624),end_fill(),left(90),backward(260),color(30,30,30)
    begin_fill(),left(90),forward(640),left(100),forward(240),left(80),forward(599),end_fill(),left(90),forward(240),begin_fill(),left(90),forward(640),right(100),forward(240),right(80),forward(599),end_fill()
    left(90),forward(350),begin_fill(),left(90),forward(640),left(100),forward(240),left(80),forward(599),end_fill(),left(90),forward(240),begin_fill(),left(90),forward(640),right(100),forward(100),right(80),forward(620)
    end_fill(),color(20,20,20),begin_fill(),left(90),forward(1),left(90),forward(350),right(45),forward(80),right(95),forward(60),left(50),forward(35),left(25),forward(50),right(115),forward(383),end_fill(),begin_fill()
    left(180),color(25,25,25),forward(430),right(100),forward(80),right(80),forward(415),end_fill(),left(90),begin_fill(),color(15,15,15),forward(3),left(90),forward(250),right(90),forward(80),left(45),forward(20),right(45)
    forward(15),left(90),forward(60),right(90),forward(100),right(90),forward(325),end_fill(),left(90),backward(20),color(25,25,25),begin_fill(),left(90),forward(230),right(95),forward(100),left(95),forward(110),right(80)
    forward(100),right(55),forward(10),right(45),forward(342),end_fill(),begin_fill(),left(90),backward(15),left(90),color(10,15,15),forward(300),right(92),forward(120),right(88),forward(20),left(90),forward(20),right(90)
    forward(275),end_fill(),color(25,25,25)
    left(180),begin_fill(),forward(275),right(90),left(80),forward(20),right(65)
    forward(200),right(15),forward(100),right(90),forward(360),end_fill(),left(90)

t = -200
u = -330
def subaru():
    color(0,150,250)
    pensize(7)
    for i in range(2):
        penup()
        goto(u,t)
        pendown()

        #roue arriere
        left(106),forward(95),left(60),forward(30),left(50),forward(30),backward(30),right(50),backward(30),right(60),forward(25),left(85),forward(40),left(65),forward(25),left(2),forward(30),left(10),forward(45),left(24),forward(40),left(90),forward(35),left(62),forward(60),left(45),forward(35),left(90),forward(37),left(37),forward(40)

        #arriere voiture
        right(155),forward(75),right(55),forward(20),left(45),forward(45),right(45),forward(50),right(25),forward(40)

        #aileron
        left(160),forward(30),right(80),forward(30),right(100),forward(60),backward(60),left(100),forward(8),right(100),forward(60),backward(60),left(80),forward(5),left(10),left(90),forward(20),left(90),forward(50),left(90),forward(35),left(20)
        
        #plafond
        forward(20),left(30),forward(80),right(22),forward(65),right(24),forward(85),right(9),forward(185),right(17),forward(70),backward(20)

        #parebrise
        right(165),forward(70),left(5),forward(145),left(112),forward(95)


        #capot
        left(50),forward(140),right(15),forward(35),left(5)

        #phare
        right(55),forward(32),backward(32),right(85),forward(35),left(90),forward(25),left(80),forward(120),left(110),forward(25),left(65),forward(85),right(10)

        #capot
        left(155),backward(35),left(20),backward(140),left(18),forward(150),left(35),backward(10),forward(20),right(35),forward(110),right(50),forward(10),backward(5),left(50),forward(15),right(40),backward(110) ,forward(110),left(23),forward(130),right(20),forward(50),right(35)


        #phare droit
        forward(20),right(10),forward(10),right(100),forward(60),right(100),forward(20),right(75),forward(50),penup(),goto(u,t),right(2),pendown()

        #roue arriere
        left(106),forward(95),left(60),forward(30)

        #dessus du peneu
        left(50),forward(30),backward(30),right(50),backward(30),right(60),forward(25),left(85),forward(40),left(65),forward(25)

        #jante
        left(2),forward(30),left(10),forward(45),left(24),forward(40),left(90),forward(35),left(62),forward(60),left(45),forward(35),left(90),forward(37),left(37),forward(40),left(37),forward(70),left(65),forward(55),left(60),forward(70)
        
        #bas de caisse
        right(58),backward(25),forward(190)

        #roue avant
        left(86),backward(45),right(78),forward(33)

        #jante
        penup(),left(85),forward(90),left(170),pendown(),left(10),forward(45),left(24),forward(40),left(90),forward(35),left(62),forward(60),left(45),forward(35),left(90),forward(37),penup(),left(48),forward(84),pendown(),left(96),backward(33),left(78),forward(112)

        #portiere
        left(10),forward(50),right(20),forward(55),left(35),forward(95),left(60),forward(75),left(35),forward(85),left(30),forward(70),left(124),forward(220),backward(140),left(67),forward(100),backward(180),right(140),forward(80),left(73),forward(140)

        #roue avant
        left(86),forward(20),right(22),forward(56),right(67),forward(50),right(67),forward(6),right(94),forward(47),left(47),forward(40),left(26),forward(62),left(27),forward(42),left(64),forward(71),left(60),forward(50),left(125),forward(15),right(77),forward(115)

        #parechock
        backward(20),right(108),forward(215),left(120),forward(40),right(120),forward(140),right(115),forward(38),left(115),backward(110),forward(190)

        #aeration parchock
        backward(45),penup(),right(90),forward(7),pendown(),right(90),forward(190),left(120),forward(10),right(120),penup(),forward(40),pendown(),forward(60),left(95),forward(20),left(85),forward(50),left(55),forward(25),right(55)
        penup(),forward(35),pendown(),right(60),forward(50),left(60),forward(130),left(60),forward(60),left(30),penup(),forward(7),pendown(),right(90),forward(45)
        
        #parechock
        right(90),backward(10),forward(42),right(90),forward(10),right(60),forward(20),right(120),forward(20),right(90),forward(17),right(90),forward(5),left(85),forward(50),right(86),forward(30),forward(160),left(5),forward(170),backward(170),right(5),backward(160),left(86),forward(40),right(25),forward(20),right(60),forward(57),right(50),forward(20),right(30),forward(40),backward(40),left(80),forward(30),right(85),forward(40),backward(25),left(85),forward(210),right(180),color(255,255,255),pensize(2)



def road():
    color(100,100,100),pensize(7)
    for i in range(2):
        liste_longueur_bandes1 = [2,10,6,10,60,150,]
        liste_longueur_bandes2 = [1,4,7,16,75,220]
        liste_longueur_bandes3 = [2,10,10,12,100,200]
        liste_longueur_bandes4 = [1,4,8,15,25,97]
        liste_longueur_distance_bandes = (1,3,6,9,20,40)
        liste_angle_gauche = [15,20,25,30,43,85]
        liste_angle1 = [90,50,45,35,45,85]
        liste_angle2 = [90,135,135,155,155,133]
        liste_angle3 = [90,70,40,20,25,45]
        liste_angle4 = [90,105,140,150,135,97]
        nblb1 = len(liste_longueur_bandes1)
        nblb2 = len(liste_longueur_bandes2)
        nblb3 = len(liste_longueur_bandes3)
        nblb4 = len(liste_longueur_bandes4)
        nbldb = len(liste_longueur_distance_bandes)
        nba = len(liste_angle_gauche)
        nba1 = len(liste_angle1)
        nba2 = len(liste_angle2)
        nba3 = len(liste_angle3)
        nba4 = len(liste_angle4)
        penup(),goto (-540,-226),pendown()  
        for i in range(6):
            right(liste_angle_gauche[i%nba])
            forward(liste_longueur_bandes1[i%nblb1])
            left(liste_angle1[i%nba1])
            forward(liste_longueur_bandes2[i%nblb2])
            left(liste_angle2[i%nba2])
            forward(liste_longueur_bandes3[i%nblb3])
            left(liste_angle3[i%nba3])
            forward(liste_longueur_bandes4[i%nblb4])
            left(liste_angle4[i%nba4])
            forward(liste_longueur_bandes1[i%nblb1])
            penup()
            forward(liste_longueur_distance_bandes[i%nbldb])
            pendown()
            left(liste_angle_gauche[i%nba])

        color(255,255,255)
        pensize(2)

#calque ===================================
background()
batiments()
road()
subaru()
logo()

#GENERER DES IMAGES AUTOMATIQUEMENT ==============

if flash:
    wn.update() 

image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')
try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    
    
except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")

exitonclick()

Télécharger mon script

Le rendu final

Art

Extraction minière au sein de l’Himalaya

Le premier projet de la classe de 1ère NSI est « Image générative ». Ce projet consiste en la création d’une image sur thème libre. Pour notre image, on a choisi d’aborder les thèmes de la montagne, du ciel et de la mine. Nous avons voulu représenter ainsi, une mine présente au sein de la chaine de montagnes de l’Himalaya sous un ciel étoilé de nuit avec une lune en fond venant se glisser derrière la montagne.

Le fond

Afin de réaliser le fond de notre image, nous avons voulu réaliser un fond dégradé du bleu foncé vers le bleu clair afin de représenter la nuit tombante.

def fond():
    for i in range(720):
        r = 173 - round((i / (720 / 173)))  
        v = 216 - round((i / (720 / 216))) 
        b = 230 - round((i / (720 / 102)))
        pencolor(r, v, b)
        forward(1280)
        goto(-640, -360 + i)

fond()

Les étoiles

Ensuite pour réaliser l’ambiance de nuit tombante, nous avons fait le choix de rajouter des étoiles. Pour cela nous avons utilisé le module « randint » nous permettant de placer les étoiles de manière aléatoire.

def etoile():
    pencolor("#fff7cd")
    fillcolor("#fff7cd")
    for _ in range(130):
        penup()
        x = randint(-650, 650)
        y = randint(-360, 360)
        goto(x, y)
        pendown()
        begin_fill()
        circle(randint(1, 4))
        end_fill()
etoile()

Lune

Pour rester dans cette ambiance de nuit tombante nous avons rajouté une lune en fond à laquelle nous avons rajouté des taches pour que celle ci soit plus fidèle à la vrai lune.

def lune():
    penup()
    goto(10,-50)
    color("#EEF0F1")
    fillcolor("#EEF0F1")
    begin_fill()
    circle(220)
    end_fill()
lune()

def taches(x, y,z):
    for i in range(15):
        penup()
        goto(x, y)
        pendown()
        shapesize(z)
        pencolor("#000000")  
        fillcolor("#a4a4a4")  
        begin_fill()  
        circle(z)
        end_fill()
taches(100, 200,20)
taches(-110, 100,50)
taches(-90, 250,30)
taches(0, 200,15)
taches(70, 75,42)
taches(70, 270,24)
taches(150, 100,12)

Les montagnes

Ici nous avons créer des montagnes sous forme de chaine où logera par la suite notre grotte minière. Nous avons rajouter un rectangle afin de combler le trou entre les montagnes même si cela est peux conventionnel.

def triangle(x,y,z):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#757575") 
    fillcolor("#757575")
    begin_fill()
    for i in range(3):
        forward(500)
        left(120)    
    end_fill()
triangle(-235,-200,10)
triangle(70,-350,10)
triangle(-600,-350,10)
triangle(-450,-400,10)
triangle(-800,-500,10)
triangle(310,-500,10)
def rectangle():
    penup()
    goto(-110,-250)
    pendown()
    pensize(150)
    pencolor("#757575")
    forward(400) #Peu conventionnel
rectangle()

Ombre des montagnes

Afin de rajouter du réalisme à notre image nous avons décidé de rajouter une ombre derrière les montagnes en suivant presque le même schéma que celles ci.

def ombre(x,y,z):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#323232") 
    fillcolor("#323232")
    begin_fill()
    for i in range(3):
        forward(500)
        left(120)    
    end_fill()
ombre(-280,-200,10)
ombre(30,-350,10)
ombre(-640,-350,10)
ombre(-490,-400,10)
ombre(-840,-500,10)
ombre(270,-500,10)

Le sol

Nous avons décidé de faire un sol dégradé marron foncé afin de rappeler la couleur de la terre et aussi se rapprocher du modèle réel présent dans la réalité.

def sol():
    for i in range(107):
        r = round(101 + (30 - 60) * (i / 107))  
        v = round(67 + (1 - 20) * (i / 107))    
        b = round(33 + (1 - 20) * (i / 107))    
        pencolor(r, v, b)                     
        forward(1280)                        
        goto(-640, -360 + i)                
sol()

La grotte

La grotte était notre idée principale ainsi nous avons décidé de la mettre au centre. Pour marquer la profondeur de celle ci nous avons choisi le noir pour récréer l’obscurité de la grotte.

def entree(x,y,z):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#000000") 
    fillcolor("#000000")
    begin_fill()
    for i in range(3):
        forward(z)
        left(120)    
    end_fill()

entree(-120,-253,150)
entree(-90,-253,165)
entree(40,-253,50)

La neige

Toujours dans la dynamique de ressemblance à la réalité, nous avons fait le choix de rajouter au sommet des montagnes de la neige comme sur les sommet de l’Himalaya. Pour cela nous avons encore utilisé la fonction triangle que nous avons préalablement définie.

def neige(x,y,z,w):
    penup()
    goto(x,y)
    pendown()
    pensize(4)
    color("#f7f7f7") 
    fillcolor("#f7f7f7")
    begin_fill()
    for i in range(3):
        forward(z)
        left(w)    
    end_fill()
neige(-49,120,130,120)
neige(-50,120,30,-120)
neige(-20,120,50,-120)
neige(35,120,15,-120)
neige(50,120,30,-120)

neige(273,0,95,120)
neige(273,0,30,-120)
neige(300,0,15,-120)
neige(310,10,40,-120)
neige(350,0,15,-120)

neige(-397,0,95,120)
neige(-397,0,30,-120)
neige(-340,0,15,-120)
neige(-365,5,25,-120)
neige(-328,0,25,-120)

neige(-225,-10,50,120)
neige(-225,-10,10,-120)
neige(-210,-10,20,-120)
neige(-190,-10,15,-120)

neige(-575,-110,50,120)
neige(-575,-110,10,-120)
neige(-560,-110,15,-120)
neige(-548,-107,10,-120)
neige(-540,-110,15,-120)

neige(535,-110,50,120)
neige(535,-110,18,-120)
neige(555,-110,9,-120)
neige(565,-110,20,-120)

Relief

Toujours dans une démarche de réalisme, nous avons voulu apporter un relief à, la montagne paraissant plate. Pour cela nous avons simplement tracé des traits prolongeant certaines arrête des montagnes.

def delimitation(x,y,z,w):
    pencolor("#2c2c2c")
    pensize(3)
    penup()
    goto(x,y)
    pendown()
    goto(z,w)
delimitation(-60,110,-208,-150)
penup()
delimitation(-402,0,-519,-210)
penup()
delimitation(270,-1,145,-210)

Chariot

En accord avec notre première idée, nous avons rajouté un chariot à la mine pour que de un l’image soit plus compréhensible mais aussi pour venir rajouter des détail à notre image. Nous avons fait le choix également de rajouter des rails pour celui ci.

Problèmes rencontrés

Nous avons eu de nombreux problèmes durant la création de notre image. En effet lors de faire la lune nous avions eu pour idée de rendre les taches aléatoire avec le module « randint » , mais cela n’allais pas car les taches se superposais et ne changeais pas de taille. Aussi lorsque nous avons fais le wagon nous réfléchissions a un moyen de le remplir réalistement mais nous n’avons pas trouver alors nous avons fais le choix de placer de simples triangles.

Sources

Afin de réaliser notre image, nous avons utilisé plusieurs sources : Tout d’abord nous avons utilisé chat gpt afin de déboguer certaines parties de notre code, ensuite nous avons utilisé le forum « stack overflow » pour trouver notre fond et réaliser notre dégradé, enfin nous avons utilisé le site « python guides » pour nous renseigner sur des commandes notamment sur l’utilisation du module « random » lors de la création des étoiles.

Projets

A Day In Minecraft

Minecraft est un jeu vidéo de type aventure « bac a sable » (construction complètement libre) développé par le Suédois Markus Persson, alias Notch, puis par la société Mojang Studios. Il s’agit d’un univers composé de voxels et généré de façon procédurale, qui intègre un système d’artisanat axé sur l’exploitation puis la transformation de ressources naturelles. Cet article montre la conception graphique à travers l’exemple de l’univers du jeu.

Le Projet

Comme cité dans l’introduction, cet article a pour but de montrer en détails la réalisation de notre conception graphique de l’univers de Minecraft. Pour ce projet, nous avons donc utilisé le module turtle, ainsi que le module random. Le script permettant d’exporter l’image générée a aussi été utilisé.

Le Code, en détails

Le code, dans son ensemble, est organisé avec chaque élément découpé et distinguable :

Tout d’abord, commençons par importation des librairies, ainsi que l’appel des fonctions :

from turtle import *
from random import randint

try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False

titre = "Perspective - A Day In Minecraft"

title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")

setup(1280, 720)

speed(0)
hideturtle()


flash = True
if flash:
    wn = Screen()
    wn.tracer(0)

On ajoute donc les librairies turtle, ainsi que random, puis, une partie du script qui permet d’« exporter une image générée par turtle » est utilisée afin de vérifier que l’utilisateur a bien installé le module PIL (PILLOW), sinon un message d’erreur s’affichera et lui donnera un lien pour installer le module. Après que la vérification soit terminée, on met en place la partie du script qui permet de nommer la fenêtre qui va s’afficher avec le rendu ainsi que sa taille. Enfin on ajoute le type de couleurs utilisées (RGB par exemple), la vitesse de la tortue, et on dissimule cette dernière.

Apres cette étape, nous pouvons enfin commencer a coder avec turtle.

pour la première étape, nous avons le fond :

import turtle

colormode(255)

def ciel():
    penup()
    # Valeurs initiales pour un bleu plus foncé
    rciel = 30   # Valeur de rouge
    gciel = 144  # Valeur de vert
    bciel = 255  # Valeur de bleu
    hauteur = -360
    goto(-640, -358)
    pendown()

    # Durée totale pour le dégradé
    total_steps = 720
    
    while hauteur <= 360:
        # Premier demi dégradé: Du bleu foncé au blanc
        if hauteur <= 0:  
            r_incr = (255 - rciel) / (total_steps / 2)  # Incrément de rouge
            g_incr = (255 - gciel) / (total_steps / 2)  # Incrément de vert
            b_incr = (255 - bciel) / (total_steps / 2)  # Incrément de bleu
        else:  # Deuxième demi dégradé: Du blanc au bleu clair
            r_incr = (173 - 255) / (total_steps / 2)  # Incrément de rouge vers bleu clair
            g_incr = (216 - 255) / (total_steps / 2)  # Incrément de vert vers bleu clair
            b_incr = (230 - 255) / (total_steps / 2)  # Incrément de bleu vers bleu clair
        
        pencolor(round(rciel), round(gciel), round(bciel))
        forward(1280)
        hauteur += 1
        goto(-640, hauteur)
        
        # Incrémenter les valeurs de couleur
        rciel += r_incr
        gciel += g_incr
        bciel += b_incr

Tout d’abord, le code commence configurer le mode de couleur pour utiliser le modèle RGB, où les valeurs des couleurs rouge, vert et bleu peuvent varier de 0 à 255. Une fonction nommée ciel est définie pour encapsuler tout le code de dessin. À l’intérieur de cette fonction, le stylo est levé au début, ce qui signifie que la tortue ne dessine pas lorsque elle se déplace à sa position initiale. Des variables sont initialisées pour représenter les valeurs de couleur du dégradé, avec une première couleur qui est un bleu plutôt clair. La tortue est ensuite déplacée à une position spécifique sur l’écran sans dessiner. Le code définit aussi une variable pour le nombre total d’étapes du dégradé, fixé à 720, ce qui représente le nombre d’itérations dans la boucle qui va dessiner le dégradé. Ensuite, une boucle commence et continuera tant que la hauteur de la tortue est inférieure ou égale à 360. Cette boucle est essentielle pour dessiner le dégradé de couleur. À chaque itération, il y a une condition qui vérifie si la tortue est dans la première moitié du dégradé (jusqu’à une hauteur de 0). Si c’est le cas, des incréments pour chaque composante de couleur sont calculés afin de passer du bleu foncé au blanc. Si la tortue est dans la seconde moitié du dégradé (au-dessus de 0), le code calcule de nouveaux incréments pour faire la transition du blanc vers une nuance de bleu clair. Dans chaque itération, la couleur actuelle du stylo est définie en fonction des valeurs calculées, puis la tortue se déplace en avant pour dessiner une ligne horizontale. Ensuite, la hauteur est augmentée pour passer à la ligne suivante, et la tortue est déplacée vers la nouvelle position. Enfin, à chaque étape de la boucle, les valeurs de couleur sont mises à jour en ajoutant les incréments précédemment calculés, permettant au dégradé de progresser progressivement à travers l’écran. Le résultat est un effet de ciel qui commence en bleu clair en haut, devient blanc au milieu, puis continue vers une couleur bleu clair en bas, recréant ainsi un effet visuel similaire à celui du ciel dans le jeu Minecraft.

Ensuite, la fonction créant les nuages est ajoutée :

def carre(x, y, size):
    # Dessine un carré de taille donnée aux coordonnées spécifiées
    penup()
    goto(x, y)
    pendown()
    color("white")
    begin_fill()
    for _ in range(4):
        forward(size)
        right(90)
    end_fill()

def unnuage(x, y, size, grid_width, grid_height):
    # Dessine un nuage carré et homogène composé d'une grille de carrés
    for row in range(grid_height):
        for col in range(grid_width):
            # Positionne chaque carré dans une disposition en grille
            square_x = x + col * size
            square_y = y - row * size
            carre(square_x, square_y, size)
                       
def lesnuages():
    # Place des nuages carrés et homogènes avec de grandes distances entre eux
    cloud_positions = [
        (-500, 250), (-200, 300), (100, 310), 
        (400, 310), (0, 180)]
    for x, y in cloud_positions:
        unnuage(x, y, size=20, grid_width=10, grid_height=5)  # Taille et dimensions de chaque nuage

# Appel des fonctions pour dessiner le ciel et les nuages
lesnuages()

Le code utilise la bibliothèque turtle de Python pour dessiner des nuages sous forme de carrés. La fonction carre(x, y, size) dessine un carré d’une taille spécifiée aux coordonnées (x, y). Elle commence par lever le stylo pour ne pas dessiner en se déplaçant, puis elle se positionne au point donné, abaisse le stylo, et définit la couleur de remplissage à blanc. Ensuite, elle dessine le carré en avançant et en tournant à droite à chaque coin, avant de terminer le remplissage. La fonction unnuage(x, y, size, grid_width, grid_height) crée un nuage en formant une grille de carrés. Elle utilise des boucles imbriquées pour parcourir les lignes et les colonnes de la grille, calculant les coordonnées de chaque carré en fonction de la taille spécifiée. Chaque carré est dessiné en appelant la fonction carre. Enfin, la fonction lesnuages() détermine où les nuages doivent être placés sur l’écran. Elle utilise une liste de positions prédéfinies pour placer plusieurs nuages avec un certain espacement entre eux. En appelant ces fonctions, le code dessine une série de nuages carrés et homogènes sur l’écran.

Pour la prochaine étape, nous coderons le soleil :

def draw_square(x, y, size,color):
    # Fonction pour dessiner un carré de couleur donnée aux coordonnées spécifiées
    penup()
    goto(x, y)
    pendown()
    turtle.color(color)
    begin_fill()
    for _ in range(4):
        forward(size)
        right(90)
    end_fill()

def soleil():
    # Centre du soleil (carré jaune)
    sun_size = 125  # Taille du carré central du soleil
    sun_x = -sun_size / 2  # Position X pour centrer le soleil
    sun_y = 250  # Position Y pour placer le soleil en haut de l'écran
    draw_square(sun_x, sun_y, sun_size, 'yellow')

# Dessiner le soleil
soleil()

Ce code utilise également la bibliothèque turtle pour dessiner un soleil sous forme de carré coloré. La fonction draw_square(x, y, size, color) permet de dessiner un carré aux coordonnées (x, y) avec une taille spécifiée et une couleur donnée. Elle commence par lever le stylo pour éviter de dessiner en se déplaçant, puis elle se positionne à la coordonnée indiquée. Après avoir abaissé le stylo, elle définit la couleur du carré en utilisant turtle.color(color). Ensuite, elle commence à remplir la forme et dessine le carré en avançant et en tournant à droite de 90 degrés à chaque coin. Une fois le carré terminé, elle termine le remplissage avec end_fill(). La fonction soleil() est responsable du dessin du soleil, elle définit d’abord la taille du carré central (sun_size) à 125 pixels et calcule les coordonnées pour centrer le carré en soustrayant la moitié de sa taille de la position X (sun_x). La position Y (sun_y) est fixée à 250 pour placer le soleil en haut de l’écran. Elle appelle ensuite la fonction draw_square pour dessiner le carré représentant le soleil, en le remplissant de couleur jaune. Enfin, l’appel à soleil() exécute cette fonction, ce qui dessine un grand carré jaune en haut de l’écran, représentant le soleil.

Puis, nous voyons le script permettant de de dessiner les blocs d’herbe :

def herbe():
    # Configuration de l'herbe pixelisée
    penup()
    grass_height = 360  # Moitié de la hauteur de l'écran (720 / 2)
    pixel_size = 20  # Taille de chaque pixel (carré)
    
    # Dessiner des "pixels" de différentes nuances de vert dans la moitié inférieure
    for y in range(-360, 0, pixel_size):
        for x in range(-640, 640, pixel_size):
            # Choisir une nuance de vert aléatoire pour chaque carré
            green_value = random.randint(200, 255)  # Valeur de vert entre 100 et 255
            color = "#00%02x00" % green_value  # Couleur hexadécimale pour une teinte de vert
            goto(x, y)
            turtle.color(color)
            begin_fill()
            for _ in range(4):
                forward(pixel_size)
                right(90)
            end_fill()

# Dessin de l'herbe pixelisée, de la végétation et des fleurs
herbe()

La fonction herbe() est responsable du dessin de l’herbe pixelisée. Elle commence par lever le stylo avec penup() pour éviter de dessiner en se déplaçant. Ensuite, elle définit la hauteur de l’herbe en spécifiant grass_height à 360, ce qui correspond à la moitié de la hauteur de l’écran (720 pixels). La variable pixel_size est définie à 20, ce qui détermine la taille de chaque « pixel » (carré) d’herbe. Le code utilise deux boucles imbriquées pour parcourir les coordonnées de la zone où l’herbe sera dessinée. La première boucle itère sur les coordonnées Y de -360 à 0 (la moitié inférieure de l’écran), et la seconde boucle itère sur les coordonnées X de -640 à 640, couvrant ainsi toute la largeur de l’écran. À l’intérieur de la boucle, une valeur de vert aléatoire est choisie pour chaque carré en utilisant random.randint(200, 255). Cela génère une nuance de vert qui sera plus claire, puisque les valeurs hexadécimales de vert vont de 200 à 255. La couleur hexadécimale est ensuite formatée en utilisant color = "#00%02x00" % green_value, ce qui crée une chaîne de caractères représentant une couleur verte dans le format hexadécimal (ex. #00CC00). Pour chaque pixel d’herbe, le curseur se déplace aux coordonnées (x, y) correspondantes, et la couleur est définie. Ensuite, le remplissage commence avec begin_fill(), et un carré est dessiné en avançant de pixel_size et en tournant à droite de 90 degrés à chaque coin. Une fois le carré terminé, end_fill() termine le remplissage de ce pixel.

Il ne reste plus que deux étapes, parmi celles-ci, on ajoute au code un script permettant de dessiner un arbre.

# Fonction pour dessiner un carré pour les blocs
def draw_block(t, size, color):
    t.begin_fill()
    t.color(color)
    for _ in range(4):
        t.forward(size)
        t.left(90)
    t.end_fill()

# Fonction pour dessiner un arbre style Minecraft
def draw_minecraft_tree(x, y):
    block_size = 65  # Taille de chaque bloc pour un effet fidèle

    # Tronc de l'arbre en 4 blocs verticaux
    trunk = turtle.Turtle()
    trunk.hideturtle()
    trunk.speed("fastest")
    trunk.penup()
    trunk.goto(x, y)
    trunk.pendown()
    
    for i in range(4):  # Tronc de 4 blocs de hauteur
        draw_block(trunk, block_size, "saddle brown")
        trunk.penup()
        trunk.goto(x, y + (i + 1) * block_size)
        trunk.pendown()
    
    # Feuillage de l'arbre en blocs
    foliage = turtle.Turtle()
    foliage.hideturtle()
    foliage.speed("fastest")
    foliage.penup()

    # Position des blocs de feuillage par rapport au tronc
    foliage_positions = [
        (-1, 4), (0, 4), (1, 4),  # Rangée supérieure
        (-1, 3), (0, 3), (1, 3),  # Rangée au milieu
        (-2, 3), (2, 3),           # Côtés de la rangée au milieu
        (-1, 2), (1, 2), (0, 2)   # Rangée inférieure
    ]

    for pos in foliage_positions:
        foliage.goto(x + pos[0] * block_size, y + pos[1] * block_size)
        foliage.pendown()
        draw_block(foliage, block_size, "forest green")
        foliage.penup()

# Dessiner l'arbre style Minecraft à gauche
draw_minecraft_tree(-500, -100)
draw_minecraft_tree(150, -100)
draw_minecraft_tree(600, -200)

La fonction draw_block(t, size, color) dessine un carré de couleur spécifiée avec une taille donnée. Elle commence le remplissage, définit la couleur, puis dessine les quatre côtés du bloc en tournant à gauche de 90 degrés après chaque côté, et termine le remplissage une fois le bloc dessiné. La fonction draw_minecraft_tree(x, y) est responsable du dessin d’un arbre aux coordonnées (x, y). Elle fixe la taille de chaque bloc à 65 pixels et crée un Turtle pour dessiner le tronc. Ce Turtle se positionne aux coordonnées données et dessine quatre blocs verticaux pour former le tronc en utilisant une couleur marron. Après avoir dessiné chaque bloc, le Turtle se déplace vers le haut pour la prochaine position. Un second Turtle, destiné au feuillage, est également créé. Il est configuré pour dessiner des blocs de feuillage verts autour du tronc, avec des positions définies dans une liste pour donner une forme arrondie. Pour chaque position de feuillage, le Turtle se déplace aux coordonnées calculées et dessine un bloc de couleur verte. Enfin, la fonction draw_minecraft_tree est appelée trois fois avec différentes coordonnées pour dessiner trois arbres à des endroits variés de l’écran. Ce code crée ainsi une représentation d’arbres en blocs de style Minecraft, composés de carrés pour le tronc et le feuillage.

Enfin, pour donner la touche finale qui va donner vie a notre conception graphique sur le thème de Minecraft, on ajoute un dernier script qui permet de dessiner un Creeper :

# Fonction pour dessiner un sous-bloc "pixel"
def draw_pixel(t, size, color):
    t.begin_fill()
    t.color(color)
    for _ in range(4):
        t.forward(size)
        t.left(90)
    t.end_fill()

# Fonction pour dessiner un bloc pixelisé avec un mélange de couleurs
def draw_pixelated_block(t, x, y, block_size, pixel_size, colors):
    t.penup()
    for row in range(block_size // pixel_size):
        for col in range(block_size // pixel_size):
            t.goto(x + col * pixel_size, y - row * pixel_size)
            t.pendown()
            color = colors[(row + col + (row % 2)) % len(colors)]
            draw_pixel(t, pixel_size, color)
            t.penup()

# Fonction pour dessiner un visage Creeper précis
def draw_creeper_face(t, x, y, pixel_size):
    t.penup()
    # Yeux (4 pixels chacun)
    t.goto(x + pixel_size, y - 1 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    t.goto(x + 2 * pixel_size, y - 1 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    t.goto(x + pixel_size, y - 2 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    t.goto(x + 2 * pixel_size, y - 2 * pixel_size)
    draw_pixel(t, pixel_size, "black")

    t.goto(x + 4 * pixel_size, y - 1 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    t.goto(x + 5 * pixel_size, y - 1 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    t.goto(x + 4 * pixel_size, y - 2 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    t.goto(x + 5 * pixel_size, y - 2 * pixel_size)
    draw_pixel(t, pixel_size, "black")
    
    # Bouche (3x2 pixels pour la rangée supérieure, 2x1 pixels pour la rangée inférieure)
    t.goto(x + 15, y - 4 * pixel_size)
    for _ in range(4):
        draw_pixel(t, pixel_size, "black")
        t.forward(pixel_size)
    t.goto(x + 25, y - 3 * pixel_size)
    for _ in range(2):
        draw_pixel(t, pixel_size, "black")
        t.forward(pixel_size)
    t.goto(x + 15, y - 5 * pixel_size)
    for _ in range(4):
        draw_pixel(t, pixel_size, "black")
        t.forward(pixel_size)
    t.goto(x + 45, y - 6 * pixel_size)
    for _ in range(1):
        draw_pixel(t, pixel_size, "black")
        t.forward(pixel_size)
    t.goto(x + 15, y - 6 * pixel_size)
    for _ in range(1):
        draw_pixel(t, pixel_size, "black")
        t.forward(pixel_size)
    

# Fonction pour dessiner un Creeper Minecraft pixelisé complet
def draw_pixelated_creeper(x, y):
    block_size = 70  # Taille de chaque section principale du Creeper
    pixel_size = 10  # Taille de chaque pixel

    # Couleurs pour le visage et le corps du Creeper
    face_colors = ["#2E8B57", "#228B22", "#32CD32", "#006400"]
    body_colors = ["#228B22", "#006400", "#32CD32"]

    creeper = turtle.Turtle()
    creeper.hideturtle()
    creeper.speed("fastest")

    # Tête du Creeper avec visage
    draw_pixelated_block(creeper, x, y, block_size, pixel_size, face_colors)
    draw_creeper_face(creeper, x, y, pixel_size)

    # Corps du Creeper (2 blocs de hauteur sous la tête)
    for i in range(2):
        draw_pixelated_block(creeper, x, y - (i + 1) * block_size, block_size, pixel_size, body_colors)

    # Pieds du Creeper (2 blocs de largeur sous le corps)
    for i in range(2):
        draw_pixelated_block(creeper, x - block_size // 2, y - (i + 3) * block_size, block_size // 2, pixel_size, body_colors)
        draw_pixelated_block(creeper, x + block_size // 2, y - (i + 3) * block_size, block_size // 2, pixel_size, body_colors)

# Dessiner le Creeper pixelisé à droite
draw_pixelated_creeper(450, 50)

Et voila ! Nous voici avec une image qui représente (plus ou moins 😅) l’univers du jeu vidéo Minecraft, et cela, avec turtle et random !

Les difficultés du projet

Durant ce projet, nous avons eus quelques difficultés a savoir lors de la correction du code ou encore lorsqu’il fallait positionner certains éléments. Nous avons, bien que très peu, utilisés l’AI Chat GPT pour nous guider dans la correction ou encore quelques conceptions de script.

Art

Le grand canyon

Pour ce premier projet en spécialité NSI, nous avons décidé de produire un paysage inspiré du Grand Canyon. Dans cet article, vous pourrait retrouver toutes les étapes pour créer cette image.

Le projet

Pour ce projet nous avons donc décidé de produire une image d’un paysage inspirée du Grand Canyon. Pour cela nous utilisons le module turtle, le module utilisé pour produire l’image ainsi que le module random. Nous avons également utilisé le script permettant d’exporter une image générée par turtle en .png que vous pouvez retrouver ici.

Au commencement

Nous nous sommes tout d’abord inspirés de l’image ci-dessous, et après en avoir réalisé un rapide croquis à la main nous avons commencé notre script : nous avons créé plusieurs fonctions pour chaque élément, que nous avons ensuite appelées dans un ordre précis à la fin du code. 

Structure du script

Pour la structure de notre script, nous avons choisi de réaliser seulement des fonctions (sol, soleil, cactus, montagnes…) et de les appeler à la fin dans un ordre respectif, en y mettant les coordonnées pour celles qui le demande, afin de construire notre image.

Le script étape par étape

Commençons par l’appel des modules et la mise en place de turtle.

from turtle import *
from random import randint

"""
Ce fichier est expliqué ici : https://nsi.xyz/py2png
Un autre tutoriel permet de commencer : https://nsi.xyz/tutoriels/decouvrir-le-module-turtle-de-python/
"""

try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False
titre = "Paysage - construite avec turtle"
title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")
setup(1280, 720)
colormode(255)
speed(0)
hideturtle()

Ce code permet d’appeler les différents modules mais également de vérifier que l’utilisateur a bien installé le module PIL et dans le cas contraire un message d’erreur s’affichera et lui donnera un lien pour installer le module et tout ça sans que le script ne s’arrête.  Aprés vérification du bon fonctionnement du script, on met à jour le titre du projet ainsi que sa taille. Enfin on définit le type de couleurs utilisées (R,G,B), la vitesse de la tortue, et on la dissimule.

Commençons par la première fonction : le fond

def fond():
penup()
rciel = 0
gciel = 0
bciel = 0
hauteur = -360
goto(-642,-358)
pendown()
while hauteur != 360:
pencolor(round(189 + rciel), round(224 + gciel), round(254 + bciel))
forward(1280)
hauteur += 1
goto(-640, hauteur)
rciel += (-42/180)
gciel += (-7/45)
bciel += (-15/500)

Pour le fond on aurait pu utiliser une fonction qui crée directement un rectangle et qui le remplit avec fill_rect, or celui-ci aurait été uni alors que nous souhaitons observé un léger dégradé. Nous avons donc produit un script qui, en faisant avancé la tortue à partir d’un point de départ goto et qui ajoute la différence de chaque couleur (rouge, vert et bleu) entre la couleur de début du dégradé et la couleur de fin, produit un fond dégradé, ici de couleur bleue.

Deuxième, troisième et quatrième fonction : Les sols

def sol1():
	penup()
	goto(-640,-360)
	fillcolor(65, 72, 51)
	begin_fill()
	forward(1280)
	left(90)
	forward(175)
	left(90)
	forward(1280)
	left(90)
	forward(175)
	left(90)
	end_fill()

Pour réaliser un effet de profondeur nous avons réalisé un dégradé au niveau des sols en créant trois fonctions différentes sous la forme de la première fonction : sol1(). Pour réaliser le sol on a utilisé de nouveau goto qui permet de placer la tortue avant de la faire avancer pour remplir l’espace.

On répète donc cette fonction en changeant les coordonnées de goto et en éclaircissant la couleur.

def sol2():
	penup()
	goto(-640,-186)
	fillcolor(101, 109, 74)
	begin_fill()
	forward(1280)
	left(90)
	forward(50)
	left(90)
	forward(1280)
	left(90)
	forward(50)
	left(90)

def sol3():
	penup()
	goto(-640,-137)
	fillcolor(164, 172, 134)
	begin_fill()
	forward(1280)
	left(90)
	forward(50)
	left(90)
	forward(1280)
	left(90)
	forward(50)
	left(90)
	end_fill()

Ensuite on réalise les montagnes, pour cela on doit créer différentes fonctions, car aucune montagne n’a la même forme.

Montagne 1 :

def montagne1():
    #montagne derrière la première
    penup()
    goto(-560,-190)
    fillcolor(158, 78, 39)
    begin_fill()
    forward(250)
    left(120)
    forward(50)
    right(30)
    forward(160)
    left(90)
    forward(10)
    left(90)
    forward(50)
    right(90)
    forward(5)
    right(90)
    forward(80)
    left(90)
    forward(140)
    left(90)
    forward(40)
    right(90)
    forward(8)
    left(90)
    forward(120)
    right(42)
    forward(70)
    end_fill()

On utilise donc de nouveau goto pour faire déplacer notre tortue et faire en sorte qu’elle dessine a peu près la même forme de montagne que sur la photo. On remplit à l’aide de begin_fill() que l’on arrête à la fin avec end_fill().

On crée ensuite les autres montagnes en changeant la forme et en les éclaircissant légèrement pour créer un effet de profondeur.

Montagne 2 et 3 :

def montagne2():
    #montagne derrière la première
    penup()
    goto(340,-150)
    fillcolor(173, 94, 55)
    begin_fill()
    right(228)
    forward(210)
    left(120)
    forward(30)
    right(30)
    forward(130)
    left(90)
    forward(140)
    left(90)
    forward(9)
    right(80)
    forward(10)
    left(78)
    forward(120)
    right(40)
    forward(2)
    end_fill()
    
def montagne3():
    #montagne derrière la première
    penup()
    goto(-60,-100)
    fillcolor(201, 116, 75)
    begin_fill()
    left(132)
    forward(125)
    left(120)
    forward(50)
    right(30)
    forward(75)
    left(90)
    forward(15)
    right(45)
    forward(7)
    left(45)
    forward(25)
    left(45)
    forward(7)
    right(45)
    forward(26)
    left(90)
    forward(26)
    right(90)
    forward(5)
    right(90)
    forward(10)
    left(90)
    forward(5)
    left(90)
    forward(50)
    right(50)
    forward(5)
    end_fill()

Ensuite la fonction permettant de dessiner les cactus : On a d’abord attribué les coordonnées x et y à la fonction cactus, qui seront choisies lors de son appel,  déterminant alors l’emplacement du cactus sur l’écran, et permettant de l’appeler plusieurs fois a différent coordonnées. On définit ensuite la couleur, la taille et l’épaisseur du trait, on oriente la tortue vers le bas avec la fonction setheading()à 270, puis on commence à dessiner les bras et le tronc du cactus.

def cactus(x, y) :
    pencolor(56, 176, 0)
    pensize(10)
    penup()
    goto(x, y)
    pendown()
    setheading(270)
    forward(50)
    left(90)
    forward(30)
    left(90)
    forward(50)
    penup()
    goto(x + 16, y + 16)
    pendown()
    setheading(270)
    forward(125)

On réalise une autre fonction qui dessine un cactus comme le code précédent mais avec des dimensions différentes.

def cactus_petit(x, y) :
    pencolor(56, 176, 0)
    pensize(5)
    penup()
    goto(x, y)
    pendown()
    setheading(270)
    forward(25)
    left(90)
    forward(15)
    left(90)
    forward(25)
    penup()
    goto(x + 7, y + 7)
    pendown()
    setheading(270)
    forward(65)

Pour dessiner les virevoltants, que l’on peut retrouver dans le désert : on a tout d’abord attribue les coordonnées x et y (comme précédemment) à la fonction paille, pour l’appeler à différents endroits de l’image. Nous avons ensuite crée une boucle « for i in range » qui dessine des cercles beiges et qui incrémente 1 à chaque nouveau cercle dessiné, réalisant donc, à chaque répétition, des cercles de plus en plus grands.

def paille(x, y) :
    penup()
    goto(x,y)
    pendown()
    radius = 0
    for i in range(20) :
        color(166, 138, 100)
        pensize(1)
        circle(radius)
        radius += 1
       

Par la suite nous codons la fonction dessinant les nuages : On a (encore une fois) attribue les coordonnées x et y à la fonction nuage, pour l’appeler à différents endroits de l’image ; pour que les deux nuages soient tous les deux horizontaux, on utilise la fonction setheading() en l’orientant à 0 et on dessine ensuite 3 cercles blancs de différentes tailles, chacun d’eux avançant après avoir été dessiné.

def nuage(x, y):
    penup()
    goto(x, y)
    setheading(0)
    fillcolor(255, 255, 255)
    begin_fill()
    circle(25)
    forward(40)
    circle(35)
    forward(35)
    circle(18)
    end_fill()

Puis celle pour dessiner le soleil : on a tout simplement établit l’emplacement de celui-ci et fait un cercle de couleur jaune.

def soleil() :
    penup()
    goto(385,250)
    fillcolor(224, 161, 66)
    begin_fill()
    circle(30)
    end_fill()

Enfin, la fonction pour dessiner un oiseau simple en bâton : on a établit la couleur et l’épaisseur du trait, orienté la tortue avec la fonction setheading() à 290 pour qu’elle soit bien horizontale, puis fait une boucle qui trace un trait et qui tourne a gauche à deux reprises.

def oiseaux() :
    penup()
    pencolor(0, 0, 0)
    pensize(3)
    goto(395, 258)
    pendown()
    setheading(290)
    for i in range(2):
        left(50)
        forward(15)
       

Pour produire notre image finale, nous appelons toutes les fonctions (en ajoutant les coordonnées de certaines) :

#appel des fonctions        
fond(), sol1(), sol2(), sol3(), montagne1(), montagne2(), montagne3()  
cactus(-600,-150), cactus(500,-240)
cactus_petit(230, -100)
paille(100, -200), paille(-550, -300), paille(480, -330)
nuage(-480, 200), nuage(490, 180)
soleil()
oiseaux()

Résultat final

Télécharger en .py

Projets

La Patrouille de France

Pour ce premier projet de NSI, nous avons décider de prendre comme thème une image de la Patrouille de France, vous pourrez retrouver ici les démarches par lesquelles nous sommes passées.

Le Fond :

Tout d’abord pour obtenir notre image nous avons créer un fond dégradé bleu :

n = 350
s = (0, 0, 139)  
e = (173, 216, 230)  
w, h = 1280, 720


def degrade(st, end, step, t_step):
    return st + (end - st) * step / t_step

Pour obtenir ce résultat nous avons donc créer les paramètres de notre dégradé, il y en a 4 : le nombre de ligne que va faire la tortue (n) ; la couleur de départ (s) ; la couleur de fin (e) ; La longueur et la largeur (w, h) . Afin que la tortue change petit à petit de couleur, on créait la fonction degrade, qui va donc utiliser 3 paramètres : le nombre de ligne que va faire la tortue ; la couleur de départ ; la couleur de fin et effectuer une opération mathématique.’

for i in range(n):
    r=int(degrade(s[0], e[0], i, n))
    g=int(degrade(s[1], e[1], i, n))
    b=int(degrade(s[2], e[2], i, n))

    screen.colormode(255)
    pen.color(r, g, b)

Ici, on calcule la nuance de bleu qui va être utilisé à chaque ligne du dégradé.

    screen.colormode(255)
    pen.color(r, g, b)

screen.colormode(255) : Cette fonction définit le mode de couleur de l’écran sur une échelle de 0 à 255. Par défaut, Turtle utilise une échelle de couleur de 0 à 1 (où chaque couleur est une valeur décimale entre 0 et 1).

pen.color(r, g, b) : Cette fonction définit la couleur du stylo en utilisant trois valeurs pour le rouge (r), le vert (g), et le bleu (b). Ces valeurs doivent être comprises entre 0 et 255.

 pen.goto(-w/2, h/2 - i * (h / n))
    pen.begin_fill()
    for _ in range(2):
        pen.forward(w)
        pen.right(90)
        pen.forward(h / n)
        pen.right(90)
    pen.end_fill()

Ici, on délimite le rectangle dans lequel le dégradé doit être créer.

Les avions :

Ensuite nous avons créer une fonction avion qui créer nos avions :

def avion(x,y):
    pen.pu()
    pen.goto(x,y)
    pen.pd()
    pen.color("#9f9f9f")
    pen.begin_fill()
    pen.goto(x-7,y-30)
    pen.goto(x-10,y-60)
    pen.goto(x-80,y-160)
    pen.goto(x-10,y-160)
    pen.goto(x-10,y-175)
    pen.goto(x,y-175)
    pen.goto(x+10,y-175)
    pen.goto(x+10,y-160)
    pen.goto(x+80,y-160)
    pen.goto(x+10,y-60)
    pen.goto(x+7,y-30)
    pen.goto(x,y)
    pen.end_fill()

Tout d’abord, nous avons créé une fonction avion. Dans cette partie du code, nous dessinons la silhouette de l’avion à l’aide de goto(), nous lui donnons une couleur avec color(), puis nous la remplissons avec begin_fill() et end_fill().

	pen.pu()
    pen.goto(x-10,y-60)
    pen.pd()
    pen.color("#999999")
    pen.begin_fill()
    pen.goto(x-10,y-160)
    pen.goto(x-80,y-160)
    pen.goto(x-10,y-60)
    pen.end_fill()
    pen.pu()
    pen.goto(x+10,y-60)
    pen.pd()
    pen.begin_fill()
    pen.goto(x+10,y-160)
    pen.goto(x+80,y-160)
    pen.goto(x+10,y-60)
    pen.end_fill()

Ici, nous façonnons l’ombre sur les ailes en leur donnant une couleur plus sombre,

	pen.pu()
    pen.goto(x,y-20)
    pen.pd()
    pen.color("#606060")
    pen.begin_fill()
    pen.goto(x-5,y-40)
    pen.goto(x-5,y-50)
    pen.goto(x,y-70)
    pen.goto(x+5,y-50)
    pen.goto(x+5,y-40)
    pen.goto(x,y-20)
    pen.end_fill()

Cette partie nous permet de faire le cockpit,

    pen.pu()
    pen.goto(x-40,y-150)
    pen.pd()
    pen.color("red")
    pen.begin_fill()
    pen.circle(10)
    pen.end_fill()
    pen.pu()
    pen.goto(x-40,y-147)
    pen.pd()
    pen.color("#ffffff")
    pen.begin_fill()
    pen.circle(7)
    pen.end_fill()
    pen.pu()
    pen.goto(x-40,y-144)
    pen.pd()
    pen.color("blue")
    pen.begin_fill()
    pen.circle(4)
    pen.end_fill()
    pen.pu()
    pen.goto(x+40,y-150)
    pen.pd()
    pen.color("red")
    pen.begin_fill()
    pen.circle(10)
    pen.end_fill()
    pen.pu()
    pen.goto(x+40,y-147)
    pen.pd()
    pen.color("#ffffff")
    pen.begin_fill()
    pen.circle(7)
    pen.end_fill()
    pen.pu()
    pen.goto(x+40,y-144)
    pen.pd()
    pen.color("blue")
    pen.begin_fill()
    pen.circle(4)
    pen.end_fill()

Et pour finir, ce long script nous permet de faire les cocardes tricolores françaises.

Les traînés :

Afin d’avoir trois traîner au couleur de la France, nous avons créer trois fonction : traine_bleu ; traine_rouge ; traine_blanche.

def traine_bleu(x,y):

    pu()
    goto(x,y)
    pd()
    begin_fill()
    color("#00034e")
    goto(x-15,y-560)
    goto(x+15,y-560)
    goto(x,y)
    end_fill()
    pu()
def traine_blanc(x,y):

    pu()
    goto(x,y)
    pd()
    begin_fill()
    color("#ffffff")
    goto(x-15,y-560)
    goto(x+15,y-560)
    goto(x,y)
    end_fill()
    pu()
def traine_rouge(x,y):

    pu()
    goto(x,y)
    pd()
    begin_fill()
    color("#c30000")
    goto(x-15,y-560)
    goto(x+15,y-560)
    goto(x,y)
    end_fill()
    pu()

Pour créer les traîners, nous avons simplement créé une fonction de base où nous avons changé la couleur.

Les problèmes rencontrés :

Lorsque nous avons voulu générer nos avions avec les traînées à l’arrière nous avons obtenue l’image suivante :

Le problème venait du fait que nous avions dessiner les avions avant de dessiner les traînées. Donc les traînées sont apparues par dessus les avions.

Nos sources :

Afin de réaliser le code nous avons utiliser le site python.org, ainsi que nos connaissances. Nous avons aussi pris le temps de regarder les travaux des années précédant de la catégories art.

Image finale :

Voici le moment tant attendu l’image finale :

Télécharger notre script :

Projets

Perspective : Paris 2024

Dans le cadre de notre projet d’art génératif en Première NSI, nous avons décidé de concevoir un paysage en perspective qui représente Paris pendant les Jeux Olympiques de 2024. Notre objectif est de mêler des éléments architecturaux emblématiques de la ville avec l’ambiance olympique qui y règne.

Note : 4.5 sur 5.

Origine des JO

Cet été 2024 à Paris a eu lieu les JO. Les JO sont des événements sportifs internationaux majeurs, regroupant les sports d’été ou d’hiver, auxquels des milliers d’athlètes participent à travers différentes compétitions tous les quatre ans, pour chaque olympiade moderne.

Pour plus d’informations, nous vous conseillons cette vidéo explicative de l’origine des JO.

Le Projet

Revenons au projet. Nous avons choisi de créer une image des Champs Elysées pendant la période des JO 2024. Pour cela, nous utilisons les modules turtle et random. Le module turtle permet de dessiner l’image, tandis que le module random génère aléatoirement la taille et la position des étoiles dans le ciel. Nous avons également intégré un script pour exporter l’image générée par turtle en format .png, que vous pouvez retrouver ici.

Structure du script

Nous avons structuré le script en séparant chaque élément de l’image (fond dégradé, étoiles, route, trottoirs, arc de triomphe, anneaux olympiques, bâtiments, arbres) dans des fonctions distinctes. Ensuite, nous avons appelé ces fonctions dans un ordre spécifique, permettant ainsi à chaque élément de se superposer correctement dans son propre plan.

Analyse du script

Nous allons donc analyser notre script.

On commence d’abord par l’appel des modules utilisés et la mise en place turtle.

from turtle import *
from random import randint

# Vérification des modules importés
try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False

# Définir le titre de la fenêtre de turtle 
titre = "Perspective Paris 2024 - construite avec turtle"
title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")

colormode(255) # Permet l'utilisation de couleurs rgb
setup(1280, 720) # Définir la taille de la fenêtre en 720p 
speed(0) # La tortue va à la vitesse du lièvre
hideturtle() # La tortue active sa cape d'invisibilité

flash = True # False par défaut, on peut mettre True sinon, ou mieux 0x2A
if flash:
    wn = Screen()
    wn.tracer(0)

On utilise les modules turtle et random, en se concentrant uniquement sur la fonction randint de random. Le script inclut également une partie pour exporter une image générée par turtle. Cela permet de vérifier si l’utilisateur a installé le module PIL ; si ce n’est pas le cas, un message d’erreur s’affiche avec un lien pour l’installer, sans interrompre l’exécution du script. Ensuite, on définit le titre de la fenêtre qui affichera le rendu ainsi que sa taille. On configure également le type de couleurs utilisées (R,G,B), la vitesse de la tortue et on cache la tortue pour une présentation plus esthétique.

Puis, voici notre première fonction : le fond dégradé sur la partie haute de l’image.

def fond():
    red, green, blue = 0, 0, 100
    penup()
    hauteur = 0
    penup(), goto(-641, hauteur)
    while hauteur != 360:
        pendown()
        pencolor(round(red), round(green), round(blue))
        forward(1280)
        hauteur += 1
        goto(-640, hauteur)
        blue = blue - float(100 / 360)

Pour le fond, nous avons donc choisi d’utiliser un dégradé. Le script fait avancer la tortue sur une ligne d’un pixel de large et à la fin de chaque ligne, la tortue est envoyée à la ligne suivante grâce à un goto. À chaque déplacement, on ajuste progressivement les valeurs des couleurs, de façon arrondie (dans notre cas, on ajuste seulement la valeur du bleu) en fonction de la différence entre la couleur de début et celle de fin du dégradé.

Ensuite, vient la deuxième fonction, celle des étoiles dans le ciel.

def etoiles (x_max1, x_max2, y_max1, y_max2, r_max1, r_max2, nb_etoiles):
    for i in range(nb_etoiles):
        x, y, r = randint(x_max1,x_max2), randint(y_max1,y_max2), randint(r_max1,r_max2)
        pencolor("#FFFFFF"), begin_fill()
        penup(), goto(x, y), pendown()
        circle (r)
        fillcolor("#FFFFFF"), end_fill()

Pour les étoiles, leur position dans le ciel et leur taille, variant entre 1 et 3 pixels de rayon, sont déterminées aléatoirement avec la fonction randint du module random. Ensuite, un cercle est tracé à chaque position générée avec la taille correspondante. Ce processus est répété 100 fois dans une boucle for i in range, afin de créer 100 étoiles au total.

Vient ensuite la fonction pour dessiner la route et les trottoirs (le script suivant n’est qu’une partie du code complet, long et répétitif, il n’est donc pas nécessaire de commenter la suite).

def base_route(xi, yi, xf, yf, col_route, larg_debut_route, larg_fin_route):
    penup(), goto(xi, yi), pendown()
    pencolor(col_route)
    begin_fill(), fillcolor(col_route)
    goto(xi - (1 / 2 * larg_debut_route), yi), goto(xi + (1 / 2 * larg_debut_route), yi), goto(xf + (1 / 2 * larg_fin_route), yf)
    goto(xf - (1 / 2 * larg_fin_route), yf), goto(xi - (1 / 2 * larg_debut_route), yi)
    end_fill()
    
def ligne_entre_routes(xi, yi, xf, yf, col_lignes):
    penup(), goto(xi, yi), pendown()
    left(90)
    size = 20
    for i in range (357):
        pensize(round(size))
        size = size - float(15 / 360)
        pencolor(col_lignes)
        forward(1)
        
def marquage_gauche(xi, yi, xf, yf, col_lignes, long_marquages, larg_debut_route):
    longueur = 360
    penup(), goto(xi - 1 / 4 * larg_debut_route, yi), pendown()
    pensize(7), pencolor(col_lignes)
    right(40)
    k = 0
    while k * long_marquages < longueur - long_marquages:
        k += 2
        pendown(), forward(long_marquages), penup(), forward(long_marquages)

def trottoir_droite(xi, yi, xf, yf, col_trottoir, larg_debut_route, larg_fin_route, larg_debut_trot, larg_fin_trot):
    penup(), goto(xi + (1 / 2 * larg_debut_route), yi), pendown()
    pencolor(col_trottoir)
    pensize(2)
    begin_fill(), fillcolor(col_trottoir)
    goto(xi + (1 / 2 * larg_debut_route) + (1 / 2 * larg_debut_trot), yi), goto(xf + (1 / 2 * larg_fin_route) + (1 / 2 * larg_fin_trot), yf)
    goto(xf + (1 / 2 * larg_fin_route), yf), goto(xi + (1 / 2 * larg_debut_route), yi)
    end_fill()
    penup(), goto(xi + (1 / 2 * larg_debut_route) + 20, yi), pendown()
    pensize(3), pencolor("#6C757D")
    begin_fill(), fillcolor("#6C757D")
    goto(xf + (1 / 2 * larg_fin_route) + 7.5, yf), goto(xf + (1 / 2 * larg_fin_route), yf)
    goto(xi + (1 / 2 * larg_debut_route), yi), goto(xi + (1 / 2 * larg_debut_route) + 20, yi)
    end_fill()

def route_et_trottoir(xi, yi, xf, yf, col_route, col_trottoir, col_lignes, col_pavage, long_marquages, larg_debut_route,
larg_fin_route, larg_debut_trot, larg_fin_trot):
    base_route(xi, yi, xf, yf, col_route, larg_debut_route, larg_fin_route)
    ligne_entre_routes(xi, yi, xf, yf, col_lignes)
    marquage_droit(xi, yi, xf, yf, col_lignes, long_marquages, larg_debut_route)
    marquage_gauche(xi, yi, xf, yf, col_lignes, long_marquages, larg_debut_route)
    trottoir_droite(xi, yi, xf, yf, col_trottoir, larg_debut_route, larg_fin_route, larg_debut_trot, larg_fin_trot)
    trottoir_gauche(xi, yi, xf, yf, col_trottoir, larg_debut_route, larg_fin_route, larg_debut_trot, larg_fin_trot)

Pour la route et les trottoirs, nous commençons par tracer la base de la route en perspective en utilisant la fonction goto, puis nous ajoutons les marquages au sol. La ligne centrale entre les deux voies est progressivement affinée pour renforcer l’effet de perspective. Ensuite, les trottoirs de chaque côté sont tracés avec goto, en appliquant les mêmes proportions pour respecter la perspective. Enfin, une fonction finale regroupe toutes les fonctions constituant notre route et nos trottoirs.

Nous poursuivrons ensuite avec le codage de l’Arc de Triomphe (le script est encore long, il ne sera donc pas intégral ici).

def pilier_gauche(x, y, larg, long, col):
    pencolor(col)
    begin_fill(), fillcolor(col)
    penup(), goto(x - larg,y), pendown()
    right(70)
    for i in range(2):
        forward(larg), left(90), forward(long - 40), left(90)
    end_fill()
    
def atique_arc_de_triomphe(x, y, larg, long, col):
    pencolor(col)
    penup(), goto(x + larg, y + long - 40), left(90), pendown()
    begin_fill()
    circle((1 / 2 * larg), 180)
    for i in range(2):
        right(90), forward(larg)
    right(90), forward(3 / 2 * (long))
    for i in range(2):
        right(90), forward(larg)
    fillcolor(col), end_fill()
    
def rajout_atique(x, y, larg, long, col):
    pencolor(col)
    penup(), goto(x + (long), y + ((long - 40) + larg)), pendown()
    begin_fill(), fillcolor(col)
    right(90)
    for i in range(2):
        forward(larg - (1 / 2 * larg)), left(90), forward((long) + larg), left(90)
    end_fill()

def details_arc_de_triomphe(x, y, larg, long, col_detail):
    penup(), goto(x + (long), y + (long - 40 + larg)), pendown()
    pensize(5), pencolor(col_detail)
    left(90), forward(long + larg)

def arc_de_triomphe(x, y, larg, long, col):
    pilier_gauche(x, y, larg, long, col)
    pilier_droite(x, y, larg, long, col)
    atique_arc_de_triomphe(x, y, larg, long, col)
    rajout_atique(x, y, larg, long, col)
    details_arc_de_triomphe(x, y, larg, long, "#9C7F6E")

Pour l’Arc de Triomphe, nous avons choisi de le coder étape par étape : d’abord les piliers, puis l’attique, et enfin les détails. Les piliers sont représentés par de simples rectangles colorés, en utilisant les commandes begin_fill, fillcolor, et end_fill. Pour l’attique, nous avons dessiné un arc de cercle avec circle(rayon, 180) pour représenter la courbure. Enfin, toutes les fonctions constituant l’Arc de Triomphe sont appelées dans une fonction unique pour générer l’ensemble du monument.

Passons maintenant au code pour générer les anneaux olympiques.

list_col_anneau = ["#0D79FF", "#FFD900", "#000000", "#12C52D", "#FF0F0F"]

def anneau_haut(x,col,rayon,size):
    penup(), forward(x), pendown()
    pencolor(col), pensize(size), circle(rayon)
 
def anneau_bas(x,col,rayon,size):
    penup(), left(90), forward(x), pendown()
    pencolor(col), pensize(size), circle(rayon)

def anneaux(xf,yf,rayon,size):
    penup(), goto(xf,yf), pendown()
    anneau_haut(0,list_col_anneau[0],rayon,size)
    anneau_haut(2 * rayon + (size + 5),list_col_anneau[2],rayon,size)
    anneau_haut(2 * rayon + (size + 5),list_col_anneau[4],rayon,size)
    penup(), goto(xf - rayon - (1 / 5 * rayon), yf - rayon), right(90), pendown()
    anneau_bas(0,list_col_anneau[1],rayon,size)
    right(90)
    anneau_bas(2 * rayon + (size + 5),list_col_anneau[3],rayon,size)

Nous avons commencé par définir une liste des couleurs pour chaque anneau. Ensuite, les anneaux de la rangée supérieure ont été dessinés, suivis de ceux de la rangée inférieure, en utilisant la fonction circle. Enfin, nous avons regroupé le tout dans une fonction unique qui positionne les anneaux correctement.

Nous poursuivrons ensuite avec le script dédié à la lune et à ses cratères (le code des cratères étant répétitif, il ne sera pas présenté dans sa totalité).

def cratere1 (x, y, rayon_lune, col):
    x_crat1 = x
    y_crat1 = y + rayon_lune + (1 / 4 * rayon_lune)
    taille_crat1 = 1 / 3 * rayon_lune
    penup(), goto(x,y), goto(x_crat1,y_crat1), pendown()
    begin_fill(), pencolor(col)
    circle(taille_crat1)
    fillcolor(col), end_fill()

def crateres(x, y, rayon_lune, col):
    cratere1 (x, y, rayon_lune, col)
    cratere2 (x, y, rayon_lune, col)
    cratere3 (x, y, rayon_lune, col)
    cratere4 (x, y, rayon_lune, col)
    cratere5 (x, y, rayon_lune, col)

def lune(x, y, rayon_lune, col_lune):
    left(180)
    begin_fill()
    penup(), goto(x,y), pendown()
    pencolor(col_lune), circle(rayon_lune), fillcolor(col_lune), end_fill()
    crateres(x, y, rayon_lune, "#DEDCDA")

A propos de la lune et de ses cratères, premièrement, chaque fonction (cratere1 à cratere5) dessine un cratère à des positions spécifiques autour de la lune, en utilisant le rayon de la lune pour ajuster la taille et la position. Deuxièmement, la fonction crateres regroupe tous les cratères en une seule fonction. Et au final, la fonction lune dessine la lune en tant que cercle rempli, puis appelle la fonction crateres pour ajouter les cratères à la surface de la lune.

Nous allons maintenant aborder le codage des bâtiments.

def bat_droite(xi, yi, xf, yf, col, col_trace, hauteur):
    pencolor(col_trace), pensize(3)
    begin_fill(), fillcolor(col)
    penup(), goto(xi, yi), pendown()
    goto(xf, yf), goto(xf, hauteur), goto(1282, hauteur), goto(xi, yi)
    end_fill()
    penup(), goto(xf, hauteur), pendown()
    right(15), forward(500)

def bat_gauche(xi, yi, xf, yf, col, col_trace, hauteur):
    pencolor(col_trace), pensize(3)
    begin_fill(), fillcolor(col)
    penup(), goto(xi, yi), pendown()
    goto(xf, yf), goto(xf, hauteur), goto(-1282, hauteur), goto(xi, yi)
    end_fill()
    penup(), goto(xf, hauteur), pendown()
    left(210), forward(500)

Pour les bâtiments, les fonctions dessinent des structures à droite et à gauche, en utilisant des coordonnées spécifiées, une couleur de remplissage, une couleur de contour et une hauteur. Chaque fonction remplit le bâtiment et trace un toit incliné, créant ainsi un effet de perspective qui enrichit visuellement l’image.

Nous allons maintenant découvrir le script qui permet de dessiner des arbres le long des trottoirs.

def tronc(x, y, larg_tronc, col_tronc, long_tronc):
    begin_fill()
    penup(), goto(x,y), pendown()
    pencolor(col_tronc)
    for i in range(2):
        forward(larg_tronc), left(90), forward(long_tronc), left(90)
    fillcolor(col_tronc), end_fill()
  
def feuilles(x, y, col_feuilles, ray_feuilles, larg_tronc, long_tronc, col_tronc):
    begin_fill()
    penup(), goto(x + (1 / 2 * larg_tronc),y + long_tronc), pendown()
    pencolor(col_feuilles)
    for i in range(5):
        begin_fill()
        circle(ray_feuilles), left(72), forward(10)
        fillcolor(col_feuilles), end_fill()

def arbre(x, y, col_feuilles, ray_feuilles, larg_tronc, long_tronc, col_tronc):
    tronc(x, y, larg_tronc, col_tronc, long_tronc)
    feuilles(x, y, col_feuilles, ray_feuilles, larg_tronc, long_tronc, col_tronc)

# On place les arbres sur le trottoir
def arbres():
    x = -275
    y = -25
    ray_feuilles = 20
    larg_tronc = 22
    long_tronc = 80
    right(195)
    for i in range(14):
        arbre(x, y, "#009B1A", ray_feuilles, larg_tronc, long_tronc, "#7F2C00")
        x -= 25
        y -= 25
        ray_feuilles += float(2.5)
        larg_tronc += float(2.5)
        long_tronc += 10
    x = 258
    y = -25
    ray_feuilles = 20
    larg_tronc = 22
    long_tronc = 80
    for i in range(14):
        arbre(x, y, "#009B1A", ray_feuilles, larg_tronc, long_tronc, "#7F2C00")
        x += 22
        y -= 25
        ray_feuilles += float(2.5)
        larg_tronc += float(2.5)
        long_tronc += 10

Concernant les arbres, tout d’abord, la fonction tronc dessine le tronc d’un arbre en utilisant des coordonnées spécifiques, une largeur, une couleur et une longueur. Elle utilise une boucle pour créer un rectangle rempli représentant le tronc. Après, la fonction feuille dessine les feuilles de l’arbre. Elle positionne le curseur au-dessus du tronc et utilise une boucle pour créer plusieurs cercles qui représentent les feuilles, disposés en étoile autour de la partie supérieure du tronc. Suite à quoi la fonction arbre combine les fonctions tronc et feuilles pour dessiner un arbre complet à des coordonnées données. Pour couronner le tout, la fonction arbres place plusieurs arbres le long des trottoirs. Elle commence à des coordonnées spécifiques et utilise une boucle pour dessiner 14 arbres de chaque côté. La position, la taille des feuilles, la largeur et la longueur du tronc augmentent progressivement pour créer un effet de perspective, tandis que les arbres se déplacent vers le bas et de manière symétrique des deux côtés.

Enfin, nous appelons chaque fonction dans un ordre spécifique pour produire l’image finale.

# Appel de toutes les fonctions
fond()
etoiles(-640, 640, 0, 360, 1, 3, 100)
route_et_trottoir(0, -360, 0, 0, "#424345", "#ADB5BD", "#CECDC9", "#6C757D", 30, 800, 300, 1000, 375)
arc_de_triomphe(-50, 0, 100, 200, "#D4C4B0")
anneaux(70,300,30,7)
lune(250, 200, 50, "#F4F1ED")
bat_droite(900, -360, 337.5, 0, "#eae2b7", "#d4a373", 250)
bat_gauche(-900, -360, -337.5, 0, "#eae2b7", "#d4a373", 250)
arbres()

Et pour exporter l’image finale en .png il y a la suite du script pour exporter une image générée par turtle en .png utilisé au début du script.

if flash:
    wn.update() 

# Enregistrement de l'image finale
image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')
try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    
 
# Vérification des modules importés
except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")

exitonclick()

Le script va donc générer une image en .ps et la convertir en .png avec un nom généré aléatoirement.

Image finale

Télécharger le .py

Art

La culture Espagnole

Nous avons choisi le thème de l’Espagne car c’est une une de mes origines, c’est donc un thème qui me tient à cœur. À travers ce titre et ce thème, nous voulons montrer un petit bout de la culture espagnole, c’est pour cela que nous avons choisi la Porte d’Alcala située à Madrid et Alhambra située à Grenade.

Les 2 monuments

La porte d’Alcala est située à Madrid et l’une des 5 anciennes portes qui donnaient accès à la ville. Elle a été construite entre 1769-1778.

L’Alhambra est un ensemble fortifié situé à Grenade, en Andalousie. Cet ensemble a été construit par les Arabes, puis agrandit par la suite par Charles Quint

Le Fond

Nous avons d’abord décidé de créer un fond bleu ciel, puis l’image est coupée en deux par la fonction ligne ci-dessous :

def ligne(ax,ay,bx,by,color_choice) :
color(color_choice)
penup()
goto(ax,ay)
pendown()
goto(bx,by)
penup()

Nous choisissons donc des coordonnées de départ et d’arrivée. Le choix de mettre « color_choice » sera vu plus tard dans l’article.

Ensuite, la création d’une fonction herbe a été nécessaire, puis pour les nuages nous avons donc créé la fonction nuage ci-dessous :

def nuage(x, y):
    penup()
    goto(x,y)
    pendown
    color("white")
    for i in range(3):
        begin_fill()
        circle(20)
        end_fill()
        penup()
        forward(30)
        pendown()

La boucle permet la création de 3 cercles côte à côte, ce qui nous permettra de faire le nuage. Pour des raisons d’esthétiques… nous préférons choisir leur emplacement manuellement qu’à l’aide du module ramdom. Ce la nous donne le résultat suivant :

Les fonctions principales

Outres la fonction ligne deux autres fonctions sont importantes :

  • La fonction colonnes nous permets de créer les colonnes de la taille et de la largeur que l’on veut dans les deux monuments :
def colonne(x, y, hauteur, largeur):
    penup()  
    goto(x, y)  
    pendown()  
    color("#9E9FA5")  
    begin_fill()
    for _ in range(2):
        forward(largeur)  
        right(90)  
        forward(hauteur)  
        right(90)  
    end_fill()

La boucle permet la création d’un rectangle qui représente les colonnes

  • Nous avons ensuite créé une fonction arche qui va aussi servir dans les deux monuments. Une fonction plutôt simple à faire…
def arche(x,y,r):
    pensize(15)
    penup()
    goto(x, y)
    pendown()
    color('#9E9FA5')
    setheading(90)
    circle(r,180)
    setheading(90)

Et évidemment tout est saisi manuellement après quelques calculs, bien entendu. Toutes ces fonctions nous perment de créer les monuments.

Fonction Madrid

La fonction Madrid nous crée le premier monument qui est la porte d’Acala, nous n’allons pas nous attarder sur toute la fonction car elle est très longue, nous allons nous attarder sur l’important.

La 1ère phase a été de créer un bâtiment gris comme celui qui suit :

Voici comment nous avons eu le résultat :

  • D’abord, nous avons utilisé la fonction herbe montait et grâce à une indentation, l’herbe montait de plus en plus, jusqu’à ce que la boucle soie finie
  • Ensuite la fonction colonne rentre en jeu, mais il y a une petite particularité
    colonne(70, -10, 254, 29)
    penup()
    pendown()
    colonne(150, -75, 190, 29)
    penup()
    pendown()
    colonne(250, -75, 190, 29)
    penup()
    pendown()
    colonne(350, -75, 190, 29)
    penup()
    pendown()
    colonne(450, -75, 190, 29)

La particularité, comme vous devez le voir, c’est que la 1ère colonne et la dernière colonne sont plus grandes que les 3 milieux. Ce choix s’explique par le fait que la définition ligne finit par des côtés ronds, les colonnes à l’extrémité donnent donc une forme plus géométrique à notre monument.

  • Ensuite, la fonction arche est utilisée pour les 3 portes du milieu. En effet, celles sur le côté sont plus petites et rectangulaires, c’est pour cela que la fonction ligne va être réutilisée.
  • Pour finir la Première phase et commencer la deuxième, nous avons utilisé la fonctions ligne, et c’est là qu’intervient le choix de mettre « color_choice » cela à pour but faire un petit contraste pour refaire un petit peu les détails du monument.
ya = -79
    yb = -79
    pensize(13)
    for i in range(10) :
        ligne(97, ya, 152, yb, "#9E9FA5")
        ya -= 7
        yb -= 7
    for i in range(5) :
        ligne(256, ya,344, yb, "#B4B4B8")
        ya += 5
        yb += 5
    pensize(5)

Tout d’abord, comme nous le voyons, la couleur va soit être dans un 1er cas gris foncé ou soit gros clair. Ensuite, pour faire les bonnes dimensions on adaptait toujours les coordonnées, les indentations soit += soit -= et la répétition et la taille du stylo.

  • Enfin, n’ayant pas trouvé comment un triangle, nous avons utilisé Thalès et Pythagore, puis la commande goto pour faire le triangle tout en haut.

La fonction Madrid nous donnes donc le résultat suivant :

Avec 1 couleur :

Avec 2 couleurs :

La fonction étant longue, vous pourrez la retrouver dans le document ci-joint.

Fonction Grenade

Après avoir fait la fonction Madrid, on a crée grâce à la fonction Grenade un bâtiment de l’Alhambra. Comme avant nous allons nous attarder sur le plus important.

La 1ère phase a été de créer le contours du bâtiment de couleur tan comme celui ci-dessous :

Pour ça, nous avons d’abord avons utilisé :

  • la fonction colonne et la fonction arche qui nous aide à faire la base du bâtiment. L’utilisation des fonction est pareil que dans la fonction Madrid.
    color("#D2B48C")
    colonne(-105, -285, 20, 165)
    penup()
    pendown()
    colonne(-195, -285, 20, 165)
    penup()
    pendown()
    colonne(-290, -285, 20, 165)
    penup()
    pendown()
    colonne(-387, -285, 20, 165)
    penup()
    pendown()
    colonne(-480, -285, 20, 165)
    penup()
    pendown()
    colonne(-570, -285, 20, 165)
    arche(-100,-154,42, "#D2B48C")
    arche(-190,-154,42, "#D2B48C")
    arche(-287,-154,42, "#D2B48C")
    arche(-383,-154,42, "#D2B48C")

Ici vous voyez qu’entre les deux fonctions, celle de Madrid et celle Grenade on a rajouté color_choice comme pour la fonction lignes car on avait besoin de changer de couleur entre les deux bâtiments.

  • Ensuite, c’est le grand retour de la fonction ligne, et celle là, a encore beaucoup servi. Car pour la première phase elle à servir à faire le début du contours du bâtiment. Son utilisation est toujours la même :
ligne(-565,-145,-565,44,"#D2B48C")
  • Dans la deuxième phase, on a fini les contours du bâtiment et on à remplit tout avec des indentations. Cela nous donne donc ce rendu :
  • Ici on a encore utilisé beaucoup d’indentation et de boules, notamment de indentation += ou +-:
for i in range(13):
        ligne(-415, ya, -235, yb, "#D2B48C")
        ya += 7
        yb += 7
for i in range(2):
        if i==1:
            ya=44
            yb=44
            for i in range(4) :
                ligne(-565, ya, -481, yb, "#E3D9B6")#Arrivé e départ a améliorer
                ya -= 7
                yb -= 7
        else :
            ya=44
            yb=44
            for i in range(4) :
                ligne(-90, ya, -174, yb, "#E3D9B6")#Arrivé e départ a améliorer
                ya -= 7
                yb -= 7
  • Enfin on utilise une nouvelle fonction qui s’appelle la fonction rempart, cette fonction nous permet de créer les remparts du monument. Son script est le suivant, elle est répété 5 fois dans a fonction Grenade.
def remparts(n) :
    right(90)
    i = 0
    for i in range(n):
        left(90)
        forward(20)
        right(90)
        forward(20)
        right(90)
        forward(20)
        left(90)
        i +=1
        if i < 5 :
            forward(20)

Cette fonction nous donnes le rendu final qui ressemble à ça :

Conclusion

Pour finir, j’espère que cette article vous on aura appris plus sur le codage python. Le fichier est joint à l’article si vous voulez le voir en detail.

N’hésitez pas à aller visiter l’Espagne et notamment c’est deux monument, ils sont plus jolis dans la vrai qu’en code python…

Projets

Le code des supporters : virage Auteuil.

En se basant sur une photo du magnifique virage Auteuil, emblématique du Parc des Princes, stade du Paris-Saint-Germain, nous avons reproduit sous un angle de vue différent cette image. Cette reproduction met en avant la disposition du stade, du virage, mais surtout les couleurs emblématiques de ce club. Notre image possède une perspective appuyant bien sur les aspects clés de l’image cités auparavant.

Pour le fond, nous avons appelé deux fonctions rectangle chacune ayant la même hauteur et la même largeur pour respecter les proportionnalités et les avons choisies rouge et bleu en référence aux couleurs du club.

rectangle modifiable

# rectangle modifiable
def rectangle(x,y,z,g,a,b):
  def longueur(a):
    a == 0 + a
    forward(a)
  def largeur(b):
    b == 0 + b
    forward(b)
  pensize(z)
  speed(100)
  # Remplissage selon la couleur donnée
  penup()
  begin_fill()
  color(g)
  goto (x,y), pendown(),
  for i in range(2):
      longueur(a), right(90), largeur(b), right (90)
  end_fill()
  penup()  

rectangle(-858,538,1,"red",858,1076)
rectangle(858,538,1,"blue",-858,1076)

Pour commencer à dessiner une perspective, nous avons réalisé une pelouse composée de formes géométriques différentes en prenant pour exemple notre image référence. Les teintes sont différentes en fonction des zones sur la pelouse pour réaliser les sens de tonte et se rapprocher ainsi au maximum d’un vrai stade.

Pelouse

## Formation en perspective de la pelouse
# Triangles
def triangle(a,b,x,y,c,d,e,f):
    begin_fill()
    pensize(a)
    color(b)
    penup(), goto(x,y), pendown(), goto(c,d), goto(e,f), goto(x,y), penup()
    end_fill()

def polygone_1(a,b,x,y,c,d,e,f,g,h):
    begin_fill()
    pensize(a)
    color(b)
    penup(), goto(x,y), pendown(), goto(c,d), goto(e,f), goto(g,h), goto(x,y), penup()
    end_fill()

def polygone_2(a,b,x,y,c,d,e,f,g,h,i,j):
    begin_fill()
    pensize(a)
    color(b)
    penup(), goto(x,y), pendown(), goto(c,d), goto(e,f), goto(g,h), goto(i,j), goto(x,y), penup()
    end_fill()

# Formes pelouse verte différentes
rectangle(-858,-414,1,"green",1716,124)
polygone_1(1,"green",-820,-414,-750,-414,-858,-474,-858,-424)
polygone_2(1,"darkgreen",-750,-414,-660,-414,-820,-538,-858,-538,-858,-474)
polygone_1(1,"darkgreen",-660,-414,-550,-414,-680,-538,-820,-538)
polygone_1(1,"darkgreen",-300,-414,0,-414,0,-538,-330,-538)
polygone_1(1,"darkgreen",300,-414,550,-414,670,-538,330,-538)
triangle(1,"darkgreen",750,-414,858,-414,858,-474)

Toujours en appelant la fonction rectangle utilisée au tout début, nous avons réalisé un panneau publicitaire de couleur grise, comme on le voit dans les stades.

Panneau publicitaire

rectangle(-858,-377,1,"grey",1716,37)

Pour commencer la perspective des gradins, nous avons tracé des courbes horizontales qui descendent en se rapprochant du centre.

Perspective des tribunes avec traits horizontaux gris

penup(), goto(-858,40), pendown()
 
penup(), goto(-858,130), pendown()
def trait_coupe():
    for x in range(-858,864):
       y = -90+(x / 300) ** 4
       goto(x,y)
       pendown()        
trait_coupe()

penup(), goto(-858,190), pendown()
def trait_coupe1():
    for x in range(-858,864):
       y = -30+(x / 300) ** 4
       goto(x,y)
       pendown()        
trait_coupe1()

penup(), goto(-858,250), pendown()
def trait_coupe2():
    for x in range(-858,864):
       y = 30+(x / 300) ** 4
       goto(x,y)
       pendown()        
trait_coupe2()

penup(), goto(-858,310), pendown()    
def trait_coupe3():
    for x in range(-858,864):
        y = 90+(x / 300) ** 4
        goto(x,y)
        pendown()        
trait_coupe3()

penup(), goto(-858,370), pendown()    
def trait_coupe4():
    for x in range(-858,864):
        y = 150+(x / 300) ** 4
        goto(x,y)
        pendown()        
trait_coupe4()

penup(), goto(-858,430), pendown()    
def trait_coupe5():
    for x in range(-858,864):
        y = 210+(x / 300) ** 4
        goto(x,y)
        pendown()        
trait_coupe5()

penup(), goto(-858,490), pendown()    
def trait_coupe6():
    for x in range(-858,864):
        y = 270+(x / 300) ** 4
        goto(x,y)
        pendown()        
trait_coupe6()

penup(), goto(-858,550), pendown()    
def trait_coupe7():
    for x in range(-858,864):
        y = 330+(x / 300) ** 4
        goto(x,y)
        pendown()        
trait_coupe7()

penup(), goto(-858,70), pendown()
def trait_coupe11():
    for x in range(-858,864):
       y = -150+(x / 300) ** 4
       goto(x,y)
       pendown()        
trait_coupe11()

penup(), goto(-858,10), pendown()
def trait_coupe12():
    for x in range(-858,864):
       y = -210+(x / 300) ** 4
       goto(x,y)
       pendown()        
trait_coupe12()

# Zone grise au dessus des gradins
def zone_grise():
    pensize(1)
    color("grey")
    penup(), goto(-858,438), begin_fill(), pendown(), trait_coupe7(), goto(858,476), goto(-858,476), goto(-858,438), end_fill(), penup()
zone_grise()

# Zone grise en bas des gradins
def zone_grise_1():
    pensize(1)
    color("grey")
    penup(), goto(-858,10), begin_fill(), pendown(), trait_coupe12(), goto(858,-377), goto(-858,-377), goto(-858,10), end_fill(), penup()
zone_grise_1()

Pour approfondir cette perspective, nous avons décidé de compléter la zone sous la banderole et au dessus de l’herbe avec du gris foncé.

Remplissage avec du gris foncé

# Zone grise au dessus des gradins
def zone_grise():
    pensize(1)
    color("grey")
    penup(), goto(-858,438), begin_fill(), pendown(), trait_coupe7(), goto(858,476), goto(-858,476), goto(-858,438), end_fill(), penup()
zone_grise()

# Zone grise en bas des gradins
def zone_grise_1():
    pensize(1)
    color("grey")
    penup(), goto(-858,10), begin_fill(), pendown(), trait_coupe12(), goto(858,-377), goto(-858,-377), goto(-858,10), end_fill(), penup()
zone_grise_1()

Pour donner une impression de hauteur en plus de la perspective dans la largeur, nous avons dessiné des traits verticaux qui font se rétrécir les cases au fur et à mesure que l’on se déplace sur les côtés de l’image.

Ajout des traits verticaux

# Traits de coupe verticaux
def trait_de_coupe_vertical(x,y,a,b):
    pensize(3)
    color("darkgrey")
    penup(), goto(x,y), pendown(), goto(a,b)
    
trait_de_coupe_vertical(0,329,0,-208)
trait_de_coupe_vertical(-80,329,-100,-208)
trait_de_coupe_vertical(80,329,100,-208)
trait_de_coupe_vertical(155,329,200,-208)
trait_de_coupe_vertical(-155,329,-200,-208)
trait_de_coupe_vertical(-225,330,-300,-207)
trait_de_coupe_vertical(225,330,300,-207)
trait_de_coupe_vertical(295,330,400,-206)
trait_de_coupe_vertical(-295,330,-400,-206)
trait_de_coupe_vertical(385,333,500,-202)
trait_de_coupe_vertical(-385,333,-500,-202)
trait_de_coupe_vertical(455,335,600,-194)
trait_de_coupe_vertical(-455,335,-600,-194)
trait_de_coupe_vertical(525,339,700,-179)
trait_de_coupe_vertical(-525,339,-700,-179)
trait_de_coupe_vertical(595,345,800,-159)
trait_de_coupe_vertical(-595,345,-800,-159)
trait_de_coupe_vertical(-665,355,-900,-185)
trait_de_coupe_vertical(665,355,900,-185)
trait_de_coupe_vertical(735,368,1000,-185)
trait_de_coupe_vertical(-735,368,-1000,-185)
trait_de_coupe_vertical(795,381,1100,-185)
trait_de_coupe_vertical(-795,381,-1100,-185)

Pour la cage, nous avons réalisé une fonction cage contenant une fonction pour les filets, une pour les montants et une pour les poteaux à côté. Tous sont reliés par des traits de contour blancs qui donnent cette impression de perspective. Un trait de contour noir se trouve en bas pour séparer la pelouse du reste.

Formation de la cage et des contours

def cage():
# Formation du cadre
	def cadre():
		pensize(5)
		penup(),color("white")
		goto(-429,-411)
		pendown()
		goto(-429,-200), right(90), goto(429,-200), right(90), goto(429,-411)
		penup()
	cadre()
# Formation du filet
	def filet():
		def traits_verticaux():
			color("white")
			pensize(1)
			penup(), goto(-395,-411), pendown(), goto(-395,-221), penup(), goto(-360,-411), pendown(), goto(-360,-221), penup(), goto(-326,-411), pendown(), goto(-326,-221), penup(), goto(-291,-411), pendown(), goto(-291,-221), penup(), goto(-257,-411), pendown(), goto(-257,-221), penup(), goto(-223,-411), pendown(), goto(-223,-221), penup(), goto(-189,-411), pendown(), goto(-189,-221), penup(), goto(-154,-411), pendown(), goto(-154,-221), penup(), goto(-120,-411), pendown(), goto(-120,-221), penup(), goto(-86,-411), pendown(), goto(-86,-221), penup(), goto(-52,-411), pendown(), goto(-52,-221), penup(), goto(-17,-413), pendown(), goto(-17,-221), penup(), goto(17,-411), pendown(), goto(17,-221), penup(), goto(51,-411), pendown(), goto(51,-221), penup(), goto(85,-411), pendown(), goto(85,-221), penup(), goto(120,-411), pendown(), goto(120,-221), penup(), goto(154,-411), pendown(), goto(154,-221), penup(), goto(188,-411), pendown(), goto(188,-221), penup(), goto(224,-411), pendown(), goto(224,-221), penup(), goto(259,-411), pendown(), goto(259,-221), penup(), goto(293,-411), pendown(), goto(293,-221), penup(), goto(327,-411), pendown(), goto(327,-221), penup(), goto(361,-411), pendown(), goto(361,-221), penup(), goto(395,-411), pendown(), goto(395,-221)
		traits_verticaux()
		def traits_horizontaux():
			color("white")
			pensize(1)
			penup(), goto(-405,-390), pendown(), goto(405,-390), penup(), goto(-405,-369), pendown(), goto(405,-369), penup(), goto(-405,-348), pendown(), goto(405,-348), penup(), goto(-405,-327), pendown(), goto(405,-327), penup(), goto(-405,-305), pendown(), goto(405,-305), penup(), goto(-405,-284), pendown(), goto(405,-284), penup(), goto(-405,-263), pendown(), goto(405,-263), penup(), goto(-405,-242), pendown(), goto(405,-242), penup(), goto(-405,-221), pendown(), goto(405,-221), penup()    
        traits_horizontaux()
	filet()
# Formation des poteaux
	def poteaux():
    	pensize(3)
    	color("black")
    	def poteau_1():
        	penup(), goto(-490,-411), pendown(), goto(-490,-170), penup()
    	poteau_1()
    	def poteau_2():
        	penup(), goto(490,-411), pendown(), goto(490,-170), penup()
    	poteau_2()
	poteaux()
	def traits_poteaux_cages():
    	def trait_poteau_cages_1():
        	pensize(2)
        	color("white")
        	penup(), goto(-490,-170), pendown(), goto(-429,-200), penup()
    	trait_poteau_cages_1()
    	def trait_poteau_cages_2():
        	pensize(2)
        	color("white")
        	penup(), goto(490,-170), pendown(), goto(429,-200), penup()
    	trait_poteau_cages_2()
	traits_poteaux_cages()
cage()

def trait_contour(a,z,x,y,b,c):
	pensize(a)
	color(z)
	penup(), goto(x,y), pendown(), goto(b,c)

trait_contour(2,"black",-858,-414,858,-414)
trait_contour(2,"white",-429,-200,-405,-221)
trait_contour(2,"white",429,-200,405,-221)
trait_contour(2,"white",-405,-221,-405,-411)
trait_contour(2,"white",405,-221,405,-411)

Pour former la banderole bleu foncée, nous avons fait appel à la fonction rectangle et pour tracer les lettres, nous avons utilisé des rectangles, des cercles et une fonction trapèze spécialement conçue pour la queue du « R »

Formation de la banderole avec le slogan

# Banderole en haut de l'image
def banderole():
    rectangle(858,438,1,"darkblue",1716,100)
    penup(), goto(-560,450), pendown(), rectangle(-560,450,1,"white",20,76), penup(), goto(-480,526), pendown(), begin_fill(), circle(39), end_fill(), penup(), goto(-463,511), color("darkblue"), pendown(), begin_fill(), circle(25), end_fill(), penup(), goto(-446,504), pendown(), rectangle(-400,450,1,"white",20,76), penup(), goto(-215,526), begin_fill(), color("white"), circle(39), end_fill(), penup(), goto(-198,511), color("darkblue"), pendown(), begin_fill(), circle(25), end_fill(), penup(), goto(-145,505), pendown(), begin_fill(), rectangle(-145,505,1,"white",10,20), end_fill(), penup(), goto(-105,450), pendown(), rectangle(-105,450,1,"white",20,76), penup(), goto(-125,511), pendown(), rectangle(-65,511,1,"white",40,15), penup(), goto(-65,480), pendown(), rectangle(-65,480,1,"white",40,15), penup(), goto(-65,450), pendown(), rectangle(-65,450,1,"white",40,15), penup(), goto(-15,530), pendown(), begin_fill(), circle(30), end_fill(), penup(), goto(-15,507), pendown(), begin_fill(), circle(30), end_fill(), penup(), goto(-40,491), begin_fill(), color("darkblue"), pendown(), circle(19), end_fill(), penup(), goto(11,525), begin_fill(), color("darkblue"), pendown(), circle(19), end_fill(), penup(), goto(90,450), pendown(), rectangle(70,450,1,"white",20,76), penup(), pendown(), rectangle(85,506,1,"white",50,20), penup(), rectangle(225,450,1,"white",20,76), penup(), goto(243,526), begin_fill(), color("white"), circle(25), end_fill(), penup(), goto(243,513), begin_fill(), color("darkblue"), circle(12), end_fill(), penup(), rectangle(305,450,1,"white",15,76), penup(), rectangle(340,511,1,"white",35,15), penup(), rectangle(345,450,1,"white",15,76), penup(), rectangle(345,480,1,"white",40,15), rectangle(388,450,1,"white",15,76), penup(), goto(406,526), begin_fill(), color("white"), circle(25), end_fill(), penup(), goto(406,513), begin_fill(), color("darkblue"), circle(12), end_fill(), penup(), trapeze("white",1,388,483,410,483,430,450,410,450), penup(), rectangle(470,450,1,"white",20,76), goto(520,530), pendown(), begin_fill(), circle(30), end_fill(), penup(), goto(520,507), pendown(), begin_fill(), circle(30), end_fill(), penup(), goto(494,491), begin_fill(), color("darkblue"), pendown(), circle(19), end_fill(), penup(), goto(545,525), begin_fill(), color("darkblue"), pendown(), circle(19), end_fill()  


banderole()

Rendu final

Projets

Avions de l’armée américaine

Nous avions donc comme premier projet de première de réaliser une image qui se génère grâce à code python que nous devions créer sur une durée de un mois. Nous avons donc choisi de générer un F-16, F-22 et F-35 pour ce projet. Nous devions utiliser le module turtle pour l’image.

Origines de ces avions

Le F-16 est un avion de combat à rôles multiples de l’armée américaine créé dans les années 70.
Le F-22 est un avion de chasse furtif de l’armée américaine créé dans les années 90.
Le F-35 est un avion de combat à rôles multiples de l’armée américaine créé dans les années 2000.

Organisation

Pour réussir à faire le script nous avons dû séparer les différentes parties du code pour s’y repérer. Cela nous a donc permis de faire des appels de fonctions dans le code (rectangle, triangle, étoile, trapèze).
Faire appel à des fonctions permet de réduire la taille du code, cela été utile étant donné la limite de 404 lignes.


Le Script

Nous allons commencer par le début du code

from turtle import *
from random import randint

try:
    from PIL import Image
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False

titre = "Avions de l'armée américaine - F16 F22 F35"
title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")

setup(1280, 720)
speed(0)
colormode(255)
hideturtle()

flash = True
if flash:
    wn = Screen()
    wn.tracer(0)

Il permet d’importer les modules nécessaires et initialiser la plupart du code (comme la couleur ou pillow).
« flash » est une nouveauté, il permet de générer instantanément l’image.


LA SAUVEGARDE DES IMAGES

Pour sauvegarder l’image on nous a donné ce code ci-dessous :

image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]

# Génère un fichier .ps
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')

# Ouvre le fichier .ps et génère le fichier .png


try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    
        
      except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")

Or nous avions besoin d’enregistrer plusieurs images pour montrer les différentes étapes. Nous avons donc transformé ce code en une fonction nommée save() qui permet de sauvegarder l’image à n’importe quel moment dans le code.


LE FOND

La première fonction « drapeau » est le fond de l’image

def drapeau():        
    ligne(-640,640,13)
    rectangle(-640,-24,640,-385,0,(35,45,100))
    pos_y = 325
    for j in range(1,6):
        for i in range(1,7):
            étoile(-700+106*i,pos_y,30)
        pos_y = pos_y-70
    pos_y = 290
    for j in range(1,5):
        for i in range(1,6):
            étoile(-647+106*i,pos_y,30)
        pos_y = pos_y-70

Cette fonction fait elle-même appel à d’autres fonctions. Commençons par la première fonction : « ligne »

def ligne(x,y,repeat):
    for i in range(repeat):
        rectangle(x,y,1280,-720/13,0,(150,20,30))
        y = y-720/13
        rectangle(x,y,1280,-720/13,0,(255,255,255))
        y = y-720/13

La fonction ligne permet de faire toutes les lignes du drapeau soit 13 lignes ou 7 rouges et 6 blanches.
Et à chaque ligne il descend de la résolution de l’image divisée par 13 (car il y a 13 lignes)

Ensuite nous avons la création du rectangle bleu en haut à gauche du drapeau.

rectangle(-640,-24,640,-385,0,(35,45,100))

Ensuite il y a la fonction « étoile »

def étoile(x,y,L):
    setup(x,y,(255,255,255))
    pensize(5)
    for i in range(5):
        forward(L)
        right(144)
    pensize(1)
    end_fill()

La fonction « étoile » utilise « setup » qui est une fonction qui permet de faire le début de toutes les formes et qui est donc utilisée dans la plupart des fonctions.
Cette fonction permet de créer une étoile et avec notre boucle « for » utilisée dans la fonction drapeau on peut créer ainsi les 50 étoiles.


PREMIER AVION : F-16

Le premier avion se situera à gauche de l’image, nous avons donc fait le plus ancien en premier : le F-16

Avant même d’avoir commencé à coder, on a refait les avions avec des formes géométriques pour savoir quelles formes créer et où les mettre.
Voici comment nous avions découpé le F-16 avec plusieurs formes géométriques (des triangles et des rectangles).

# ======================== F-16 ========================

def F16_plane(x,y):
    triangle_iso(-50 + x, -90 + y, 100, 100, (100, 100, 100))
    triangle_iso(-100 + x, -20 + y, 200, 100, (80, 80, 80))
    triangle_iso(-25 + x, 60 + y, 50, 180, (100, 100, 100))
    rectangle(-100 + x, -20 + y, 200, 20, 0, (70, 70, 70))
    rectangle(-10 + x, -110 + y, 20, -250, 0, (100, 100, 100))
    rectangle(-20 + x, -70 + y, 40, -130, 0, (100, 100, 100))

    for i in range(0, 66, 65):
        rectangle(-50 + i + x, -110 + y, 35, -20, 0, (80, 80, 80))

    for i in range(0, 203, 202):
        rectangle(-102 + i + x, -42 + y, 2, -55, 0, (70, 70, 70))

# ======================== COCKPIT F-16 ========================

    rectangle(-10 + x, 130 + y, 20, 50, 0, (10, 10, 10))
    triangle_iso(-10 + x, 80 + y, 20, -15, (10, 10, 10))
    cercle(10, 0 + x, 130 + y, (10, 10, 10))

Nous avons donc utilisé ces formes là pour créer l’avion puis ensuite fait un cockpit en noir. On a joué avec l’obscurité des couleurs pour créer un effet de profondeur.


DEUXIEME AVION : F-22

Le deuxième avion se situera au milieu de l’image, ce sera donc le F-22

Tout comme le F-16 nous avons d’abord refait le F-22 avec des formes géométriques.
Voici comment nous avons refait le F-22 avec les formes géométriques (des triangles et des rectangles).

La forme finale n’est pas exactement la même car nous avons décidé de modifier certaines choses pour que la forme soit plus ressemblante.

# ======================== F-22 ========================

def F22_plane(x,y):

    triangle_iso(-150+x,-20+y,300,150, (155, 155, 155))
    rectangle(-150+x,-40+y,300,-20, 0, (155, 155, 155))
    triangle_iso(-150+x,-40+y,300,-50, (155, 155, 155))
    rectangle(-85+x,-85+y,60,45, 45, (155,155,155))
    rectangle(-85+x,-85+y,30,30, 0, (155,155,155))
    rectangle(85+x,-85+y,-60,45, -45, (155,155,155))
    rectangle(85+x,-85+y,-30,30, 0, (155,155,155))
    rectangle(-30+x,-85+y,60,-220, 0, (160, 160, 160))
    for i in range(0,31,30):
        triangle_iso(-25+i+x,-85+y,20,-10, (50, 50, 50))
    triangle_iso(-30+x,135+y,60,50, (160, 160, 160))
    rectangle(-15+x,140+y,30,-80, 0, (160, 160, 160))
    triangle_iso(-15+x,220+y,30,35, (160, 160, 160))
    
# ======================== COCKPIT F-22 ========================

    triangle_iso(-10+x,160+y,20,-15,(255,190,0))
    rectangle(-10+x,160+y,20,-30,0,(255,190,0))
    trapèze(-10+x,190+y,20,20,10,(255,190,0))
    triangle_iso(-5+x,210+y,10,5,(255,190,0))

Pour éviter de créer une fonction losange nous avons mis l’orientation de base de la fonction rectangle donc en mettant l’orientation à 45° ou -45° cela nous a permis d’avoir des losanges.


TROISIEME AVION : F-35

Le troisième avion se situera à droite de l’image, ce sera donc le plus récent : le F-35

Tout comme les deux autres avions nous avons d’abord refait le F-35 avec des formes géométriques.
Voici le schéma du F-35 fait avec des formes géométriques (triangles, rectangles et trapèzes). Cet avion est celui que nous avons dû le plus modifier

#========================= F-35 ================================
    
def F35_plane(x,y):
    
    triangle_iso(-125+x,-20+y,250,150,(130,130,130))
    rectangle(-125+x,-20+y,250,25,0,(130,130,130))
    triangle_iso(-125+x,-45+y,250,-45,(130,130,130))
    triangle_iso(-30+x,80+y,60,110,(130,130,130))
    trapèze(-50+x,60+y,30,60,20,(130,130,130))
    trapèze(20+x,60+y,30,60,20,(130,130,130))
    trapèze(-20+x,120+y,40,70,20,(130,130,130))
    triangle_iso(-10+x,190+y,20,15,(130,130,130))
    trapèze(-15+x,-85+y,30,-20,20,(50,50,50))
    rectangle(-50+x,-115+y,50,-40,45,(130,130,130))
    rectangle(-80+x,-89+y,40,30,0,(130,130,130))
    rectangle(80+x,-85+y,50,-40,135,(130,130,130))
    rectangle(40+x,-89+y,40,30,0,(130,130,130))
    
#========================== COCKPIT F-35 ========================
    
    trapèze(-9+x,160+y,18,-35,40,(15,15,15))
    trapèze(-9+x,160+y,18,15,5,(15,15,15))
    rectangle(-18+x,125+y,36,10,0,(15,15,15))
    trapèze(-18+x,115+y,36,-20,10,(15,15,15))

Le F-35 fut le plus compliqué à faire étant donné la fonction trapèze très complexe à utiliser mais après un moment nous avons réussit à le finir.

LE NOM DES AVIONS

Maintenant que nous avons les différents avions nous avons décidé de mettre leur nom sous chacun d’eux. Pour cela, il nous fallait générer les caractères : F – 1 2 3 5 6

Donc nous avons créé 7 fonctions pour les 7 caractères différents.

#========================= CARACTERES =====================

def F(x,y):
    rectangle(-50+x,y,10,100,0,(0,0,0))
    rectangle(-50+x,y-30,30,10,0,(0,0,0))
    rectangle(-50+x,y,50,10,0,(0,0,0))

def tiret(x,y):
    rectangle(x,y,30,10,0,(0,0,0))

def un(x,y):
    rectangle(x,y,10,100,0,(0,0,0))
    rectangle(x,y-15,-20,10,0,(0,0,0))

def deux(x,y):
    rectangle(x,y,50,10,0,(0,0,0))
    rectangle(x,y-90,50,10,0,(0,0,0))
    rectangle(x,y-50,50,10,0,(0,0,0))
    rectangle(x,y-90,10,-30,0,(0,0,0))
    rectangle(x+40,y-50,10,-40,0,(0,0,0))

def trois(x,y):
    rectangle(40+x,y,10,100,0,(0,0,0))
    rectangle(x,y,50,10,0,(0,0,0))
    rectangle(x,y-50,50,10,0,(0,0,0))
    rectangle(x,y-90,50,10,0,(0,0,0))

def cinq(x,y):
    rectangle(x,y,50,10,0,(0,0,0))
    rectangle(x,y,10,50,0,(0,0,0))
    rectangle(x,y-90,50,10,0,(0,0,0))
    rectangle(x+40,y-90,10,-30,0,(0,0,0))  
    rectangle(x,y-50,50,10,0,(0,0,0))

def six(x,y):
    rectangle(x,y,50,10,0,(0,0,0))
    rectangle(x,y,10,100,0,(0,0,0))
    rectangle(x,y-90,50,10,0,(0,0,0))
    rectangle(x+40,y-90,10,-30,0,(0,0,0))
    rectangle(x,y-50,50,10,0,(0,0,0))

Maintenant, que nous avons les lettres, il nous suffit d’y faire appel pour créer les noms.

Premièrement le F-16 :

def F_16(x,y):
    F(x,y)
    tiret(x,y-50)
    un(x+50,y)
    six(x+70,y)

Ensuite le F-22 :

def F_22(x,y):
    F(x,y)
    tiret(x,y-50)
    deux(x+40,y)
    deux(x+100,y)

Et dernièrement le F-35 :

def F_35(x,y):
    F(x,y)
    tiret(x,y-50)
    trois(x+40,y)
    cinq(x+100,y)

Les difficultés

La principale difficulté était de trouver les bonnes proportions et coordonnées à mettre pour positionner les formes.

Au début, une autre difficulté que nous avons rencontrée était d’utiliser des fonctions pour créer les avions, mais nous avons rapidement réussi.

L’IMAGE FINALE

Le fichier .py

Art

Five Night At Freddy’s 4

Pour notre premier projet en classe de 1ère spécialité NSI, nous nous sommes basés sur le thème du célèbre jeu vidéo d’horreur Five Night At Freddy’s 4. Notre image représente le menu du jeu vidéo Five Night At Freddy’s 4.


Ici vous trouverez les différentes étapes qui nous ont permis de créer cette image.

Description de notre projet.

Ce projet consiste a créer une image fait par l’art génératif grâce à un script python qui doit utiliser plusieurs fonctions. Pour ce projet, le thème de l’image créée est libre. Nous avons choisi de recréer l’image du menu du jeu vidéo d’horreur Five Night At Freddy’s 4 comme nous sommes dans la période d’&Halloween.

Pour le réaliser, nous avons utilisé le module turtle qui nous permet de tracer l’image.

Le fond de l’image.

Tout d’abord, nous avons commencé notre script par le code du fond de l’image. Ce code crée un dégradé du rouge jusqu’au noir, qui démarré à partir de la moitié de l’image pour aller jusqu’en haut. Il correspond au ciel.

for i in range(180):
    pencolor(120-int(i/2), 0, 0)
    forward(1280)
    up()
    backward(640)
    down()
    go(-640,i*2)

Nous avons choisi d’utiliser une boucle for i in range() : pour répéter 180 fois le programme. Le pencolor(120-int(i/2), 0, 0) permet de faire le dégradé. L’utilisation du -int fait en sorte que le fond va se dégrader moins rapidement et le (i/2) permet de régler la vitesse du dégradé.

Les nuages.

La seconde étape de notre projet consiste à créer des nuages. Ces nuages sont assez particuliers du fait de leur couleur qui se fond dans le dégradé du ciel.

def draw_stripes(x, y, radius, stripe_width):
    for i in range(-radius, radius, stripe_width):
        half_width = math.sqrt(radius**2 - i**2)

        up()
        goto(x - half_width, y + i)
        down()
        goto(x + half_width, y + i)

def cloud(x=0,y=0,r=30,s=2):#nuage
    pensize(0.1)
    pencolor(255,200,200)
    radius1 = r
    stripe_width = s
    for i in range(2):
        draw_stripes(x+30*i, y+10*i, radius1, stripe_width)
        draw_stripes(x+30*i, y-10*i, radius1, stripe_width)

Ici on a défini deux fonctions :

  • La première permet de faire des traits à l’intérieur d’un cercle pour régler l’opacité en turtle python.,
  • La seconde permet à la suite de la première d’empiler plusieurs cercles pour former un nuage.

La demi-lune.  

La troisième étape de notre script consiste à faire une demi-lune, qui se placera en haut à gauche de notre image.

def half_moon():
    fillcolor(255,255,255)
    pencolor(255,255,255)
    go(-500,200)
    begin_fill()
    left(180)
    circle(-60,180)
    left(200)
    circle(55,180)
    left(200)
    circle(-65,50)
    end_fill()
    left(190)

Ce script forme un demi-cercle plus grand puis un autre demi-cercle plus petit qui se rejoignent.

La maison.

La quatrième étape consiste à créer une maison qui se situera au milieu de notre image.

def House(t = 1):
    fillcolor(47,6,6)
    pencolor(47,6,6)
    go(0,35)
    for i in range(2):
        for i in range(2):
            begin_fill()
            forward(65*t)
            right(90)
            forward(15*t)
            right(90)
            end_fill()
        up()
        left(90)
        forward(30*t)
        right(90)
        down()
    go(0,35*t)
    for i in range(2):
        for i in range(2):
            begin_fill()
            forward(25*t)
            right(90)
            forward(25*t)
            right(90)
            end_fill()
        up()
        forward(40*t)
        down()
    go(130,95)
    for i in range(2):
        begin_fill()
        forward(40)
        right(90)
        forward(45*t)
        right(90)
        end_fill()
    begin_fill()
    go(170,95)
    left(105)
    forward(30*t)
    y=5
    for i in range(y):
        left(75/y)
        forward(2)
    forward(70*t)
    for i in range(y):
        left(90/y)
        forward(2)
    forward(35*t)
    backward(17*t)
    right(90)
    forward(40*t)
    y=10
    for i in range(y):
        left(90/y)
        forward(3)
    left(90)
    forward(55*t)
    backward(35*t)
    right(90)
    forward(15*t)
    left(90)
    forward(5*t)
    left(90)
    forward(15*t)
    end_fill()
    begin_fill()
    backward(15*t)
    left(90)
    forward(20*t)
    left(90)
    forward(25*t)
    left(90)
    forward(50*t)
    left(90)
    forward(25*t)
    left(90)
    forward(30*t)
    end_fill()

Dans ce script nous avons construit plusieurs rectangles grâce à des boucles for qui forment la maison.

Les arbres.

La cinquième étape, crée deux arbres qui sont constitués chacun de 6 points.

def tree(l=1,x=0,y=0):
    go(x,y)
    right(180)
    begin_fill()
    for i in range(2):
        forward(10*l)
        left(90)
        forward(30*l)
        left(90)
    left(90)
    forward(40*l)
    right(90)
    for i in range(2):
        dot(30*l)
        forward(5*l)
        dot(30*l)
        forward(5*l)
        left(90)
        dot(30*l)
        forward(15*l)
        dot(30*l)
        forward(15*l)
        left(90)
        dot(30*l)
    end_fill()

Ce code permet de créer 6 points qui vont faire les feuilles de l’arbre et un rectangle qui va faire le tronc.

Le sol.

Pour la sixième étape, nous avons fait le sol de notre image qui représente une colline.

begin_fill()
for i in range(400):
    forward(3)
    if i<35 or 80<i<100:
        ligne_down()

    elif 25<i<80 :
        ligne_up()

right(90)
forward(360)
right(90)
forward(1280)
right(90)
forward(347)
end_fill()

Le sol est fait par les fonctions ligne_up() et ligne_down() qui permettent de créer la montée et la descente de la colline.

Ecriture de FNAF4.

Pour la dernière étape nous avons fait créer le titre du jeu pour realiser l’intégralité de l’image du menu du jeu.  L’écriture Five Night At Freddy’s 4 sera de couleur rouge et se situera en bas à droite de notre image.

pencolor(200,10,10)
go(400,-200)
write('five',False,'left',('Baskerville Old Face',24,'normal'))
go(400,-230)
write('nights',False,'left',('Baskerville Old Face',24,'normal'))
go(400,-260)
write('at',False,'left',('Baskerville Old Face',24,'normal'))
go(400,-290)
write("freddy's",False,'left',('Baskerville Old Face',24,'normal'))
go(480,-320)
write("4",False,'left',('Baskerville Old Face',105,'normal'))

Pour écrire Five Night At Freddy’s 4, nous avons utilisé la fonction write() puis on a défini la police Baskerville Old Face avec la taille 24 et pour le chiffre 4 nous avons décidé de prendre la taille 105.

Les difficultés rencontrées durant le projet.

La première difficulté rencontrée et surtout celle qui nous a le plus posé problème est la création des nuages. Nous ne savions pas trop comment les coder et ni comment faire pour la couleur. Au début nous avons cherché une formule permettant d’avoir la couleur recherchée, que nous n’avons jamais trouvé. Finalement, à la suite de plusieurs essais, nous avons fait, un peu par hasard, une illusion d’optique avec l’assemblage de plusieurs traits qui donnent une couleur rouge plus claire.

Puis l’autre difficulté a été de maitriser les fillcolor(), car il fallait mettre au bon endroit le begin() et le end().

Les sources.

Pour écrire ce script nous avons utilisé nos connaissances ainsi que le site Python Docs pour trouver de nouvelles commandes. Nous avons aussi regardé quelques projets des années précédentes pour nous inspirer et nous guider.

Image finale.

Code complet.