
Sommaire7
Votre saut semble cassé parce que la physique de Godot ne pardonne pas les erreurs de timing — ces deux mécaniques règlent ça en 20 lignes de GDScript.
Pourquoi ça marche
Le temps de réaction humain à un signal visuel est d'environ 150–200 ms. À 60 fps, le bord d'une plateforme ne dure qu'un pixel — personne ne peut timer ça de façon fiable. Les mécaniques de pardon absorbent l'écart entre l'intention et l'exécution.
- Le coyote time rattrape les appuis trop tardifs — le joueur a sauté juste après le bord.
- Le jump buffer rattrape les appuis trop précoces — le joueur a sauté juste avant d'atterrir.
Ensemble, ils donnent l'impression au joueur d'être compétent, pas chanceux.

La recette
| Paramètre | Valeur de départ | Plage pratique | Ce que ça change |
|---|---|---|---|
coyote_time | 0.10 s (6 frames) | 0.06–0.15 s | Fenêtre de grâce après le bord |
jump_buffer_time | 0.08 s (5 frames) | 0.05–0.12 s | Acceptation de l'appui anticipé |
Commencez avec ces valeurs exactes. Les jeux de précision descendent en dessous ; les jeux casual ou mobiles montent. Ajustez par paliers de 10 ms et testez à chaque changement.

Le code
À attacher à votre CharacterBody2D. Intégrez-le dans votre _physics_process existant, ou utilisez-le tel quel comme point de départ.
extends CharacterBody2D
const GRAVITY: float = 980.0
const JUMP_VELOCITY: float = -400.0
const SPEED: float = 200.0
@export var coyote_time: float = 0.10 # secondes — Celeste utilise 0.10 s
@export var jump_buffer_time: float = 0.08 # secondes — légèrement inférieur au coyote
var _coyote_timer: float = 0.0
var _jump_buffer_timer: float = 0.0
func _physics_process(delta: float) -> void:
# 1. Gravité — appliquée uniquement en vol
if not is_on_floor():
velocity.y += GRAVITY * delta
# 2. Timer coyote — se remet à zéro au sol, décompte dans les airs
if is_on_floor():
_coyote_timer = coyote_time
else:
_coyote_timer -= delta
# 3. Buffer de saut — enregistre un appui saut pendant une courte fenêtre
if Input.is_action_just_pressed("ui_accept"):
_jump_buffer_timer = jump_buffer_time
else:
_jump_buffer_timer -= delta
# 4. Saut — se déclenche si le buffer a un appui en attente ET que le coyote est valide
if _jump_buffer_timer > 0.0 and _coyote_timer > 0.0:
velocity.y = JUMP_VELOCITY
_coyote_timer = 0.0 # consomme le coyote — évite le double saut aérien
_jump_buffer_timer = 0.0 # consomme le buffer — évite un saut non voulu à l'atterrissage
# 5. Déplacement horizontal
var direction: float = Input.get_axis("ui_left", "ui_right")
velocity.x = direction * SPEED
move_and_slide()
L'astuce clé : comme _coyote_timer se remet à zéro à chaque frame au sol, la simple vérification _coyote_timer > 0.0 gère à la fois "actuellement au sol" et "vient de quitter le sol". Pas besoin d'un is_on_floor() séparé au moment du saut.

Réglages et erreurs fréquentes
Conseils
- Baissez
coyote_timeà 0.06 s pour les jeux de précision. Trop de grâce donne l'impression de marcher sur de l'air. - Gardez
jump_buffer_timelégèrement inférieur àcoyote_time— ça semble plus intentionnel. - Exportez les deux variables pour les ajuster depuis l'Inspecteur sans recompiler.
Erreurs fréquentes
- Ne pas remettre
_coyote_timerà zéro après un saut → double saut depuis un bord de plateforme. - Ne pas remettre
_jump_buffer_timerà zéro après un saut → l'appui en file se déclenche à l'atterrissage suivant, ce qui surprend le joueur. - Appeler
is_on_floor()directement au moment du saut au lieu d'utiliser le timer → tout le pardon est perdu.

Exemples célèbres
Maddy Thorson (co-créateur de Celeste) a publié un thread en mars 2020 listant les mécaniques de pardon cachées du jeu. Le coyote time est le point n°1 — JumpGraceTime = 0.1f dans le code source, mesuré exactement à 6 frames par feelframes.dev. Note de Thorson : "Je ne crois pas qu'on ait inventé ces mécaniques."

Les 133 ms de Mario Odyssey s'accordent avec son design casual orienté exploration. Les 100 ms de Celeste sont délibérés — le jeu est difficile, mais la précision reste juste. Les ~50 ms de Super Meat Boy exigent une vraie maîtrise. Le devlog Behind the Code de GMTK inclut les deux mécaniques comme valeurs par défaut essentielles dans le Platformer Toolkit.

Tableau de référence
| Style de jeu | Coyote time | Jump buffer |
|---|---|---|
| Précision (Super Meat Boy) | 0.06 s | 0.05 s |
| Action-platformer (Hollow Knight) | 0.10 s | 0.08 s |
| Casual / débutant (Mario) | 0.13 s | 0.10 s |

FAQ
Est-ce que le coyote time casse les wall jumps ou les double jumps ?
Ça peut. La correction est déjà dans le code ci-dessus : remettez _coyote_timer à zéro immédiatement après tout saut — au sol, sur un mur, ou double saut. Sans ça, un wall jump pourrait consommer le coyote time et accorder un saut supplémentaire.
Vaut-il mieux utiliser des nœuds Timer plutôt que des timers en float ?
Les timers en float dans _physics_process sont plus simples, déterministes et n'ajoutent aucun nœud à la scène. Utilisez des nœuds Timer uniquement si vous avez besoin de signaux (par exemple pour déclencher un son ou une animation à la fin exacte de la fenêtre de grâce).
Mon saut est encore trop flottant — quoi ajouter ensuite ?
Ajoutez la hauteur de saut variable : quand le joueur relâche le bouton de saut tôt, multipliez la gravité par 2.0–3.0 pour couper l'arc. Ça donne des pics de saut précis et contrôlables, et c'est l'étape naturelle suivante après le coyote time.
Est-ce compatible avec un state machine d'animation ?
Oui. Les timers sont purement de la logique de mouvement — ils ne touchent pas à l'animation. Connectez votre animation en vérifiant velocity.y et is_on_floor() dans une fonction séparée.
Ça fonctionne avec Godot 4.3 ou 4.4 ?
Oui. CharacterBody2D, is_on_floor() et move_and_slide() sont stables sur tout Godot 4.x. Aucune migration nécessaire.
Ajoutez le coyote time et le jump buffer une fois pour toutes et vous ne recevrez plus de retours "les contrôles ne répondent pas". Pour la boîte à outils complète — screen shake, hit stop, squash & stretch — consultez le Game Feel Cookbook.


