2016-12-06 4 views
1

私は円に基づいてドラムマシンを作成しており、テンポで変調された速度で回転するレーダーのような線が必要で、拍数。このようにして、それは速度で回転し、1つの尺度の同等の持続時間で回転を完了する。BPMと拍数によるラインの回転

私はこの代数的にモデル化するのに苦労しています。私は考え出したものから:

秒を拍= 60secs/BPMごと

60secs/120bpm = .5spb 

SPBの*のbbpm(拍子)(計量につき秒)SPMを生成します。

.5bps * 4bbpm = 2spm 

これは私が立ち往生した場所です。私は、2秒後に4拍の尺度を完成させるために、線が360度回転している必要があることを知っています。私はこれをモデリングするのに苦労して、これをコーディングするのがずっと少ないです。

私が推測し始めたのは、フレームメイトをspmで除算して、メジャーごとにフレームを生成することです。しかし私は360でそれを分けて、1フレームあたりの度数を決定しましたが、真のメトロノームと比較すると私のチックアームは不正確です。

洞察が得られるでしょう。

マイコード:

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

1)モーション・レンダリングでは、ハードコーディングされたフレームレートやフレームごとに任意の一定の速度に依存していることはありません。何らかの基準位置(この場合、前回のターンまたはinit以降)から時間デルタを測定し、時間デルタに従って現在位置を計算する。でも、あなたのVsyncが)60

2に、いくつかのフレームとフレームレートは必ずしも等しくないん逃すことにして

pygame.display.set_mode(..., pygame.HWSURFACE | pygame.DOUBLEBUF)を使用して、この場合、(代わりに、ハードウェアのVSYNCを使用し、仮定フレームレートに基づく遅延でレンダリングを同期しないでください。

あなたの測定値が正しいと思われます。回転をラジアンに変換する必要はありません。

正しい例:

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() 
+0

ありがとうございます!私は時間デルタを使って動きを理解することを理解しています。 revDeltaに2piを掛けてラジアン(deltaRadian)の値を取得したことを理解していると思います。私は現在revDelta変数を理解しようとしています。計算の開始から現在の瞬間までの時間の変化にミリ秒単位のターン数を掛けた値。それで、経過時間に亘って何回アームを回すべきでしょうか?そして、deltaRadiansはその値をラジアンに変換します。私は正しく理解していますか? –

+0

非常に単純である:直線運動の場合、距離=速度*時間(角度=角速度*時間)。そこで、ループの前に角速度を計算し、ループ内で渡された時間にスピードをかけて角度を求めます。例を明確にするために、角速度をターン/ミリ秒で定義し、角度計算の前にラジアンに変換しました。実際には、revPerMsではなく、radParMs =(2 * math.pi)(/ 1000 * spm) 'の代わりにラジアンで直線を事前に計算することができます。ループ内のラジアンの角度(radDelta = radPerMs * timeDelta')と 'x = ..cos(radDelta)..' –

関連する問題