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

如何在高效viewport滚动中正确适配右侧菜单,避免全量Blit?

优化平滑滚动时右侧菜单的绘制问题

我写了一个函数实现平滑滚动,不想每帧全量blit整个屏幕。这个函数通过blit滚动到viewport(位于(0,0),尺寸640×640像素)内的右侧菜单部分来做补偿。现在用的Surface是680×680的,出于性能考虑不能每帧都blit整个viewport,请问怎么正确处理右侧菜单?

用户提供的原始代码:

def optimized_blit(source, dest, position,frametime,xt=0,xtd=0):
    global phash,phashx
#     
#     if viewportx.__class__.__name__ == 'str':
#         viewportx = viewport.Viewport(position[0],position[1],source,dest)
    
#         viewportx.sc(position[0],position[1])
    if (frametime%4)==1 or xt==1:
        source.set_alpha(255)
        #dest.blit(source,position)
        phash = position
        dest.blit(source,position)
    elif not xt==1:
        if not str(phash) == str(position):
            #new_position = ( phash[0]-position[0] , position[1] - phash[1])
            #visible_width = min(680 - new_position[0], 680)
            #ufr = 640-(position[0]-phash[0])
            #sca = position[0] - phash[0]
            x_p = min((640-position[0])-5,679)
            y_p = 0
            rect = (x_p,y_p,5,640)
            dest.scroll(position[0] - phash[0], position[1] - phash[1])
            print(rect)
            #print
            if x_p>0 and y_p>0:
                #time.sleep(0.1)
                print(rect)
                dest.blit(source.subsurface(rect),(635,0))
                print()

        
            phash = position
            xtract = [640-position[0],680-phash[0]]
            #print(xtract)
        #print(phash)
    #positionx = [int(i) for i in position]
    #if not phas
    if  xtd:
         phashx = position
         phash = position
         #phash = position
         #print(position)
         dest.blit(source,position)
#viewportx.draw(dest)

问题分析与修正方案

你的核心思路没问题:用dest.scroll()移动已有内容,只补画新露出的区域来节省性能。但当前实现存在滚动方向搞反、区域计算错误、无效条件判断等问题,修正后可以正确处理右侧菜单:

关键修正点

  1. 修正滚动方向
    pygame的Surface.scroll(dx, dy)中,dx为正代表内容向左移动(右侧留空),dx为负代表内容向右移动(左侧留空)。你的代码里滚动方向和position偏移逻辑相反,需要调整为dest.scroll(-dx, -dy)(dx是当前position与上一帧position的差值)。

  2. 准确计算补画区域
    右侧菜单是source中x从640到680的40像素宽度区域,向左滚动时,viewport右侧会露出新的菜单内容,需要截取对应宽度的菜单区域补画到dest右侧;向右滚动时则补画source左侧区域。

  3. 去掉无效判断
    不要用str(phash) == str(position)比较位置,直接用元组相等判断phash != position更高效;同时删除x_p>0 and y_p>0的错误条件(菜单y从0开始,y_p=0时应该正常绘制)。

修正后的完整代码

def optimized_blit(source, dest, position, frametime, xt=0, xtd=0):
    global phash, phashx
    # 初始化上一帧位置(第一次调用时)
    if 'phash' not in globals():
        phash = position

    # 全量绘制触发条件:定时刷新、强制刷新标记、xtd标记
    if (frametime % 4) == 1 or xt == 1 or xtd:
        phash = position
        dest.blit(source, position)
        if xtd:
            phashx = position
        return

    # 位置未变化时无需操作
    if phash == position:
        return

    # 计算滚动偏移量
    dx = position[0] - phash[0]
    dy = position[1] - phash[1]

    # 滚动已有内容,方向与position偏移相反
    dest.scroll(-dx, -dy)

    # 处理水平滚动的补画(重点处理右侧菜单)
    if dx < 0:
        # 向左滚动:补画source右侧的菜单区域
        blit_width = abs(dx)
        # 限制补画宽度不超过菜单总宽度40px
        blit_width = min(blit_width, 40)
        # 截取source中对应的菜单区域
        menu_subsurface = source.subsurface((640, 0, blit_width, 640))
        # 补画到viewport右侧的对应位置
        dest.blit(menu_subsurface, (640 - blit_width, 0))
    elif dx > 0:
        # 向右滚动:补画source左侧的内容区域(如果需要)
        blit_width = dx
        left_subsurface = source.subsurface((0, 0, blit_width, 640))
        dest.blit(left_subsurface, (0, 0))

    # 处理垂直滚动的补画(可选,根据需求调整)
    if dy < 0:
        blit_height = abs(dy)
        blit_height = min(blit_height, 40)
        bottom_subsurface = source.subsurface((0, 640, 640, blit_height))
        dest.blit(bottom_subsurface, (0, 640 - blit_height))
    elif dy > 0:
        blit_height = dy
        top_subsurface = source.subsurface((0, 0, 640, blit_height))
        dest.blit(top_subsurface, (0, 0))

    # 更新上一帧位置
    phash = position

额外优化建议

  • 避免使用全局变量phash,可以将其封装为类属性或函数的默认参数(如phash=None),减少副作用。
  • 提前缓存右侧菜单Surface:menu_surface = source.subsurface((640, 0, 40, 640)),每次补画直接使用缓存的Surface,避免重复截取subsurface。
  • 当滚动偏移量超过菜单宽度(40px)时,触发一次全量blit,避免多次补画累积显示错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:04:56