我正在创建一个基于圆形的鼓机,需要类似雷达的线以速度调制的速度旋转,周期等于每次测量的节拍。这样它以速度旋转,并在一个测量的等效持续时间内完成旋转。
我很难用代数建模。根据我的想法:
每次拍子秒= 60秒/每分钟
60secs/120bpm = .5spb
Spb * bbpm(每次测量的节拍)产生spm(每次测量的秒数)。
.5bps * 4bbpm = 2spm
这就是我被困住的地方。我知道在2秒内线路需要转动360度才能完成四拍。我很难将其建模,而不是将其提交给代码。
我开始猜测的是将帧速率除以spm以产生每秒测量的帧数。然而,我试图将其除以360来确定每次测量每帧每秒的度数,但与真正的节拍器相比,我的嘀嗒臂是不准确的。
任何见解都将不胜感激。
我的代码:
import pygame
from pygame.locals import *
import math
SIZE = 800, 800
pygame.init()
screen = pygame.display.set_mode(SIZE)
clock = pygame.time.Clock()
framerate = 40
done = False
bpm = int(input("Enter a BPM: ")) #beats per minute
bbpm = int(input("How many Beats Per Measure?: ")) #beats per measure
spb = (60/bpm)
spm = spb*bbpm #speed per measure; a measure is made every x seconds
frames = (framerate/spm)
rev = 360/frames # degrees per frame
deg = 0
secs = 0
while not done:
screen.fill(0)
for e in pygame.event.get():
if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE):
done = True
break
line = (400,400)
line_len = 400
x = line[0] + math.cos(math.radians(deg)) * line_len
y = line[1] + math.sin(math.radians(deg)) * line_len
# then render the line ->(x,y)
pygame.draw.line(screen, Color("red"), line, (x,y), 1)
pygame.display.flip()
print(secs)
print(deg)
deg+=rev
secs+= 1
clock.tick(framerate)
答案 0 :(得分:0)
1)在运动渲染中,永远不要依赖于硬编码帧速率或每帧的任何恒定速度。测量自某个参考位置起的时间增量(例如,在这种情况下,自上次转弯或初始化)并根据时间增量计算当前位置。即使使用vsync,您也可能会错过一些帧,帧速率并不总是等于60。
2)不要根据假设的帧率同步渲染延迟,而是使用硬件vsync(在这种情况下使用pygame.display.set_mode(..., pygame.HWSURFACE | pygame.DOUBLEBUF)
)
你的测量计算似乎是正确的。没有必要以度为单位将转数转换为弧度。
更正示例:
import pygame
from pygame.locals import *
import math
SIZE = 800, 800
pygame.init()
screen = pygame.display.set_mode(SIZE, pygame.HWSURFACE | pygame.DOUBLEBUF)
done = False
bpm = 120# int(input("Enter a BPM: ")) #beats per minute
bbpm = 4# int(input("How many Beats Per Measure?: ")) #beats per measure
spm = bbpm*60/bpm #seconds per measure; a measure is made every x seconds
turnsPerMs = 1/(1000*spm) #turns per millisecond
startTime = pygame.time.get_ticks()
color = Color("red")
lineStart = (400,400)
line_len = 400
while not done:
for e in pygame.event.get():
if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE):
done = True
break
screen.fill(0)
pygame.draw.circle(screen, color, lineStart, line_len, 2)
timeDelta = pygame.time.get_ticks() - startTime
revDelta = timeDelta*turnsPerMs;
deltaRadian = revDelta*2*math.pi;
x = lineStart[0] + math.cos(deltaRadian) * line_len
y = lineStart[1] + math.sin(deltaRadian) * line_len
# then render the line ->(x,y)
pygame.draw.line(screen, color, lineStart, (x,y), 1)
pygame.display.flip()