使用 pygame 生成和绘制正弦波

问题描述

我正在尝试生成和绘制正弦波。我正在使用我在网上找到的这个公式 y = Amp * sin(2 * PI * frequency * time + shift)

import pygame
import math
import time

window = pygame.display.set_mode((600,600))

class Point:
    def __init__(self):
        self.x = 0
        self.y = 0

class Line:
    def __init__(self):
        self.points = []

def generateLine(startX,nPoints,length,y):
    line = Line()
    for i in range(nPoints):
        p = Point()
        p.x = startX + ((i / nPoints) * length)
        p.y = y
        line.points.append(p)
    return line;

nPoints = 100
line = generateLine(10,590,300)
start = time.time()
accNPoints = 0
frequency = 100
amplitude = 30
overallY = 300

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

    window.fill((255,255,255))

    keys = pygame.key.get_pressed()
    
    if (keys[pygame.K_a]): frequency -= 0.002
    if (keys[pygame.K_d]): frequency += 0.002

    if (keys[pygame.K_s]): amplitude -= 0.05
    if (keys[pygame.K_w]): amplitude += 0.05

    if (keys[pygame.K_q]): overallY += 0.5
    if (keys[pygame.K_e]): overallY -= 0.5

    if (keys[pygame.K_p]): accNPoints += 0.5
    if (keys[pygame.K_o]): accNPoints -= 0.5

    if accNPoints > 50:
        line = generateLine(10,300)
        accNPoints = 0
        nPoints += 1
    elif accNPoints < -50:
        line = generateLine(10,300)
        accNPoints = 0
        nPoints -= 1

    for i in range(1,len(line.points)):
        #calculate y based on x
        #y = A * sin(2 * PI * f * t + shift)
        #yStart = (amplitude * math.sin(2 * math.pi * frequency * ((time.time() - start) * 0.01) + line.points[i].x))     + overallY
        #yEnd =   (amplitude * math.sin(2 * math.pi * frequency * ((time.time() - start) * 0.01) + line.points[i - 1].x)) + overallY
        yStart = (amplitude * math.sin(2 * math.pi * frequency + line.points[i].x))     + overallY
        yEnd =   (amplitude * math.sin(2 * math.pi * frequency + line.points[i - 1].x)) + overallY

        
        pygame.draw.circle(window,(255,0),(line.points[i].x,yStart),1)
        pygame.draw.circle(window,(line.points[i - 1].x,yEnd),1)
            
        pygame.draw.aaline(
            window,(0,yEnd)
            )

    
    pygame.display.flip()

似乎有两个问题。改变 frequency 值似乎并没有真正改变波的频率。频率似乎取决于生成行的函数中的 nPoints 变量,即 def generateLine(startX,y):

解决方法

公式有误。 x 坐标取决于循环的控制变量 (i)。 y 坐标需要依赖于 x 坐标:

例如:频率 5(5 波)

frequency = 5
amplitude = 50
overallY = 300

while True:
    # [...]

    no_pts = window.get_width()
    for i in range(no_pts):
        x = i/no_pts * 2 * math.pi
        y = (amplitude * math.cos(x * frequency)) + overallY
        if i > 0:
            pygame.draw.aaline(window,(0,0),prev_pt,(i,y))
        prev_pt = (i,y)

    # [...]