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

Pygame模拟帆船航行时矩形沿波浪旋转出现闪烁问题求助

问题原因分析
  • 绘制顺序错误:原代码先绘制船再绘制水面,水面的像素会覆盖船身下半部分,造成视觉闪烁
  • 角度计算参考值错误:计算左右水位时使用了旋转后的外接矩形rect的left/right属性,图像旋转后外接矩形宽高会动态变化,导致左右采样点位置不稳定,角度计算出现跳变
  • 位置更新逻辑顺序错误:先设置船的底部位置再执行旋转,旋转后外接矩形变化会导致之前设置的位置偏移,进一步加剧抖动
  • 水位采样取整误差:存储水位时提前转成整数,浮点精度损失导致高度差计算出现跳变
修复方案
  1. 调整绘制顺序:先绘制背景、水面,再绘制船,避免水面覆盖船身
  2. 固定角度采样点:用原始船宽计算相对于中心点的固定偏移量作为水位采样x坐标,不受旋转后外接矩形的影响
  3. 调整更新逻辑顺序:先计算角度、完成旋转,再统一设置船的位置
  4. 水位用浮点数存储,避免精度损失
修复后完整代码
import sys
import math
import pygame
from pygame.locals import *

pygame.init()
SCREEN_WIDTH = 900
SCREEN_HEIGHT = 900
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

clock = pygame.time.Clock()

BLUE = (0, 103, 247)
RED = (255,0,0)

# 改为存储浮点数水位
water_levels = [0.0 for _ in range(SCREEN_WIDTH)]
ORIGIN_SHIP_WIDTH = 80  # 固定原始船宽

def draw_water(surface, dy):
    amplitude = 35
    global water_levels
    for x in range(SCREEN_WIDTH):
        y = math.sin(x * 0.01) * amplitude + dy
        water_levels[x] = y
        pygame.draw.aaline(surface, BLUE, (x, int(y)), (x, int(y)))

def get_water_level(index):
    if index <= 0:
        return water_levels[0]
    if index >= SCREEN_WIDTH:
        return water_levels[-1]
    return water_levels[index]

font = pygame.font.Font(None,30)
def debug(info,x=10,y=10):
    display_surf = pygame.display.get_surface()
    debug_surface = font.render(str(info),True,'White')
    debug_rect = debug_surface.get_rect(topleft=(x,y))
    pygame.draw.rect(display_surf,'Black',debug_rect)
    display_surf.blit(debug_surface,debug_rect)

class Ship(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((ORIGIN_SHIP_WIDTH,80),pygame.SRCALPHA)
        self.image.fill('red')
        self.rect = self.image.get_rect(topleft=(0,0))
        self.copy_img = self.image.copy()
        self.move = pygame.math.Vector2(0,0)
        self.velocity = 8
        self.half_width = ORIGIN_SHIP_WIDTH / 2  # 半宽固定

    def rotate(self, angle):
        # 不用强行转int,角度可以是浮点数更平滑
        self.image = pygame.transform.rotate(self.copy_img, angle)
        self.rect = self.image.get_rect(center=self.rect.center)

    def update(self):
        self.get_input()
        cx = self.rect.centerx
        # 用固定偏移量取左右采样点
        left_x = cx - self.half_width
        right_x = cx + self.half_width
        left_y = get_water_level(int(left_x))
        right_y = get_water_level(int(right_x))
        angle = 180 * math.atan2(left_y - right_y, ORIGIN_SHIP_WIDTH) / math.pi
        debug("angle: "+str(int(angle)))
        # 先旋转
        self.rotate(angle)
        # 旋转后再统一设置底部位置为中心点水位
        self.rect.bottom = int(get_water_level(int(cx)))

    def replicate(self):
        if self.rect.left == 363:
            return
        self.rect.x += 1

    def get_input(self):
        self.replicate()
        # 原有键盘控制逻辑保留即可
        # keys = pygame.key.get_pressed()
        # if keys[K_LEFT]:
        #     self.move.x = -self.velocity
        # elif keys[K_RIGHT]:
        #     self.move.x = self.velocity
        # else:
        #     self.move.x = 0
        # if keys[K_UP]:
        #     self.move.y = -self.velocity
        # elif keys[K_DOWN]:
        #     self.move.y = self.velocity
        # else:
        #     self.move.y = 0
        # self.rect.x += self.move.x
        # self.rect.y += self.move.y
        # if self.rect.left <= 0:
        #     self.rect.left = 0
        # if self.rect.right >= SCREEN_WIDTH:
        #     self.rect.right = SCREEN_WIDTH


ship_sprite = pygame.sprite.GroupSingle()
ship_sprite.add(Ship())
while True:
    screen.fill((200,210,255,0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    ship_sprite.update()
    # 调整顺序:先画水再画船
    draw_water(screen,SCREEN_HEIGHT-300)   
    ship_sprite.draw(screen) 
    clock.tick(60)
    pygame.display.update()

内容的提问来源于stack exchange,提问作者Juan Álvarez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:15:03