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

Pygame中鼠标移动Surface抖动问题及替代实现方法咨询

Pygame Surface拖动抖动问题解决

问题描述

在Pygame中尝试通过鼠标移动磁盘图片表示的Surface,按空格键激活拖动功能,但拖动时Surface剧烈抖动,当前使用event.rel获取相对移动的方式存在问题,需要正确的实现方法。

用户原代码:

import sys
import pygame
from pygame.locals import *

WINDOW_SIZE = (600, 400)
FPS = 60


class System:
    def __init__(self, screen, surface):
        self.screen = screen
        self.surface = pygame.transform.scale(surface, (WINDOW_SIZE[0] * 2, WINDOW_SIZE[1] * 2))
        self.clock = pygame.time.Clock()

    def run(self):
        running = True
        moving = False
        offset_x = 0
        offset_y = 0

        while running:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        sys.exit()
                    if event.key == pygame.K_SPACE:
                        mouse_pos = pygame.mouse.get_pos()
                        if self.surface.get_rect().collidepoint(mouse_pos):
                            moving = True
                elif event.type == pygame.KEYUP:
                    moving = False
                elif event.type == MOUSEMOTION and moving:
                    offset_x = event.rel[0]
                    offset_y = event.rel[1]
                elif event.type == MOUSEWHEEL:
                    offset_y -= event.y * 50

            self.screen.fill((105, 212, 229))

            self.screen.blit(self.surface, (offset_x, offset_y))

            pygame.display.update()
            self.clock.tick(FPS)


def run_system(screen, surface):
    system = System(screen, surface)
    system.run()


pygame.init()
screen = pygame.display.set_mode(WINDOW_SIZE, 0, 32)
surface = pygame.image.load('image.png')

if __name__ == '__main__':
    run_system(screen, surface)

问题原因

  1. 使用event.rel直接赋值给offset_x/offset_y,而非累加偏移,导致每次移动都会重置Surface位置,引发抖动。
  2. 碰撞检测时,self.surface.get_rect()默认以(0,0)为左上角,未考虑当前Surface的实际偏移位置,可能导致激活拖动的判断不准确。
  3. 未记录拖动开始时鼠标与Surface的相对位置,拖动时Surface会直接跳转到鼠标位置,产生抖动。

解决方案

修改run方法,记录拖动初始时的鼠标位置与Surface偏移,基于当前鼠标位置计算Surface的新位置:

import sys
import pygame
from pygame.locals import *

WINDOW_SIZE = (600, 400)
FPS = 60


class System:
    def __init__(self, screen, surface):
        self.screen = screen
        self.surface = pygame.transform.scale(surface, (WINDOW_SIZE[0] * 2, WINDOW_SIZE[1] * 2))
        self.clock = pygame.time.Clock()

    def run(self):
        running = True
        moving = False
        offset_x = 0
        offset_y = 0
        # 记录拖动时鼠标相对于Surface的偏移
        drag_dx = 0
        drag_dy = 0

        while running:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        sys.exit()
                    if event.key == pygame.K_SPACE:
                        mouse_x, mouse_y = pygame.mouse.get_pos()
                        # 获取Surface当前位置的rect
                        surface_rect = self.surface.get_rect(topleft=(offset_x, offset_y))
                        if surface_rect.collidepoint(mouse_x, mouse_y):
                            moving = True
                            # 计算鼠标在Surface上的相对位置
                            drag_dx = mouse_x - offset_x
                            drag_dy = mouse_y - offset_y
                elif event.type == pygame.KEYUP:
                    moving = False
                elif event.type == MOUSEMOTION and moving:
                    # 根据当前鼠标位置和相对偏移,计算Surface新位置
                    offset_x = event.pos[0] - drag_dx
                    offset_y = event.pos[1] - drag_dy
                elif event.type == MOUSEWHEEL:
                    offset_y -= event.y * 50

            self.screen.fill((105, 212, 229))
            self.screen.blit(self.surface, (offset_x, offset_y))
            pygame.display.update()
            self.clock.tick(FPS)


def run_system(screen, surface):
    system = System(screen, surface)
    system.run()


pygame.init()
screen = pygame.display.set_mode(WINDOW_SIZE, 0, 32)
surface = pygame.image.load('image.png')

if __name__ == '__main__':
    run_system(screen, surface)

关键修改点

  • 激活拖动时,通过surface_rect = self.surface.get_rect(topleft=(offset_x, offset_y))获取Surface当前位置的rect,确保碰撞检测准确。
  • 记录drag_dx和drag_dy,即鼠标点击位置与Surface左上角的偏移,避免拖动时Surface跳转到鼠标位置。
  • MOUSEMOTION事件中,用event.pos[0] - drag_dx计算新的offset_x,保证Surface跟随鼠标平滑移动,而非重置位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:50:46