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)


留言
avatar-img
留言分享你的想法!
avatar-img
ysf的沙龍
15會員
142內容數
寫點東西自娛娛人
ysf的沙龍的其他內容
2024/09/20
這一節要模擬的是擺(pendulum)這個裝置中,構造最簡單、具有理想化性質的單擺(simple pendulum)。
Thumbnail
2024/09/20
這一節要模擬的是擺(pendulum)這個裝置中,構造最簡單、具有理想化性質的單擺(simple pendulum)。
Thumbnail
2024/09/16
我們曾經利用sin函數來模擬彈簧吊錘(bob)的運動,雖然這樣子的做法程式很容易寫,但是卻沒辦法模擬彈簧吊錘受到如風力、重力等環境中其他作用力的影響下,在空間中的運動狀況。要克服這樣子的問題,就不能再倚靠sin函數,而必須改用能夠用來計算彈簧彈力的虎克定律(Hooke's law)。
Thumbnail
2024/09/16
我們曾經利用sin函數來模擬彈簧吊錘(bob)的運動,雖然這樣子的做法程式很容易寫,但是卻沒辦法模擬彈簧吊錘受到如風力、重力等環境中其他作用力的影響下,在空間中的運動狀況。要克服這樣子的問題,就不能再倚靠sin函數,而必須改用能夠用來計算彈簧彈力的虎克定律(Hooke's law)。
Thumbnail
2024/09/13
在x軸上依序取一些點,然後把這些點以及其對應的sin函數的值所構成的二維座標點畫出來時,就可以看到由這個sin函數所產生的像波一樣的圖案,也就是波型(wave pattern)。不同樣式的波型,可以用來設計生物的軀幹或肢體,也可以用來模擬像水這類柔軟的表面。
Thumbnail
2024/09/13
在x軸上依序取一些點,然後把這些點以及其對應的sin函數的值所構成的二維座標點畫出來時,就可以看到由這個sin函數所產生的像波一樣的圖案,也就是波型(wave pattern)。不同樣式的波型,可以用來設計生物的軀幹或肢體,也可以用來模擬像水這類柔軟的表面。
Thumbnail
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
在物理的領域裏 不變的物質有著恆常的定律 於是乎 月球繞著地球轉 地球繞著太陽轉 太陽繞著銀河系   在化學的領域裏 物質隨著原子們的排列組合 形成了 形色多變銀河系 各有千秋太陽系 繽紛美麗的地球   在數學的領域裏 數字的跳躍翻轉變化萬千中 綜言是 正負平方開根
Thumbnail
在物理的領域裏 不變的物質有著恆常的定律 於是乎 月球繞著地球轉 地球繞著太陽轉 太陽繞著銀河系   在化學的領域裏 物質隨著原子們的排列組合 形成了 形色多變銀河系 各有千秋太陽系 繽紛美麗的地球   在數學的領域裏 數字的跳躍翻轉變化萬千中 綜言是 正負平方開根
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5 弦的振動 三 1755年,歐拉改變了主意,在《微分學原理》(Institutiones calculi differen
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 1.2.4 微積分的記法 1.2.5 弦的振動 三 1755年,歐拉改變了主意,在《微分學原理》(Institutiones calculi differen
Thumbnail
直觀理解 導數:考慮的是單一變數的函數,描述的是函數在某點的斜率或變化率。 偏導數:考慮的是多變數函數,描述的是函數在某個變數變化時的變化率,其他變數保持不變。  (針對各維度的調整 或者稱變化 你要調多少) 應用 導數:在物理學中應用廣泛,例如描述速度和加速度。 偏導數:在多變量分析、優
Thumbnail
直觀理解 導數:考慮的是單一變數的函數,描述的是函數在某點的斜率或變化率。 偏導數:考慮的是多變數函數,描述的是函數在某個變數變化時的變化率,其他變數保持不變。  (針對各維度的調整 或者稱變化 你要調多少) 應用 導數:在物理學中應用廣泛,例如描述速度和加速度。 偏導數:在多變量分析、優
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News