首页 > 解决方案 > 如何在Pygame中画一个小角度低速闪烁的运动圆圈?

问题描述

下面的代码在屏幕上移动两个球。第一个以低速移动10度角,绘图质量好。第二个球以 1 度的角度移动,为了尊重角度,速度必须高得多,并且绘图不令人满意,并且闪烁很多。有没有办法减慢第二个球的绘制速度并避免过度眨眼?

import pygame, sys, math
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((1000, 600))
pygame.display.set_caption('Bouncing Ball with position and angle')

# Set our color constants
BLACK = (0, 0, 0)
YELLOW = (255, 255, 0)

# Create the ball class
class Ball():
    def __init__(self,
                 screen,
                 color,
                 radius,
                 startX,
                 startY,
                 speed,
                 angle=45):
        super().__init__()
        self.screen = screen
        self.color = color
        rectSize = radius * 2
        self.rect = pygame.Rect(startX, startY, rectSize, rectSize)
        self.speed = speed
        self.angle = math.radians(angle)

    def update(self):
        delta_x = self.speed * math.cos(self.angle)
        delta_y = self.speed * math.sin(self.angle)
        self.rect = self.rect.move(delta_x, delta_y)

        if self.rect.right >= self.screen.get_width() or self.rect.left <= 0:
            self.angle = math.pi - self.angle

        if self.rect.top <= 0 or self.rect.bottom >= self.screen.get_height():
            self.angle = -self.angle

    def draw(self):
        '''
        Draw our ball to the screen with position information.
        '''
        pygame.draw.circle(self.screen, self.color, self.rect.center, int(self.rect.width / 2))

# Create a new Ball instance named 'myball'
myball = Ball(screen=DISPLAYSURF, color=YELLOW, startX=100, startY=100, radius=150, speed=8, angle=10)
mySmaLlAngleball = Ball(screen=DISPLAYSURF, color=YELLOW, startX=100, startY=500, radius=150, speed=58, angle=-1)

run = True
clock = pygame.time.Clock()

# Display loop
while run:
    # Handle events
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    # Update ball position
    myball.update()
    mySmaLlAngleball.update()

    # Draw screen
    DISPLAYSURF.fill(BLACK)
    myball.draw()
    mySmaLlAngleball.draw()
    pygame.display.update()
    clock.tick(30)

标签: pythonpygame

解决方案


问题是由于pygame.Rect存储积分坐标引起的:

Rect 对象的坐标都是整数。[...]

delta_x和的分数分量在delta_y处丢失self.rect.move(delta_x, delta_y)

您必须使用浮点数进行计算。添加一个属性self.pos,它是一个包含 2 个组件的元组,用于存储球的中心点:

self.pos = self.rect.center

计算具有最大浮点精度的位置:

delta_x = self.speed * math.cos(self.angle)
delta_y = self.speed * math.sin(self.angle)
self.pos = (self.pos[0] + delta_x, self.pos[1] + delta_y)   

self.rect.centerround()ed位置更新。

self.rect.center = round(self.pos[0]), round(self.pos[1])

self.pos是“内部”位置,负责位置的精确计算。self.rect.center是积分位置,负责拉球。self.pos每一帧都有细微的变化。self.rect.center仅当坐标的 a 分量已更改 1 时才更改。

Ball

class Ball():
    def __init__(self,
                 screen,
                 color,
                 radius,
                 startX,
                 startY,
                 speed,
                 angle=45):
        super().__init__()
        self.screen = screen
        self.color = color
        rectSize = radius * 2
        self.rect = pygame.Rect(startX, startY, rectSize, rectSize)
        self.speed = speed
        self.angle = math.radians(angle)
        self.pos = self.rect.center

    def update(self):
        delta_x = self.speed * math.cos(self.angle)
        delta_y = self.speed * math.sin(self.angle)
        self.pos = (self.pos[0] + delta_x, self.pos[1] + delta_y)

        self.rect.center = round(self.pos[0]), round(self.pos[1])

        if self.rect.right >= self.screen.get_width() or self.rect.left <= 0:
            self.angle = math.pi - self.angle

        if self.rect.top <= 0 or self.rect.bottom >= self.screen.get_height():
            self.angle = -self.angle

    def draw(self):
        '''
        Draw our ball to the screen with position information.
        '''
        pygame.draw.circle(self.screen, self.color, self.rect.center, int(self.rect.width / 2))

使用此解决方案,您可以扩大每秒的触发器 ( clock.tick()) 并按相同的比例缩小速度。这会导致流畅的运动而不会眨眼。


推荐阅读