I'm trying to make a game inspired by the puzzles of The Witness

Fluffy1oo
Tue, 13 Jan 2026 06:24:46 +0000
Coding Questions

from p5 import run,createCanvas,noLoop,background,stroke,line,fill,noStroke,rect,strokeWeight,noFill,ellipse,point,mouseIsPressed

# DÉFINITION DES NIVEAUX

LEVELS = [
{
"grid": (4, 4), # taille de la grille : 4 colonnes x 4 lignes
"start": (0, 0), # nœud de départ
"end": (4, 4), # nœud d'arrivée
"blocked": [(1,1),(2,1)],# cases interdites
"symbols": [(0,2,'circle'), (3,1,'circle')]# symboles à visiter avant l'arrivée
},
{
"grid": (5, 5),
"start": (0, 4),
"end": (4, 0),
"blocked": [(2,2),(1,3)],
"symbols": [(0,2,'circle'), (2,4,'circle')]
},
{
"grid": (6, 6),
"start": (0, 0),
"end": (5, 5),
"blocked": [(2,2),(3,3),(1,4)],
"symbols": [(1,1,'circle'), (4,4,'circle')]
}
]

# CONFIGURATION VISUELLE

CELL = 80 # taille d'une cellule
MARGIN = 40 # marge autour de la grille pour le dessin
SNAP_RADIUS = CELL / 1.5 # rayon pour “attraper” le nœud avec le clic

# VARIABLES DU JEU

current_level = 0 # niveau actuel
path = [] # liste des nœuds visités pour le chemin
lines_drawn = set() # lignes déjà tracées (pour ne pas repasser dessus)
game_finished = False

# FONCTIONS UTILITAIRES

def node_position(node):
"""
Convertit un nœud (col, row) en coordonnées pixels pour l'affichage
"""
x, y = node
return MARGIN + x * CELL, MARGIN + y * CELL

def distance(x1, y1, x2, y2):
"""
Calcul de la distance euclidienne entre deux points
"""
return ((x1-x2)**2 + (y1-y2)**2)**0.5

def snap_to_node(mx, my, grid):
"""
Retourne le nœud le plus proche du clic
"""
closest = None
min_dist = SNAP_RADIUS
cols, rows = grid
for x in range(cols+1):
for y in range(rows+1):
nx, ny = node_position((x, y))
d = distance(mx, my, nx, ny)
if d <= min_dist:
closest = (x, y)
min_dist = d
return closest

def is_adjacent(a, b):
"""
Vérifie si deux nœuds sont adjacents horizontalement ou verticalement
"""
return abs(a[0]-b[0]) + abs(a[1]-b[1]) == 1

def node_blocked(node):
"""
Vérifie si un nœud est dans la liste des blocs interdits
"""
x, y = node
return (x, y) in LEVELS[current_level].get('blocked', [])

def line_used(a, b):
"""
Vérifie si une ligne entre deux nœuds a déjà été tracée
"""
return ((a,b) in lines_drawn) or ((b,a) in lines_drawn)

# CONFIGURATION DE LA FENÊTRE

def setup():
"""
Initialisation du canvas en fonction de la taille de la grille
"""
cols, rows = LEVELS[current_level]["grid"]
createCanvas(2*MARGIN + cols*CELL, 2*MARGIN + rows*CELL)
noLoop() # dessin manuel uniquement (rafraîchissement avec redraw())

def draw_grid():
"""
Dessine la grille principale
"""
cols, rows = LEVELS[current_level]["grid"]
stroke(80)
for x in range(cols+1):
line(MARGIN+x*CELL, MARGIN, MARGIN+x*CELL, MARGIN+rows*CELL)
for y in range(rows+1):
line(MARGIN, MARGIN+y*CELL, MARGIN+cols*CELL, MARGIN+y*CELL)

def draw_blocks():
"""
Dessine les cases bloquées
"""
fill(0)
noStroke()
for bx, by in LEVELS[current_level].get('blocked', []):
rect(MARGIN+bx*CELL, MARGIN+by*CELL, CELL, CELL)

def draw_symbols():
"""
Dessine les symboles (ex: cercles) que le joueur doit visiter
"""
symbols = LEVELS[current_level].get('symbols', [])
strokeWeight(8)
for x, y, kind in symbols:
nx, ny = node_position((x, y))
if kind=='circle':
stroke(0,0,255)
noFill()
ellipse(nx, ny, 20, 20)
strokeWeight(1)

def draw_points():
"""
Dessine les points de départ (vert) et d'arrivée (rouge)
"""
sx, sy = LEVELS[current_level]["start"]
ex, ey = LEVELS[current_level]["end"]
strokeWeight(10)
stroke(0,255,0)
px, py = node_position((sx, sy))
point(px, py)
stroke(255,0,0)
px, py = node_position((ex, ey))
point(px, py)
strokeWeight(1)

def draw_path():
"""
Dessine le chemin jaune tracé par le joueur
"""
stroke(255,255,0)
strokeWeight(6)
for i in range(len(path)-1):
a = path[i]
b = path[i+1]
x1, y1 = node_position(a)
x2, y2 = node_position(b)
line(x1, y1, x2, y2)
strokeWeight(1)

# INTERACTION : CLICS
# DESSIN

def draw():
"""
Dessine la grille, les blocs, les symboles, les points de départ/arrivée et le chemin
"""
background(30)
global path, lines_drawn, current_level, game_finished
if game_finished:
fill(255)
textSize(32)
textAlign(CENTER, CENTER)
text("JEU TERMINÉ", width/2, height/2)
return

draw_grid()
draw_blocks()
draw_symbols()
draw_path()
draw_points()

if mouseIsPressed:

if game_finished:
return

# détecte le nœud le plus proche du clic
node = snap_to_node(mouseX, mouseY, LEVELS[current_level]["grid"])
if node is None:
return

# si début du chemin
if not path and node == LEVELS[current_level]["start"]:
path.append(node)
lines_drawn = set()
redraw()
return

# si on a déjà commencé le chemin
elif path:
last = path[-1]

# clic sur l'arrivée
if node == LEVELS[current_level]["end"]:
# vérifier que tous les symboles ont été visités
symbols = LEVELS[current_level].get('symbols', [])
visited = set(path)
all_symbols = all((x,y) in visited for x,y,_ in symbols)
if not all_symbols:
print("Vous devez passer sur tous les symboles !")
return
# niveau terminé : passer au niveau suivant
current_level += 1
path = []
lines_drawn = set()
if current_level >= len(LEVELS):
game_finished = True
redraw()
return

# clic sur nœud adjacent valide
elif is_adjacent(last, node) and not node_blocked(node) and not line_used(last, node):
path.append(node)
lines_drawn.add((last, node))
redraw()

run()

Well, no matter how hard I try, the level shows, but when I try clicking on a node, it just doesn’t do anything.

7 posts - 3 participants