600T

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 Area2D avec CollisionShape2D ;
    • une ressource PackedScene (en gros : sauvegarder une scène et l’exporter dans un script).

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.gd

1.1. Main.tscn (scène principale)

  • Racine : Node2D (nom : Main).
  • Enfant : Node (nom : MultiverseManager) avec le script MultiverseManager.gd.
  • Enfant : CanvasLayer (nom : par ex. UI) contenant un Label (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 Node2D nommé Spawn à l’endroit où le joueur doit apparaître ;
  • un Area2D nommé Portal (avec CollisionShape2D) pour changer d’univers, avec le script Portal.gd.

Exemple :

UniversA (Node2D)
├── Spawn (Node2D)
└── Portal (Area2D) [Portal.gd]
    └── CollisionShape2D

Même structure pour UniversB.tscn (avec éventuellement un décor différent).

1.3. Scène du joueur : Player.tscn

  • Racine : CharacterBody2D ou Node2D (nom : Player),
  • Script : Player.gd pour 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_universe

2.1. À configurer dans l’éditeur

Dans l’inspecteur de MultiverseManager :

  • univers_scenes → ajoute UniversA.tscn, UniversB.tscn, etc.
  • player_scene → assigne Player.tscn.
  • ui_label_path → sélectionne ton UniverseLabel (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.tscn doit s’appeler Main.
  • Le node avec le script MultiverseManager.gd doit s’appeler MultiverseManager.
  • Dans l’éditeur, connecte le signal body_entered de Portal à 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 :

  1. Dans Portal.gd, stocker le fait que le joueur est dedans.
  2. 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 :

  • CanvasLayerUI

    • LabelUniverseLabel

Tu peux aussi ajouter :

  • un Label pour la vie (HPLabel) ;
  • des boutons (Button) pour tester les changements d’univers sans portail (en connectant pressed() à teleport_to_next() ou teleport_to_previous()).

Actions clavier suggérées

Dans Project Settings → Input Map, ajoute :

  • ui_accept → touche E ou Enter (activer un portail) ;
  • ui_left / ui_right / ui_up / ui_down si 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 :

  1. 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 ».
  2. É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.
  3. 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.

  4. Passage en 3D

    • Remplace Node2D / CharacterBody2D par Node3D / CharacterBody3D.
    • Remplace Area2D par Area3D et CollisionShape2D par CollisionShape3D.

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.).