根据BPM和Beats per Measure旋转一条线

时间:2016-12-06 18:53:52

标签: python python-3.x

我正在创建一个基于圆形的鼓机,需要类似雷达的线以速度调制的速度旋转,周期等于每次测量的节拍。这样它以速度旋转,并在一个测量的等效持续时间内完成旋转。

我很难用代数建模。根据我的想法:

每次拍子

秒= 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)

1 个答案:

答案 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()