You need to enable JavaScript to run this app. pygame.Surface.set_at()在for循环中的工作逻辑与失效排查
优惠活动
大模型
产品
解决方案
定价
更多

pygame.Surface.set_at()在for循环中的工作逻辑与失效排查

问题根因
  • 坐标值完全错位:存在SelectRect实例里的x、y是屏幕放大绘制用的画布坐标,不是32x32导出Surface需要的像素索引坐标。
    假设TILE_SIZE=16,创建网格时第1个格子传入的x是0*16=0,第2个是1*16=16,第32个是31*16=496。但export_surf尺寸只有32x32,合法坐标范围是0~31,把16、496这类超出范围的值传给set_at,方法会直接静默忽略,不会写入任何像素。之前尝试用半径1的圆绘制也没效果,本质是同一个原因,传入的坐标完全不在Surface的范围内。
  • 边界越界的无效调用:初始化时写的export_surf.set_at((32, 32), CYAN),32已经超出32x32 Surface的最大坐标(索引从0开始,最大合法值是31),这行代码完全不会生效。
  • 导出逻辑不全:原代码只遍历selected_rects写入像素,没有选中的格子会保留Surface默认的纯黑底色,容易误判为写入失败。
修复步骤
  1. 拆分存储两类坐标,把用于导出的网格索引和用于屏幕绘制的放大坐标分开存
    修改SelectRect类的初始化方法,新增属性存0~31的网格索引:
    class SelectRect:
        def __init__(self, xpos: int, ypos: int, w: int, h: int, rect_colour: tuple or list, grid_x: int, grid_y: int):
            self.rect = pygame.Rect(xpos, ypos, w, h)
            self.colour = rect_colour
            # 保留原属性用于屏幕绘制
            self.x = xpos
            self.y = ypos
            # 新增网格索引,用于导出Surface
            self.grid_x = grid_x
            self.grid_y = grid_y
    
        def render(self, surf):
            pygame.draw.rect(surf, self.colour, self.rect)
    
    修改网格创建逻辑,把循环索引传入作为网格坐标:
    rects = []
    for y_idx in range(32):
        for x_idx in range(32):
            draw_x = x_idx * TILE_SIZE
            draw_y = y_idx * TILE_SIZE
            rects.append(SelectRect(
                draw_x, draw_y,
                TILE_SIZE, TILE_SIZE,
                None,
                grid_x=x_idx, grid_y=y_idx
            ))
    
  2. 修正导出逻辑的坐标和Surface初始化
    删除原来越界的export_surf.set_at((32, 32), CYAN)代码,修改e键触发的导出逻辑:
    if event.key == pygame.K_e:
        # 如需透明背景,加SRCALPHA参数创建带alpha通道的Surface
        export_surf = pygame.Surface((32, 32), pygame.SRCALPHA)
        # 遍历所有网格矩形写入像素,不要只遍历selected_rects
        for rect in rects:
            if rect.colour is not None:
                export_surf.set_at((rect.grid_x, rect.grid_y), rect.colour)
        # 导出为文件的话加这行即可
        pygame.image.save(export_surf, "pixel_art.png")
    
  3. 验证显示效果
    原代码直接把32x32的export_surfblit在屏幕(0,0)位置,因为尺寸太小很难观察,可以临时加缩放显示确认写入是否成功:
    scaled_export = pygame.transform.scale(export_surf, (128, 128))
    screen.blit(scaled_export, (0, 0))
    
注意事项
  • set_at()的工作逻辑是:传入(x,y)像素坐标和颜色值,直接修改Surface内部对应位置的像素内存值,没有内置边界校验,超出范围的坐标不会抛出任何错误,会被直接跳过,使用时必须自行确认坐标合法。
  • Surface宽高为W、H时,合法x范围是0~W-1,合法y范围是0~H-1。
  • 不要把屏幕绘制用的放大坐标直接传给导出Surface的绘制方法,两类坐标必须完全分开存储。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 04:36:04