Objectif : préparer un dossier de projet, créer des images avec l’éditeur Pyxel, charger un fichier .pyxres, afficher un sprite, déplacer un personnage avec les flèches, placer des murs via une grille (liste de listes) et empêcher les collisions.
Préparer le dossier du projet
Créer l’arborescence minimale
- Créer un dossier de projet dans votre espace personnel :
P:\Documents\NSI\Projet_Pyxel\ - Placer dans ce dossier deux fichiers Python :
editor.py: qui ouvrira l’éditeur Pyxelmain.py: qui lancera le programme de jeu
- L’éditeur créera un fichier de ressources :
my_resource.pyxres
Ouvrir l’éditeur Pyxel depuis Thonny
Créer le script d’ouverture de l’éditeur
Créer editor.py avec le code suivant :
import sys, runpy
# Simuler la commande : pyxel edit my_resource.pyxres
sys.argv = ["pyxel", "edit", "my_resource.pyxres"]
runpy.run_module("pyxel.__main__", run_name="__main__")
Lancer l’éditeur
- Exécuter
editor.pydans Thonny. - Observer l’ouverture de la fenêtre de l’éditeur Pyxel.
- Conserver cette fenêtre ouverte le temps de dessiner, puis enregistrer.
Comprendre l’éditeur Pyxel (système de coordonnées)
Comprendre ce qu’est un fichier .pyxres
- Considérer
my_resource.pyxrescomme une “boîte” qui contient des ressources :- Images (sprites) dans des banques d’images (Image 0, Image 1, etc.)
- Tilemaps (cartes composées de tuiles)
- Sons et musiques (optionnel)
Le programme Python chargera ce fichier avec l’instruction :
pyxel.load("my_resource.pyxres")
Comprendre l’onglet Image
- Se placer dans l’onglet Image.
- Sélectionner Image 0 (banque d’image numéro 0).
- Observer la grande zone de pixels avec une grille.
- Interpréter les coordonnées :
u: coordonnée horizontale dans l’image (vers la droite)v: coordonnée verticale dans l’image (vers le bas)(u, v) = (0, 0): pixel en haut à gauche de la banque d’image
Comprendre l’idée de “sprite”
- Un sprite correspond à un rectangle dans l’image.
- Exemple : un sprite 16×16 placé en haut à gauche occupe :
ude 0 à 15vde 0 à 15
Comprendre le lien entre l’éditeur et le code
Pour dessiner à l’écran un sprite stocké dans l’image 0, utiliser :
pyxel.blt(x, y, img, u, v, w, h, colkey=0)
x, y: position en pixels dans la fenêtre du jeuimg: numéro de banque d’image (souvent 0)u, v: coordonnées dans l’image (ce qui est dessiné)w, h: largeur et hauteur du sprite en pixelscolkey=0: rendre la couleur 0 transparente (souvent le noir)
Créer la première image (personnage) dans l’éditeur
Dessiner un personnage 16×16
- Dans l’onglet Image, sur Image 0 :
- Dessiner un personnage dans un carré 16×16 à partir de
(u=0, v=0) - Utiliser un fond en couleur 0 (noir) si la transparence est souhaitée
- Dessiner un personnage dans un carré 16×16 à partir de
- Enregistrer le fichier :
- Menu File → Save (ou raccourci clavier)
- Vérifier l’existence de
my_resource.pyxresdans le dossier du projet.
Premier programme : charger l’image et déplacer le personnage
Objectif
- Ouvrir une fenêtre noire.
- Charger les ressources dessinées.
- Afficher le personnage.
- Déplacer le personnage avec les flèches.
- Empêcher le personnage de sortir de la fenêtre.
Créer main.py
Créer main.py avec le code suivant :
import pyxel
# Définir la taille de la fenêtre
W, H = 160, 120
# Définir la position initiale du personnage
x, y = 50, 50
# Définir la vitesse de déplacement (pixels par frame)
speed = 2
# Initialiser la fenêtre Pyxel
pyxel.init(W, H, title="Deplacement simple")
# Charger le fichier de ressources créé par l'éditeur
pyxel.load("my_resource.pyxres")
def update():
"""
Mettre à jour l'état du jeu.
Lire le clavier.
Calculer la nouvelle position du personnage.
Appliquer des limites pour rester dans la fenêtre.
"""
global x, y
# Modifier x et y selon les touches pressées
if pyxel.btn(pyxel.KEY_LEFT):
x = x - speed
if pyxel.btn(pyxel.KEY_RIGHT):
x = x + speed
if pyxel.btn(pyxel.KEY_UP):
y = y - speed
if pyxel.btn(pyxel.KEY_DOWN):
y = y + speed
# Empêcher la sortie de l'écran (sprite 16x16)
if x < 0:
x = 0
if x > W - 16:
x = W - 16
if y < 0:
y = 0
if y > H - 16:
y = H - 16
def draw():
"""
Dessiner l'écran.
Effacer l'écran en noir.
Dessiner le personnage.
"""
# Remplir l'écran avec la couleur 0 (noir)
pyxel.cls(0)
# Dessiner le sprite du personnage
# sprite 16x16 dans l'image 0 à (u=0, v=0)
pyxel.blt(x, y, 0, 0, 0, 16, 16, colkey=0)
# Lancer la boucle Pyxel : update puis draw répétés
pyxel.run(update, draw)
Détailler l’algorithme de déplacement
- Initialiser la position
(x, y)du personnage. - À chaque frame (boucle de jeu) :
- Lire l’état des touches avec
pyxel.btn(...). - Si une touche est pressée, modifier
xouy:- gauche : diminuer
x - droite : augmenter
x - haut : diminuer
y - bas : augmenter
y
- gauche : diminuer
- Appliquer des bornes pour rester à l’écran :
- forcer
xà rester entre0etW-16 - forcer
yà rester entre0etH-16
- forcer
- Lire l’état des touches avec
- À chaque frame :
- Effacer l’écran avec
pyxel.cls(0). - Dessiner le sprite avec
pyxel.blt(...).
- Effacer l’écran avec
Créer une seconde image : un mur en coordonnées (16,0)
Objectif
- Dessiner un bloc “mur” 16×16 dans la même banque d’image (Image 0).
- Placer ce mur juste à droite du personnage dans l’image.
Dessiner le mur
- Ouvrir l’éditeur via
editor.py. - Dans l’onglet Image, sur Image 0 :
- Laisser le personnage dans le carré 16×16 à
(0,0) - Dessiner un mur dans un carré 16×16 à partir de
(u=16, v=0)- le mur occupe
ude 16 à 31 etvde 0 à 15
- le mur occupe
- Laisser le personnage dans le carré 16×16 à
- Enregistrer
my_resource.pyxres.
Ajouter le mur à la map à 6 endroits avec une liste de listes
Principe de la grille (liste de listes)
- Découper la fenêtre en cases de 16×16.
- Pour une fenêtre
160×120:- Colonnes :
160 / 16 = 10 - Lignes :
120 / 16 = 7
- Colonnes :
- Représenter la carte avec une liste de 7 lignes, chacune contenant 10 valeurs :
0: case vide1: case mur
Placer exactement 6 murs
Définir une grille qui contient 6 valeurs 1. Exemple ci-dessous.
Empêcher le personnage de traverser les murs (collision)
Principe de la collision
- Associer une position en pixels
(x, y)à une case(col, row):col = x // 16row = y // 16
- Un personnage 16×16 occupe plusieurs pixels.
- Tester les 4 coins du personnage :
- coin haut-gauche
- coin haut-droite
- coin bas-gauche
- coin bas-droite
- Refuser un déplacement si au moins un coin tombe dans une case mur.
Utiliser un déplacement “fluide”
- Calculer une position candidate
(nx, ny)à partir du clavier. - Tester le déplacement sur l’axe X puis sur l’axe Y :
- autoriser X si pas de collision
- autoriser Y si pas de collision
Programme complet : murs (6), affichage, déplacement, collisions
Remplacer main.py par :
import pyxel
TILE = 16
W, H = 160, 120
COLS = W // TILE # 10
ROWS = H // TILE # 7
# Grille : 0 = vide, 1 = mur
# Placer exactement 6 murs (6 valeurs à 1)
level = [
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,0,0,0,0,0,0], # mur 1
[0,0,0,1,0,0,0,1,0,0], # mur 2 et mur 3
[0,0,0,0,0,0,0,1,0,0], # mur 4
[0,0,0,0,1,0,0,0,0,0], # mur 5
[0,0,0,0,1,0,0,0,0,0], # mur 6
[0,0,0,0,0,0,0,0,0,0],
]
# Position initiale du personnage
px, py = 32, 32
speed = 2
pyxel.init(W, H, title="Murs et collisions")
pyxel.load("my_resource.pyxres")
def is_wall_at_pixel(x, y):
"""
Déterminer si le pixel (x, y) tombe sur une case mur.
Convertir pixel -> case via division entière.
Considérer l'extérieur de la fenêtre comme un mur.
"""
col = x // TILE
row = y // TILE
if col < 0 or col >= COLS or row < 0 or row >= ROWS:
return True
return level[row][col] == 1
def can_move_to(nx, ny):
"""
Déterminer si un sprite 16x16 placé en (nx, ny) toucherait un mur.
Tester les 4 coins du sprite.
"""
corners = [
(nx, ny),
(nx + 15, ny),
(nx, ny + 15),
(nx + 15, ny + 15),
]
for cx, cy in corners:
if is_wall_at_pixel(cx, cy):
return False
return True
def update():
"""
Lire le clavier.
Proposer une nouvelle position.
Tester la collision.
Appliquer le mouvement seulement si autorisé.
"""
global px, py
nx, ny = px, py
# Construire une position candidate
if pyxel.btn(pyxel.KEY_LEFT):
nx = nx - speed
if pyxel.btn(pyxel.KEY_RIGHT):
nx = nx + speed
if pyxel.btn(pyxel.KEY_UP):
ny = ny - speed
if pyxel.btn(pyxel.KEY_DOWN):
ny = ny + speed
# Appliquer X puis Y (meilleur ressenti en collision)
if can_move_to(nx, py):
px = nx
if can_move_to(px, ny):
py = ny
def draw():
"""
Effacer l'écran.
Dessiner les murs selon la grille.
Dessiner le personnage.
"""
pyxel.cls(0)
# Dessiner les murs : sprite 16x16 en (u=16, v=0)
for row in range(ROWS):
for col in range(COLS):
if level[row][col] == 1:
x = col * TILE
y = row * TILE
pyxel.blt(x, y, 0, 16, 0, 16, 16)
# Dessiner le personnage : sprite 16x16 en (u=0, v=0)
pyxel.blt(px, py, 0, 0, 0, 16, 16, colkey=0)
pyxel.run(update, draw)
Travail demandé pour valider la compréhension
Modifier l’emplacement des 6 murs
- Déplacer les
1dans la grillelevel. - Conserver exactement 6 murs.
- Vérifier que le personnage ne traverse pas les murs.
Modifier l’apparence du mur
- Retoucher le sprite du mur dans l’éditeur en restant dans le carré 16×16 à
(16,0). - Sauvegarder puis relancer
main.py.
Ajouter un autre élément
- Créer un nouveau sprite dans l’éditeur dans le carré 16×16 à
(32,0). - Sauvegarder.
- Ajouter des
2dans la grilleleveldu fichiermain.py. - Faire correspondre le nouveau sprite à ces nombres.