You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot 4.2 C#:加载Packed Scene后Ready信号未触发问题咨询

Godot 4.2 C# 场景切换后Setup方法未触发的原因与解决办法

问题原因

Root节点的Ready信号仅在游戏启动时触发一次——也就是主场景加载完成、整个初始化流程结束时发射。SceneOne在自身_Ready中订阅了这个信号,所以能正常触发Setup;但切换到SceneTwo时,Root已经完成初始化,不会再次发射Ready信号,因此SceneTwo订阅的Setup方法不会被调用。

从你的输出日志也能验证这一点:只有SceneOne的Scene 1 Ready和Scene 1 In Setup被打印,SceneTwo的对应日志完全没出现,说明Root的Ready信号没有再次触发。

解决方案

方案1:直接在场景自身的_Ready中调用Setup

场景节点的_Ready方法本身就是场景加载完成、节点树就绪后的回调,完全可以替代Root的Ready信号来触发初始化逻辑。修改代码如下:

SceneOne.cs 修改后

using Godot;

public partial class SceneOne : Node3D
{
    [Export]
    private string _SceneTwoPackedPath;
    private PackedScene _SceneTwoPacked;

    public override void _Ready()
    {
        _SceneTwoPacked = ResourceLoader.Load<PackedScene>(_SceneTwoPackedPath);

        GD.Print("Scene 1 In Ready");
        // 直接调用Setup,无需订阅Root的Ready信号
        Setup();
        GD.Print("Scene 1 Almost Ready");
    }

    public override void _Process(double delta)
    {
        GD.Print("Scene 1 Processing");
    }

    public void Setup()
    {
        GD.Print("Scene 1 Ready");
        GD.Print("Scene 1 In Setup");
        GetTree().ChangeSceneToPacked(_SceneTwoPacked);
    }
}

SceneTwo.cs 修改后

using Godot;

public partial class SceneTwo : Node3D
{
    [Export]
    private PackedScene _SceneOnePacked;

    public override void _Ready()
    {
        GD.Print("Scene 2 In Ready");
        // 直接调用Setup
        Setup();
        GD.Print("Scene 2 Almost Ready");
    }

    public override void _Process(double delta)
    {
        GD.Print("Scene 2 Processing");
    }

    public void Setup()
    {
        GD.Print("Scene 2 Ready");
        GD.Print("Scene 2 In Setup");
        
        GetTree().ChangeSceneToPacked(_SceneOnePacked);
    }
}

方案2:自定义信号传递关卡数据(适配你的关卡随机化需求)

如果需要在加载场景(SceneOne)计算完关卡数据后,传递给游戏场景(SceneTwo)初始化,可以通过公共属性实现:

  1. 在SceneTwo中定义公共属性接收关卡数据:
public partial class SceneTwo : Node3D
{
    // 用于接收加载场景传递的关卡数据
    public Dictionary<string, object> LevelData { get; set; }

    public override void _Ready()
    {
        GD.Print("Scene 2 In Ready");
        Setup();
        GD.Print("Scene 2 Almost Ready");
    }

    public void Setup()
    {
        GD.Print("Scene 2 Ready");
        GD.Print("Scene 2 In Setup");
        // 使用LevelData还原关卡
        if (LevelData != null)
        {
            GD.Print($"还原关卡数据:{LevelData}");
        }
    }
}
  1. 在SceneOne的Setup中切换场景时传递数据:
public void Setup()
{
    GD.Print("Scene 1 Ready");
    GD.Print("Scene 1 In Setup");
    // 随机生成关卡数据
    var levelData = new Dictionary<string, object>
    {
        ["EnemyCount"] = GD.RandRange(5, 15),
        ["MapSeed"] = GD.RandSeed()
    };
    // 实例化场景并传递数据
    var sceneTwoInstance = _SceneTwoPacked.Instantiate<SceneTwo>();
    sceneTwoInstance.LevelData = levelData;
    GetTree().ChangeSceneToNode(sceneTwoInstance);
}

方案3:全局单例管理器(更适合复杂关卡系统)

创建一个全局的LevelManager单例,负责存储和管理关卡数据:

  1. 创建LevelManager.cs:
using Godot;

public partial class LevelManager : Node
{
    public static LevelManager Instance { get; private set; }
    public Dictionary<string, object> CurrentLevelData { get; set; }

    public override void _Ready()
    {
        if (Instance == null)
        {
            Instance = this;
            // 保持节点不被销毁
            DontDestroyOnLoad(this);
        }
        else
        {
            QueueFree();
        }
    }
}
  1. 在SceneOne中生成数据并存入管理器:
public void Setup()
{
    GD.Print("Scene 1 Ready");
    GD.Print("Scene 1 In Setup");
    // 生成随机关卡数据
    var levelData = new Dictionary<string, object>
    {
        ["EnemyCount"] = GD.RandRange(5, 15),
        ["MapSeed"] = GD.RandSeed()
    };
    LevelManager.Instance.CurrentLevelData = levelData;
    GetTree().ChangeSceneToPacked(_SceneTwoPacked);
}
  1. 在SceneTwo的Setup中读取数据:
public void Setup()
{
    GD.Print("Scene 2 Ready");
    GD.Print("Scene 2 In Setup");
    var levelData = LevelManager.Instance.CurrentLevelData;
    if (levelData != null)
    {
        GD.Print($"还原关卡数据:{levelData}");
    }
}

适配关卡随机化的建议

如果你的关卡随机化逻辑比较复杂,推荐使用全局单例管理器的方案:

  • 加载场景专注于数据计算和资源预加载,完成后切换到游戏场景
  • 游戏场景从管理器中读取数据,完成关卡还原
  • 这种解耦方式更便于扩展,比如后续添加关卡保存、难度调整等功能

内容的提问来源于stack exchange,提问作者Stephen Hyberger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:49:52