The Nature of Code閱讀心得與Python實作:3.7 Oscillation with...

閱讀時間約 1 分鐘
這一節的標題是
3.7 Oscillation with Angular Velocity
因為方格子標題字數限制,所以沒完整顯現

在上一節,藉由設定振幅、頻率、週期等性質,我們可以模擬出真實世界中的振盪現象。在這一節,我們會用稍微簡單一點的方式來處理,但依舊可以得到相同的效果。

在上一節,我們在處理振盪時,使用的式子是

x = amplitude*math.sin(2*math.pi*frame_count/period)

現在把它改寫成

x = amplitude*math.sin(某個慢慢增加的數值)

也就是說,我們不再乖乖的去算sin裡頭的那一串東西,而是直接把某個數字當成那一串東西算出來的結果。畢竟現在我們要的是最後的結果,而不是多大的週期和幀數可以得到這樣的結果。

結合第二節角速度的觀念,就可以用比較簡單的方式,來改寫上一節的例子。假設

angle = 0
angular_velocity = 0.05

把那個處理振盪的式子改寫成

angle += angular_velocity
x = amplitude*math.sin(angle)

這裡的angle,就是那個慢慢增加的數值,而這也意味著,其中隱含了下面的關係式:

angle = 2*math.pi*frame_count/period

因為在每一幀畫面中,angle的值都會加上angular_velocity的值,所以更進一步拆解後可以發現

angular_velocity = 2*math.pi/period

移項之後得到

period = 2*math.pi/angular_velocity

這也就是說,採用這樣子的處理方式時,雖然程式中並沒有看到週期這個變數,但這並不表示週期這個變數已經被捨棄掉了,它只是在角速度的掩護下隱藏起來而已。

改寫後的程式如下:

Example 3.6: Simple Harmonic Motion II

# python version 3.10.9
import math
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 3.6: Simple Harmonic Motion II")

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

WIDTH, HEIGHT = screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)
screen_center = (WIDTH//2, HEIGHT//2)

FPS = 60
frame_rate = pygame.time.Clock()

amplitude = 100

angle = 0
angular_velocity = 0.05

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

screen.fill(WHITE)

# 球的位置
x = amplitude*math.sin(angle)
position = (x+WIDTH//2, HEIGHT//2)

pygame.draw.circle(screen, BLACK, position, 20)
pygame.draw.line(screen, BLACK, position, screen_center, 3)

angle += angular_velocity

pygame.display.update()
frame_rate.tick(FPS)

接下來,把這個例子再進一步推廣,並造出名為Oscillator的類別,然後讓振盪同時沿著x軸和y軸進行。要達到這樣子的目的,會需要分別設定x軸和y軸上的振幅、角速度,還有那個慢慢增加的數值;這些用向量來處理,會方便很多。

Example 3.7: Oscillator Objects

class Oscillator:
def __init__(self):
# 取得顯示畫面的大小
self.screen = pygame.display.get_surface()
self.width, self.height = self.screen.get_size()

# 樞軸,拴住oscillator的地方
self.pivot = pygame.Vector2(self.width//2, self.height//2)

self.angle = pygame.Vector2(0, 0)
self.angular_velocity = pygame.Vector2(random.uniform(-0.05, 0.05), random.uniform(-0.05, 0.05))
self.amplitude = pygame.Vector2(random.randint(0, self.width//2), random.randint(0, self.height//2))

# 設定oscillator所在surface的格式為per-pixel alpha
self.surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)

def oscillate(self):
self.angle += self.angular_velocity

def show(self):
# 使用具透明度的白色把oscillator所在的surface清空
self.surface.fill((255, 255, 255, 0))

# oscillator的位置
x = self.amplitude.x*math.sin(self.angle.x)
y = self.amplitude.y*math.sin(self.angle.y)
position = pygame.Vector2(x, y) + self.pivot

# 畫出具有透明度的oscillator
color = (0, 0, 0, 100)
pygame.draw.circle(self.surface, color, position, 20)
pygame.draw.line(self.surface, color, position, self.pivot, 3)

# 把oscillator所在的surface貼到最後要顯示的畫面上
self.screen.blit(self.surface, (0, 0))


# python version 3.10.9
import math
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 3.7: Oscillator Objects")

WHITE = (255, 255, 255)

WIDTH, HEIGHT = screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

oscillators = [Oscillator() for i in range(10)]

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

screen.fill(WHITE)

for oscillator in oscillators:
oscillator.oscillate()
oscillator.show()

pygame.display.update()
frame_rate.tick(FPS)

Exercise 3.8

raw-image
class Oscillator:
def __init__(self, joint, leg, angular_velocity, amplitude):
# 取得顯示畫面的大小
self.screen = pygame.display.get_surface()
self.width, self.height = self.screen.get_size()

# 關節位置
self.joint = joint

# 腿長
self.leg = leg

self.angle = 0
self.angular_velocity = angular_velocity
self.amplitude = amplitude

# 設定oscillator所在surface的格式為per-pixel alpha
self.surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)

def oscillate(self):
self.angle += self.angular_velocity

def show(self):
self.surface.fill((255, 255, 255, 0))

# 腳尖位置
x = self.leg
y = self.amplitude*math.sin(self.angle)
position = pygame.Vector2(x, y) + self.joint

color = (0, 0, 0, 100)
pygame.draw.circle(self.surface, color, position, 5)
pygame.draw.line(self.surface, color, position, self.joint, 3)

# 把oscillator所在的surface貼到最後要顯示的畫面上
self.screen.blit(self.surface, (0, 0))


# python version 3.10.9
import math
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Exercise 3.8")

WHITE = (255, 255, 255)

WIDTH, HEIGHT = screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

oscillators = []

# 腿長,負號代表左腳,正號代表右腳
legs = [-50, 50]

for leg in legs:
for i in range(10):
joint = pygame.Vector2(320+leg/50, 100+20*i)
angular_velocity = 0.08
amplitude = 10
oscillators.append(Oscillator(joint, leg, angular_velocity, amplitude))

# 讓各oscillator的初始位置不一樣,這樣腳的動作才不會過於整齊劃一,像是在划龍舟一樣
for i in range(20):
oscillators[i].angle = 0.2*i*math.pi

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

screen.fill(WHITE)

for oscillator in oscillators:
oscillator.oscillate()
oscillator.show()

pygame.display.update()
frame_rate.tick(FPS)

Exercise 3.9

class Oscillator:
def __init__(self):
# 取得顯示畫面的大小
self.screen = pygame.display.get_surface()
self.width, self.height = self.screen.get_size()

# 樞軸,拴住oscillator的地方
self.pivot = pygame.Vector2(self.width//2, self.height//2)

# 最高速限
self.top_speed = 0.1

self.angle = pygame.Vector2(0, 0)
self.angular_acceleration = 1.e-4*pygame.Vector2(random.uniform(-1, 1), random.uniform(-1, 1))
self.angular_velocity = pygame.Vector2(0, 0)
self.amplitude = pygame.Vector2(random.randint(0, self.width//2), random.randint(0, self.height//2))

self.surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)

def oscillate(self):
self.angular_velocity += self.angular_acceleration

# 限速
if self.angular_velocity.magnitude() > self.top_speed:
self.angular_velocity.scale_to_length(self.top_speed)

self.angle += self.angular_velocity

def show(self):
# 使用具透明度的白色把oscillator所在的surface清空
self.surface.fill((255, 255, 255, 0))

# oscillator的位置
x = self.amplitude.x*math.sin(self.angle.x)
y = self.amplitude.y*math.sin(self.angle.y)
position = pygame.Vector2(x, y) + self.pivot

# 畫出具有透明度的oscillator
color = (0, 0, 0, 100)
pygame.draw.circle(self.surface, color, position, 20)
pygame.draw.line(self.surface, color, position, self.pivot, 3)

# 把oscillator所在的surface貼到最後要顯示的畫面上
self.screen.blit(self.surface, (0, 0))


# python version 3.10.9
import math
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Exercise 3.9")

WHITE = (255, 255, 255)

WIDTH, HEIGHT = screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

oscillators = [Oscillator() for i in range(10)]

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

screen.fill(WHITE)

for oscillator in oscillators:
oscillator.oscillate()
oscillator.show()

pygame.display.update()
frame_rate.tick(FPS)


15會員
116內容數
寫點東西自娛娛人
留言0
查看全部
發表第一個留言支持創作者!
ysf的沙龍 的其他內容
這一節談的是振盪(oscillation)。日常生活中,隨處都可見到振盪的現象。例如,彈奏弦樂器時,弦的振動、盪鞦韆時的來回擺動、音叉的振動、單擺的來回擺動、彈簧的振動等。除了這些眼睛看得到的之外,麥克風、交流電、收音機、手機等許許多多的電子產品,也都是利用振盪的原理來運作的。
除了直角座標系統外,極座標(polar coordinate)系統是另一種相當有用的座標系統。
在模擬運動中的物體時,如果物體是圓形,那就不需要考慮旋轉的問題,畢竟不管怎麼轉,圓還是圓,看起來都一樣。但是,如果物體不是圓形而是其他形狀呢?
這一節主要在談三角函數和向量的分量、角度間的關聯性。這個關聯性在向量的應用上,非常重要。
角運動(angular motion)指的是物體的旋轉運動。物體進行直線運動時,可以用速度和加速度來描述它的運動。同樣的做法也可以運用在描述角運動上,我們可以用角速度(angular velocity)和角加速度(angular acceleration)來描述角運動。
角度有兩種單位,一個就是大家耳熟能詳的「度」(degree),記做 °;另一個是「弳度」(radian),也翻譯成「弧度」,記做rad。當使用弳度來度量角度的大小時,通常會把rad省略,不寫出來。
這一節談的是振盪(oscillation)。日常生活中,隨處都可見到振盪的現象。例如,彈奏弦樂器時,弦的振動、盪鞦韆時的來回擺動、音叉的振動、單擺的來回擺動、彈簧的振動等。除了這些眼睛看得到的之外,麥克風、交流電、收音機、手機等許許多多的電子產品,也都是利用振盪的原理來運作的。
除了直角座標系統外,極座標(polar coordinate)系統是另一種相當有用的座標系統。
在模擬運動中的物體時,如果物體是圓形,那就不需要考慮旋轉的問題,畢竟不管怎麼轉,圓還是圓,看起來都一樣。但是,如果物體不是圓形而是其他形狀呢?
這一節主要在談三角函數和向量的分量、角度間的關聯性。這個關聯性在向量的應用上,非常重要。
角運動(angular motion)指的是物體的旋轉運動。物體進行直線運動時,可以用速度和加速度來描述它的運動。同樣的做法也可以運用在描述角運動上,我們可以用角速度(angular velocity)和角加速度(angular acceleration)來描述角運動。
角度有兩種單位,一個就是大家耳熟能詳的「度」(degree),記做 °;另一個是「弳度」(radian),也翻譯成「弧度」,記做rad。當使用弳度來度量角度的大小時,通常會把rad省略,不寫出來。
你可能也想看
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
到目前為止,我們所模擬的萬有引力,是一個物體吸引另一個物體,或者是一個物體吸引多個物體。然而,在真實世界中,每個物體都會互相吸引,所以在這一節中,就來把模擬的情境,擴展成多個物體互相吸引。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
到目前為止,為了簡化問題,我們都假設物體的質量是1。接下來,我們將移除這個假設,然後將完全符合牛頓第二運動定律的apply_force()方法,整合到Mover這個類別中。
這一節談的是牛頓的三大運動定律,以及力對於物體運動狀態的影響。
介紹以物件導向的方式,以向量來實作物體運動的模擬程式。
介紹如何在模擬物體運動時,引入加速度這個物理量。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
這篇要來分享關於「頻率」這件事,談到頻率,不免就要順便談談「吸引力法則」,現在訪間已經有多書籍、影片都有詳細描述吸引力法則的運行方式。它並不是什麼怪力亂神也不是什麼偽科學,實則吸引力法則是個再科學不過的量子力學,同頻相吸的概念而已。
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
到目前為止,我們所模擬的萬有引力,是一個物體吸引另一個物體,或者是一個物體吸引多個物體。然而,在真實世界中,每個物體都會互相吸引,所以在這一節中,就來把模擬的情境,擴展成多個物體互相吸引。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
到目前為止,為了簡化問題,我們都假設物體的質量是1。接下來,我們將移除這個假設,然後將完全符合牛頓第二運動定律的apply_force()方法,整合到Mover這個類別中。
這一節談的是牛頓的三大運動定律,以及力對於物體運動狀態的影響。
介紹以物件導向的方式,以向量來實作物體運動的模擬程式。
介紹如何在模擬物體運動時,引入加速度這個物理量。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
這篇要來分享關於「頻率」這件事,談到頻率,不免就要順便談談「吸引力法則」,現在訪間已經有多書籍、影片都有詳細描述吸引力法則的運行方式。它並不是什麼怪力亂神也不是什麼偽科學,實則吸引力法則是個再科學不過的量子力學,同頻相吸的概念而已。