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

如何在ggez中调整窗口大小且不造成绘制元素变形

ggez 调整窗口大小无变形实现方案

你当前调用的graphics::set_drawable_size并不是用来修改窗口尺寸的接口,它的作用是修改内部逻辑绘制区域的大小。直接调用它但不同步调整物理窗口、更新投影矩阵的话,必然会出现两个异常:

  • 设置的逻辑绘制区域宽高比和窗口实际物理宽高比不匹配,图形被拉伸,圆形变椭圆
  • 绘制区域尺寸和窗口尺寸不匹配,清屏操作无法覆盖整个窗口范围,旧帧内容残留形成残影

正确实现方式

根据你的需求选对应方案即可,都不会出现图形变形:

场景1:代码主动修改窗口大小

不要用set_drawable_size改窗口尺寸,直接调用winit窗口提供的接口修改物理窗口大小,ggez会自动同步更新投影矩阵,不会出现比例异常:

use ggez::winit::dpi::LogicalSize;

// 示例:将窗口调整为800*600尺寸
ctx.gfx.window().set_inner_size(LogicalSize::new(800.0, 600.0));

调用后不需要手动执行任何和drawable size相关的操作,ggez内部会自动对齐逻辑绘制尺寸和窗口物理尺寸。

场景2:允许用户拖拽窗口边缘自由调整大小

  1. 初始化窗口时先开启可调整大小的配置:
    use ggez::conf;
    
    let window_mode = conf::WindowMode::default().resizable(true);
    let (mut ctx, event_loop) = ggez::ContextBuilder::new("your_game", "your_name")
        .window_mode(window_mode)
        .build()?;
    
  2. 在事件处理的resize_event回调中同步更新屏幕坐标配置,可按需固定逻辑宽高比,从根源避免拉伸:
    fn resize_event(&mut self, ctx: &mut Context, width: f32, height: f32) -> GameResult {
        // 示例固定16:9逻辑宽高比,多余区域自动留边,不需要可以直接用传入的width/height作为绘制尺寸
        const TARGET_RATIO: f32 = 16.0 / 9.0;
        let current_ratio = width / height;
        let (draw_w, draw_h) = if current_ratio > TARGET_RATIO {
            (height * TARGET_RATIO, height)
        } else {
            (width, width / TARGET_RATIO)
        };
    
        // 设置绘制区域居中,适配当前窗口尺寸
        let screen_area = graphics::Rect::new(
            (width - draw_w) / 2.0,
            (height - draw_h) / 2.0,
            draw_w,
            draw_h
        );
        graphics::set_screen_coordinates(ctx, screen_area)?;
        Ok(())
    }
    
  3. 每帧绘制的第一步执行全画布清屏,彻底解决残影问题:
    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        // 用你需要的背景色清空整个帧缓冲,示例用黑色
        let mut canvas = graphics::Canvas::from_frame(ctx, graphics::Color::BLACK);
    
        // 后续正常写你的绘制逻辑即可,比如绘制白色圆形
        let circle = graphics::Mesh::new_circle(
            ctx,
            graphics::DrawMode::fill(),
            glam::Vec2::new(400.0, 300.0),
            100.0,
            2.0,
            graphics::Color::WHITE,
        )?;
        canvas.draw(&circle, glam::Vec2::ZERO);
    
        canvas.finish(ctx)?;
        Ok(())
    }
    

注意点

  • 非特殊渲染需求不要主动调用set_drawable_size,这个接口是给多渲染目标、离屏渲染这类场景用的,常规窗口大小调整用上面的方法就行
  • 只要保证逻辑绘制区域的宽高比和你设计的一致,就不会出现圆形变椭圆的拉伸问题
  • 每帧开头统一清屏是解决残影的最直接方式,不要依赖缓冲区默认的覆盖逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:21:31