600T
- Entrée #066 – Jour 1,5
Une galère...
Non, rien
Oui, c’est parfait comme base. Je te propose une version nettoyée, corrigée et un peu plus pédagogique de ton fichier GODOT_MULTIVERSE.md, que tu peux mettre telle quelle dans ton repo.
Je garde ton esprit, je corrige quelques détails Godot 4 et j’ajoute deux-trois explications pour que tu voies où cliquer dans l’éditeur.
Tutoriel : coder un multivers dans Godot
Ce guide propose un mini-prototype 2D qui permet de voyager entre plusieurs « univers » parallèles (scènes Godot) tout en partageant certaines données du joueur.
Il est pensé pour Godot 4.x et un niveau débutant/intermédiaire en GDScript.
0. Pré-requis rapides
- Godot 4.x installé.
- Savoir créer :
- une scène 2D (
Node2D) ; - un
Area2DavecCollisionShape2D; - une ressource
PackedScene(en gros : sauvegarder une scène et l’exporter dans un script).
- une scène 2D (
L’objectif n’est pas d’avoir un jeu complet, mais un prototype clair à modifier à ta sauce.
1. Structure des scènes
On va partir sur cette arborescence :
res://
/Scenes
Main.tscn
UniversA.tscn
UniversB.tscn
/Player
Player.tscn
Player.gd
/Scripts
MultiverseManager.gd
Portal.gd1.1. Main.tscn (scène principale)
- Racine :
Node2D(nom : Main). - Enfant :
Node(nom : MultiverseManager) avec le scriptMultiverseManager.gd. - Enfant :
CanvasLayer(nom : par ex. UI) contenant unLabel(nom : UniverseLabel).
Visuellement :
Main (Node2D)
├── MultiverseManager (Node) [MultiverseManager.gd]
└── UI (CanvasLayer)
└── UniverseLabel (Label)Cette scène sera la scène principale de ton jeu.
1.2. Scènes d’univers : UniversA.tscn, UniversB.tscn
Pour chaque univers, crée une scène 2D avec :
- une racine
Node2D(nom au choix, ex.UniversA); - un
Node2Dnommé Spawn à l’endroit où le joueur doit apparaître ; - un
Area2Dnommé Portal (avecCollisionShape2D) pour changer d’univers, avec le scriptPortal.gd.
Exemple :
UniversA (Node2D)
├── Spawn (Node2D)
└── Portal (Area2D) [Portal.gd]
└── CollisionShape2DMême structure pour UniversB.tscn (avec éventuellement un décor différent).
1.3. Scène du joueur : Player.tscn
- Racine :
CharacterBody2DouNode2D(nom : Player), - Script :
Player.gdpour ses stats, les contrôles, etc.
Important : on n’instancie le joueur qu’une seule fois, dans MultiverseManager. Ensuite, on le déplace d’un univers à l’autre.
2. Script du gestionnaire de multivers
Crée Scripts/MultiverseManager.gd et attache-le au node MultiverseManager dans Main.tscn.
# Scripts/MultiverseManager.gd
extends Node
@export var univers_scenes: Array[PackedScene]
@export var player_scene: PackedScene
@export var ui_label_path: NodePath
var _current_universe: int = 0
var _player: Node2D
func _ready() -> void:
# Instancie le joueur une seule fois
_player = player_scene.instantiate()
add_child(_player)
# Charge le premier univers
_load_universe(_current_universe)
_update_ui()
func _load_universe(index: int) -> void:
if index < 0 or index >= univers_scenes.size():
push_warning("Index d'univers invalide : %s" % index)
return
# Supprimer la scène d'univers active, mais garder :
# - le joueur
# - les couches d'UI (CanvasLayer)
for child in get_children():
if child == _player:
continue
if child is CanvasLayer:
continue
child.queue_free()
# Instancier le nouvel univers
var universe := univers_scenes[index].instantiate()
add_child(universe)
# Placer le joueur au point de spawn si présent
_place_player(universe)
_current_universe = index
_update_ui()
func _place_player(universe: Node) -> void:
# On cherche un node "Spawn" dans la scène d'univers
var spawn := universe.get_node_or_null("Spawn")
if spawn and _player:
_player.global_position = spawn.global_position
func teleport_to_next() -> void:
var next_index := (_current_universe + 1) % univers_scenes.size()
_load_universe(next_index)
func teleport_to_previous() -> void:
var prev_index := (_current_universe - 1 + univers_scenes.size()) % univers_scenes.size()
_load_universe(prev_index)
func _update_ui() -> void:
if ui_label_path.is_empty():
return
var label := get_node_or_null(ui_label_path)
if label and label is Label:
label.text = "Univers : %d" % _current_universe2.1. À configurer dans l’éditeur
Dans l’inspecteur de MultiverseManager :
univers_scenes→ ajouteUniversA.tscn,UniversB.tscn, etc.player_scene→ assignePlayer.tscn.ui_label_path→ sélectionne tonUniverseLabel(par ex.../UI/UniverseLabel).
3. Script des zones de téléportation
Crée Scripts/Portal.gd et attache-le au Portal (Area2D) de chaque univers.
# Scripts/Portal.gd
extends Area2D
@export var direction: int = 1 # 1 = univers suivant, -1 = univers précédent
func _on_body_entered(body: Node) -> void:
# Ne réagit que si c'est le joueur
if body.name != "Player":
return
# On récupère la scène principale et le MultiverseManager
var manager := get_tree().root.get_node("/root/Main/MultiverseManager")
if manager:
if direction > 0:
manager.teleport_to_next()
else:
manager.teleport_to_previous()⚠️ Important :
- Le root de
Main.tscndoit s’appeler Main.- Le node avec le script
MultiverseManager.gddoit s’appeler MultiverseManager.- Dans l’éditeur, connecte le signal
body_entereddePortalà la fonction_on_body_entered.
Variante : exiger une touche pour activer le portail
Si tu ne veux pas téléporter dès que le joueur touche le portail, tu peux :
- Dans
Portal.gd, stocker le fait que le joueur est dedans. - Gérer l’input pour activer la téléportation.
Exemple rapide :
extends Area2D
@export var direction: int = 1
var _player_inside := false
func _on_body_entered(body: Node) -> void:
if body.name == "Player":
_player_inside = true
func _on_body_exited(body: Node) -> void:
if body.name == "Player":
_player_inside = false
func _process(delta: float) -> void:
if _player_inside and Input.is_action_just_pressed("ui_accept"):
var manager := get_tree().root.get_node("/root/Main/MultiverseManager")
if manager:
if direction > 0:
manager.teleport_to_next()
else:
manager.teleport_to_previous()4. Joueur et état partagé entre univers
Le joueur reste instancié en permanence dans Main.tscn.
Ça permet de garder :
- vie / énergie ;
- inventaire ;
- buffs / debuffs ;
- etc.
Exemple très simple de Player.gd :
# Player/Player.gd
extends CharacterBody2D
@export var max_hp: int = 100
var current_hp: int = max_hp
@export var move_speed: float = 200.0
func _physics_process(delta: float) -> void:
var input_vector := Vector2.ZERO
input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
velocity = input_vector.normalized() * move_speed
move_and_slide()Si tu veux afficher la vie dans l’UI, ajoute un label dédié et mets à jour son texte depuis Player.gd ou depuis un script d’UI.
5. UI minimale
Dans Main.tscn :
-
CanvasLayer→UILabel→UniverseLabel
Tu peux aussi ajouter :
- un
Labelpour la vie (HPLabel) ; - des boutons (
Button) pour tester les changements d’univers sans portail (en connectantpressed()àteleport_to_next()outeleport_to_previous()).
Actions clavier suggérées
Dans Project Settings → Input Map, ajoute :
ui_accept→ toucheEouEnter(activer un portail) ;ui_left/ui_right/ui_up/ui_downsi tu n’utilises pas encore les axes par défaut.
6. Astuces de performance et confort
-
Préchargement : Si tes univers deviennent lourds :
@export var univers_scenes: Array[PackedScene] = [ preload("res://Scenes/UniversA.tscn"), preload("res://Scenes/UniversB.tscn") ] -
Ressources partagées : Sons, shaders, données globales → mets-les dans un script d’Autoload (ex.
GlobalData.gd) pour éviter de les recharger dans chaque univers. -
Spawns cohérents : Garde le même nom de point de spawn (
Spawn) dans chaque univers et vérifie visuellement que le joueur ne « clignote » pas à des endroits absurdes.
7. Aller plus loin
Une fois le prototype fonctionnel :
-
Transitions visuelles
- Ajouter un écran noir avec fondu (Tween) avant/après
_load_universe. - Utiliser un shader de glitch pour donner une impression de « saut de dimension ».
- Ajouter un écran noir avec fondu (Tween) avant/après
-
États environnementaux partagés
- Heure du jour, météo, tension politique, niveau d’alerte…
- Tu peux stocker ça dans un Autoload (
WorldState.gd) et l’appliquer différemment selon l’univers.
-
Règles différentes par univers
-
Dans
MultiverseManager, tu peux définir une petite table de paramètres :var universe_rules := { 0: {"gravity": 1.0, "enemy_multiplier": 1.0}, 1: {"gravity": 0.5, "enemy_multiplier": 2.0}, } -
Puis appliquer ces règles aux ennemis, au joueur, etc.
-
-
Passage en 3D
- Remplace
Node2D/CharacterBody2DparNode3D/CharacterBody3D. - Remplace
Area2DparArea3DetCollisionShape2DparCollisionShape3D.
- Remplace
8. Résultat attendu
En suivant ce guide, tu obtiens un prototype où :
- le joueur existe en un seul exemplaire ;
- plusieurs univers (
UniversA,UniversB, …) peuvent être chargés ; - tu passes d’un univers à l’autre via des portails ou des boutons d’UI ;
- ton joueur garde ses stats d’un univers à l’autre.
C’est une base solide pour un jeu narratif, un jeu « politique » à univers parallèles, ou un prototype plus ambitieux de multivers.
Si tu veux, on peut faire la prochaine étape ensemble :
par exemple brancher ce multivers sur une idée de jeu concret (genre : chaque univers = un modèle de société, avec des règles différentes) et définir les variables de gameplay minimales à suivre (niveau de contrôle, liberté, accès à l’info, etc.).