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

Raylib_cs加载字体到静态类成员后程序异常终止问题排查

问题

我在Raylib的C#绑定(Raylib_cs)中尝试将字体加载到静态类的成员对象中,目标是通过单一命名空间的静态类实现项目全局访问。我使用Newtonsoft.Json库反序列化对象,由于直接反序列化到静态类存在困难,采用了如下实现方案:

using Raylib_cs;
using Newtonsoft.Json;
using System.Runtime.Serialization;
namespace Game.Configs
{
    public static class Configuration
    {
        /*Debug config*/
        private static DebugConfig? _debug;
        public static DebugConfig Debug => _debug!;

        /*Graphics config*/
        private static GraphicsConfig? _graphics;
        public static GraphicsConfig Graphics => _graphics!;
        

        public static void Load(string Path)
        {
            try
            {
                _debug = JsonConvert.DeserializeObject<DebugConfig>(File.ReadAllText($"{Path}dbg.json"))!;
                _graphics = JsonConvert.DeserializeObject<GraphicsConfig>(File.ReadAllText($"{Path}gfx.json"))!;
            }
            catch (Exception e)
            {
                // Log the exception
                Console.WriteLine($"Exception during deserialization: {e}");
            }

        }
    }
    //these classes are in separate source files, but within the same namespace so I added them here
    public class DebugConfig
    {
        public string? FontPath {get; set;}
        [JsonIgnore]
        public Font DebugFont {get;set;}
        [OnDeserialized]
        internal void OnDeserializedMethod(StreamingContext context)
        {
            if(!string.IsNullOrEmpty(FontPath))
                DebugFont = Raylib.LoadFont(FontPath);
        }
    }
    public class GraphicsConfig
    {
        public  string? Title {get; set;}
        public  V2Di Resolution {get;set;}
        public  bool Windowed {get;set;}
        public  byte Framerate {get;set;}
    }
}

Game类实现如下:

partial class Game
{
    public Game()
    {
        Configuration.Load("res/cfg/");
    }
    public void Initialize()
    {
        Raylib.InitWindow(Configuration.Graphics.Resolution.X,Configuration.Graphics.Resolution.Y,Configuration.Graphics.Title);
        if(!Configuration.Graphics.Windowed && !Raylib.IsWindowFullscreen())
            Raylib.ToggleFullscreen();
        Raylib.SetTargetFPS(Configuration.Graphics.Framerate);
        Start();
    }
}

程序入口首先调用Game构造函数,调试时,Raylib报告字体加载成功后程序立即终止,输出:

INFO: FILEIO: [res/fnt/_stmr.ttf] File loaded successfully
The program '[24301] rayNet' has exited with code 0 (0x0).

将字体加载到Game类的静态变量(public static Font ttfTest = Raylib.LoadFont("res/fnt/_stmr.ttf");)可正常运行,Configuration.Graphics的加载与使用也符合预期。注释掉Configuration类中_debug = JsonConvert.DeserializeObject<DebugConfig>(File.ReadAllText($"{Path}dbg.json"))!;这一行后,程序可正常启动。编译无警告,终止时无异常抛出,请问为何Configuration.Graphics正常而Configuration.Debug会导致程序终止?

分析与解决

核心原因

Raylib的字体加载依赖已初始化的图形上下文,但你在Game构造函数中调用Configuration.Load()时,Raylib.InitWindow()还未执行——此时图形窗口和OpenGL上下文都未创建,直接调用Raylib.LoadFont()会触发Raylib内部的断言失败或上下文错误,导致程序静默终止。

你把字体加载放到Game类静态变量中能正常运行,是因为静态变量的初始化时机晚于窗口初始化(或刚好在窗口初始化之后);而DebugConfig的OnDeserialized方法在反序列化时立即执行,此时窗口还未创建,图形环境不具备加载字体的条件。Configuration.Graphics仅加载配置数据,不涉及图形资源操作,因此不受影响。

解决方案

  1. 调整字体加载时机:将字体加载逻辑从反序列化回调中移出,放到窗口初始化完成之后。
    修改DebugConfig类:

    public class DebugConfig
    {
        public string? FontPath {get; set;}
        [JsonIgnore]
        public Font DebugFont {get; private set;}
    
        // 新增加载方法,在窗口初始化后调用
        public void LoadFont()
        {
            if(!string.IsNullOrEmpty(FontPath) && !DebugFont.IsReady)
                DebugFont = Raylib.LoadFont(FontPath);
        }
    }
    

    然后在Game.Initialize()中补充调用:

    public void Initialize()
    {
        Raylib.InitWindow(Configuration.Graphics.Resolution.X,Configuration.Graphics.Resolution.Y,Configuration.Graphics.Title);
        // 窗口初始化完成后加载字体
        Configuration.Debug.LoadFont();
        
        if(!Configuration.Graphics.Windowed && !Raylib.IsWindowFullscreen())
            Raylib.ToggleFullscreen();
        Raylib.SetTargetFPS(Configuration.Graphics.Framerate);
        Start();
    }
    
  2. 清理无效回调:删除DebugConfig中的[OnDeserialized]标记和对应的OnDeserializedMethod方法,避免在图形上下文未就绪时触发资源加载。

  3. 补充资源释放:程序退出时调用Raylib.UnloadFont(Configuration.Debug.DebugFont),防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:25:11