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

Godot 4 Checkpoint存档加载问题:重启无法从最近 checkpoint 续玩

Godot 2D游戏存档点系统问题修复

问题描述

我是游戏开发新手,正在用Godot开发首款2D游戏以熟悉平台功能。调试Checkpoint存档系统时遇到日志提示:'Checkpoint file does not exist',期望实现的核心功能是:关闭游戏重启后点击“开始”按钮,玩家能从最近到达的Checkpoint位置继续游戏。

核心问题分析

  1. 存档加载逻辑错误:globals.gd的load_checkpoint_from_file函数中,错误地将current_checkpoint(原本应为节点引用)赋值为Vector2类型的位置数据,导致后续调用current_checkpoint.global_position时出现类型错误,同时重启游戏后节点已不存在,无法直接引用。
  2. 场景切换与玩家位置赋值顺序错误:title_screen.gd中先设置Globals.player.position再切换场景,此时玩家节点尚未在目标场景中实例化,赋值操作无效。
  3. 退出保存机制不可靠:依赖_exit_tree处理退出保存,在直接关闭窗口等场景下可能无法触发,导致存档丢失。
  4. 首次启动日志误解:首次启动时无存档文件,打印的Checkpoint file does not exist是正常调试日志,并非报错,但需确保不影响游戏流程。

代码修复方案

1. 修改globals.gd(全局存档逻辑)

调整变量存储逻辑,区分运行时节点引用与持久化存档数据,同时优化退出保存机制:

extends Node

var player = null
var current_checkpoint = null  # 运行时的存档点节点引用
var saved_checkpoint_scene: String = ""  # 持久化的存档场景路径
var saved_checkpoint_position: Vector2 = Vector2.ZERO  # 持久化的存档位置
var checkpoint_save_path = "user://checkpoint.sav"

func _ready():
    print("Globals script ready")
    load_checkpoint_from_file()

# 用窗口退出通知替代_exit_tree,确保保存触发更可靠
func _notification(what):
    if what == NOTIFICATION_WM_QUIT_REQUEST:
        save_checkpoint()
        get_tree().quit()

func respawn_player():
    if player != null and saved_checkpoint_position != Vector2.ZERO:
        player.position = saved_checkpoint_position

func load_checkpoint():
    # 基于持久化数据返回存档信息,而非运行时节点
    if saved_checkpoint_scene != "":
        return {
            "position": saved_checkpoint_position,
            "scene": saved_checkpoint_scene
        }
    return null

func save_checkpoint():
    if current_checkpoint != null:
        saved_checkpoint_scene = get_tree().current_scene.get_path()
        saved_checkpoint_position = current_checkpoint.global_position
        var file = FileAccess.open(checkpoint_save_path, FileAccess.WRITE)
        if file:
            file.store_pascal_string(saved_checkpoint_scene)
            file.store_var(saved_checkpoint_position)
            file.close()
            print("Checkpoint saved: ", saved_checkpoint_scene, saved_checkpoint_position)
        else:
            print("Error opening file for writing")

func load_checkpoint_from_file():
    if not FileAccess.file_exists(checkpoint_save_path):
        print("Checkpoint file does not exist (首次启动或无存档)")
        return
    
    var file = FileAccess.open(checkpoint_save_path, FileAccess.READ)
    if file:
        saved_checkpoint_scene = file.get_pascal_string()
        saved_checkpoint_position = file.get_var() as Vector2
        file.close()
        print("Checkpoint loaded: ", saved_checkpoint_scene, saved_checkpoint_position)
    else:
        print("Error opening file for reading")

2. 修改title_screen.gd(标题场景逻辑)

调整场景切换与玩家位置赋值顺序,确保玩家节点实例化后再设置位置:

extends Control

func _ready():
    pass

func _on_start_btn_pressed():
    var checkpoint_data = Globals.load_checkpoint()
    if checkpoint_data != null:
        # 先切换到存档场景
        var scene_change_result = get_tree().change_scene_to_file(checkpoint_data.scene)
        if scene_change_result == OK:
            # 等待场景加载完成,确保玩家节点已实例化
            await get_tree().idle_frame
            if Globals.player != null:
                Globals.player.position = checkpoint_data.position
    else:
        get_tree().change_scene_to_file("res://levels/world_01.tscn")

func _on_new_btn_pressed():
    get_tree().change_scene_to_file("res://levels/world_01.tscn")

func _on_credits_btn_pressed():
    pass

func _on_quit_btn_pressed():
    Globals.save_checkpoint()
    get_tree().quit()

3. 其他代码无需修改

checkpoint.gd、world.gd、player.gd等文件的逻辑保持不变,因为运行时的存档点节点引用逻辑是正常的,仅需调整全局存档的持久化与加载逻辑。

验证步骤

  1. 运行游戏,到达任意存档点,触发存档(控制台会打印保存日志)。
  2. 关闭游戏后重启,点击“开始”按钮,玩家会直接出现在之前的存档点位置。
  3. 首次启动游戏时,控制台会打印Checkpoint file does not exist (首次启动或无存档),但游戏会正常进入初始场景,无功能影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:43:09