如何在Pygame中以低速和闪烁的小角度绘制移动圆圈? [英] How to draw a moving circle in Pygame with a small angle at a low speed and blinking?
问题描述
下面的代码在屏幕上移动两个球.第一个以 10 度的角度低速移动,具有良好的绘图质量.第二个球以 1 度的角度移动,为了尊重这个角度,速度必须高得多,并且闪烁很多,绘图不令人满意.有没有办法减慢第二个球的绘制速度,避免过度闪烁?
The code below moves two balls on the screen. The first one is moved with an angle of 10 degree at a low speed with a good drawing quality. The second ball is moved with an angle of 1 degree and in order for the angle to be respected, the speed must be much higher and the drawing is unsatisfactory with a lot of blinking. Is there a way to slow down the drawing of the second ball and avoid the excessive blinking ?
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)
推荐答案
问题是造成的,因为 pygame.Rect
存储积分坐标:
The issue is caused, because pygame.Rect
stores integral coordinates:
Rect 对象的坐标都是整数.[...]
The coordinates for Rect objects are all integers. [...]
delta_x
和 delta_y
的小数部分在 self.rect.move(delta_x, delta_y)
处丢失.
The fraction component of delta_x
and delta_y
is lost at self.rect.move(delta_x, delta_y)
.
您必须使用浮点数进行计算.添加一个属性 self.pos
,它是一个包含 2 个组件的 tupe,用于存储球的中心点:
You have to use floating point numbers for the computation. Add an attribute self.pos
, which is a tupe with 2 components an stores the center point of a ball:
self.pos = self.rect.center
计算具有最大浮点精度的位置:
Compute the position with the maximum floating point accuracy:
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()
ed 位置.
Update the self.rect.center
by the round()
ed position.
self.rect.center = round(self.pos[0]), round(self.pos[1])
self.pos
是内部"位置并负责位置的精确计算.self.rect.center
是积分位置,负责拉球.self.pos
在每一帧中都略有变化.self.rect.center
仅当坐标的 a 分量改变了 1 时才会改变.
self.pos
is the "internal" position and responsible for the exact computation of the position. self.rect.center
is the integral position and responsible to draw the ball. self.pos
slightly changes in each frame. self.rect.center
changes only if the a component of the coordinate has changed by 1.
类球
:
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()
) 并按相同比例降低速度.这会导致平稳移动而不会眨眼.
With this solution you can scale up the flops per second (clock.tick()
) and scale down the speed by the same scale. This leads to a smooth movement without blinking.
这篇关于如何在Pygame中以低速和闪烁的小角度绘制移动圆圈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!