The Nature of Code閱讀心得與Python實作:3.4 Pointing in the...

更新於 發佈於 閱讀時間約 16 分鐘
這一節的標題是
3.4 Pointing in the Direction of Movement
因為方格子標題字數限制,所以沒完整顯現

在模擬運動中的物體時,如果物體是圓形,那就不需要考慮旋轉的問題,畢竟不管怎麼轉,圓還是圓,看起來都一樣。但是,如果物體不是圓形而是其他形狀呢?模擬如螞蟻、汽車、太空船等不是圓形物體時,除非是要讓它們倒著走,不然不管是直線前進、轉彎,乃至於回頭,都需要讓它們一直面朝運動方向。那要怎麼做,才能讓物體一直面朝運動方向呢?

所謂的「面朝運動方向」,指的其實是「把物體轉到和速度向量一樣的角度」。要達到這個目的,就必須算出速度向量的角度。假設速度向量v=(vx, vy)$,從前一節的圖以及分析可以知道

tanθ = vy / vx

這裡的θ就是速度向量的角度。所以

θ = tan-1(vy / vx)

也就是說,利用tan的反三角函數tan-1,就可以算出v的角度。

在python中,math.atan(x)math.atan2(y, x)都可以用來計算tan-1,但是它們有什麼不同,又該用哪一個呢?

math.atan(x)只有一個參數,算出來的角度範圍介於-π/2到π/2之間。所以,從math.atan(x)所得到的向量角度,沒有辦法得知向量到底是位於哪一個象限。例如,向量(4, 3)和(-4, -3)分別位於第一、三象限,在算角度時,傳給math.atan(x)的數值分別是

3 / 4 = 0.75

(-3) / (-4) = 0.75

這是完全一樣的數值,算出來的角度當然是一樣的。又例如,向量(-4, 3)和(4, -3)分別位於第二、四象限,傳給math.atan(x)的數值分別是

3 / (-4) = -0.75

(-3) / 4 = -0.75

也是完全一樣的數值,最後算出來的角度,當然也會一樣。因此,使用math.atan(x)時,要想知道向量真正的角度,還必須要搭配兩個分量的正負號來判斷才有辦法辦到。

至於math.atan2(y, x),算出的角度範圍,會介於-π到π之間。因此,從math.atan2(y, x)所得到的角度,是向量真正的角度,可以清楚地知道向量到底是位於哪個象限。

從上述的分析就可以知道,選用math.atan2(y, x)來計算向量的角度,是比較好的做法,可以省去不少功夫。

下面這個例子,是把Example 1.10中的mover圖案,由圓形改成長方形,並加入旋轉的功能,讓mover可以自動轉向,永遠面向滑鼠游標的方向。

Example 3.3: Pointing in the Direction of Motion

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

# 起始位置位於畫面中央
self.position = pygame.Vector2(self.width//2, self.height//2)

# 最高速限
self.top_speed = 4

# 初始速度
self.velocity = pygame.Vector2(0, 0)

# mover的大小
self.size = (30, 10)

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

def update(self):
# 計算加速度,其方向為,由mover所在位置指向滑鼠游標位置的方向
mouse = pygame.Vector2(pygame.mouse.get_pos())
acceleration = mouse - self.position
# 調整加速度大小,呈現比較好的模擬效果
acceleration.scale_to_length(0.5)

self.velocity += acceleration
# 限速
if self.velocity.length() > self.top_speed:
self.velocity.scale_to_length(self.top_speed)

self.position += self.velocity

def show(self):
# 在surface上畫出mover
rect = pygame.Rect((0, 0), self.size)
pygame.draw.rect(self.surface, (0, 0, 0), rect)

# 讓mover面朝運動方向
angle = math.atan2(self.velocity.y, self.velocity.x)
# 旋轉角度的單位需由弳度轉換為度
rotated_surface = pygame.transform.rotate(self.surface, -math.degrees(angle))
rect_new = rotated_surface.get_rect(center=self.position)

# 把mover所在的surface貼到最後要顯示的畫面上
self.screen.blit(rotated_surface, (rect_new.x, rect_new.y))

def check_edges(self):
if self.position.x > self.width:
self.position.x = 0
elif self.position.x < 0:
self.position.x = self.width

if self.position.y > self.height:
self.position.y = 0
elif self.position.y < 0:
self.position.y = self.height


# python version 3.10.9
import math
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 3.3: Pointing in the Direction of Motion")

WHITE = (255, 255, 255)

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

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

mover = Mover()

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

screen.fill(WHITE)

mover.update()
mover.check_edges()
mover.show()

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

在旋轉surface時需加上負號,這是因為surface的原點是在左上角,而y軸的方向是向下,剛好與一般我們所熟悉的,y軸方向向上的直角座標系統相反。所以,必須加上負號來調整,使其方向一致。

Exercise 3.4

按下向左鍵時,加速度向量的方向,是速度向量逆時針轉90度的方向;按下向右鍵時,則是順時針轉90度。寫程式時要注意在畫面上呈現出來的旋轉方向是相反的,必須加上負號來調整。這是因為畫面的y軸方向是向下,跟直角座標系統的y軸方向相反。

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

# 起始位置位於畫面中央
self.position = pygame.Vector2(self.width//2, self.height//2)

# 最高速限
self.top_speed = 10

# 初始速度
self.velocity = pygame.Vector2(1, 0)

# vehicle的大小
self.size = (30, 10)

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

def update(self):
keys = pygame.key.get_pressed()
# 按鍵盤向左鍵左轉灣;向右鍵右轉灣
if keys[pygame.K_LEFT]:
acceleration = self.velocity.rotate(-90)
# 調整加速度大小,呈現比較好的模擬效果
acceleration.scale_to_length(0.05)
elif keys[pygame.K_RIGHT]:
acceleration = self.velocity.rotate(90)
# 調整加速度大小,呈現比較好的模擬效果
acceleration.scale_to_length(0.05)
else:
acceleration = pygame.Vector2(0, 0)

self.velocity += acceleration
# 限速
if self.velocity.length() > self.top_speed:
self.velocity.scale_to_length(self.top_speed)

self.position += self.velocity

def show(self):
# 在surface上畫出vehicle
rect = pygame.Rect((0, 0), self.size)
pygame.draw.rect(self.surface, (0, 0, 0), rect)

# 讓vehicle面朝運動方向
angle = math.atan2(self.velocity.y, self.velocity.x)
# 旋轉角度的單位需由弳度轉換為度
rotated_surface = pygame.transform.rotate(self.surface, -math.degrees(angle))
rect_new = rotated_surface.get_rect(center=self.position)

# 把vehicle所在的surface貼到最後要顯示的畫面上
self.screen.blit(rotated_surface, (rect_new.x, rect_new.y))

def check_edges(self):
if self.position.x > self.width:
self.position.x = 0
elif self.position.x < 0:
self.position.x = self.width

if self.position.y > self.height:
self.position.y = 0
elif self.position.y < 0:
self.position.y = self.height


# python version 3.10.9
import math
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Exercise 3.4")

WHITE = (255, 255, 255)

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

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

vehicle = Vehicle()

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

screen.fill(WHITE)

vehicle.update()
vehicle.check_edges()
vehicle.show()

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


留言
avatar-img
留言分享你的想法!
avatar-img
ysf的沙龍
18會員
149內容數
寫點東西自娛娛人
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
孩子寫功課時瞇眼?小心近視!這款喜光全光譜TIONE⁺光健康智慧檯燈,獲眼科院長推薦,網路好評不斷!全光譜LED、180cm大照明範圍、5段亮度及色溫調整、350度萬向旋轉,讓孩子學習更舒適、保護眼睛!
Thumbnail
孩子寫功課時瞇眼?小心近視!這款喜光全光譜TIONE⁺光健康智慧檯燈,獲眼科院長推薦,網路好評不斷!全光譜LED、180cm大照明範圍、5段亮度及色溫調整、350度萬向旋轉,讓孩子學習更舒適、保護眼睛!
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
創作者營運專員/經理(Operations Specialist/Manager)將負責對平台成長及收入至關重要的 Partnership 夥伴創作者開發及營運。你將發揮對知識與內容變現、影響力變現的精準判斷力,找到你心中的潛力新星或有聲量的中大型創作者加入 vocus。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
圓形為空心線圈中最常出現的形狀,但很多設計者在規劃時,常常漏了一點,導致實際生產的尺寸有落差,那就是爬層空間。 如下圖所示,過往在空心線圈排列規劃時免不了兩種形式,左側的方形排列以及右側的緊實排列兩種,生產上是右側較為接近現實。但無論是左右兩種規劃,設計者往往都忽略了從線圈從第一層往上爬至第二層時
Thumbnail
圓形為空心線圈中最常出現的形狀,但很多設計者在規劃時,常常漏了一點,導致實際生產的尺寸有落差,那就是爬層空間。 如下圖所示,過往在空心線圈排列規劃時免不了兩種形式,左側的方形排列以及右側的緊實排列兩種,生產上是右側較為接近現實。但無論是左右兩種規劃,設計者往往都忽略了從線圈從第一層往上爬至第二層時
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
直觀理解 導數:考慮的是單一變數的函數,描述的是函數在某點的斜率或變化率。 偏導數:考慮的是多變數函數,描述的是函數在某個變數變化時的變化率,其他變數保持不變。  (針對各維度的調整 或者稱變化 你要調多少) 應用 導數:在物理學中應用廣泛,例如描述速度和加速度。 偏導數:在多變量分析、優
Thumbnail
直觀理解 導數:考慮的是單一變數的函數,描述的是函數在某點的斜率或變化率。 偏導數:考慮的是多變數函數,描述的是函數在某個變數變化時的變化率,其他變數保持不變。  (針對各維度的調整 或者稱變化 你要調多少) 應用 導數:在物理學中應用廣泛,例如描述速度和加速度。 偏導數:在多變量分析、優
Thumbnail
1. 凡所有相皆是虛妄,若見諸相非相,即見如來 2. 能量看不到,卻統籌物理世界(形而上統籌形而下) 3. 數學與物理的不同:數學「定理」:絕對真理,不因時空轉換;物理「定律」:找到自然背後的律,而非證明 4. 數學的本質:建立在不能再問的「公理」上 5. 歐式平
Thumbnail
1. 凡所有相皆是虛妄,若見諸相非相,即見如來 2. 能量看不到,卻統籌物理世界(形而上統籌形而下) 3. 數學與物理的不同:數學「定理」:絕對真理,不因時空轉換;物理「定律」:找到自然背後的律,而非證明 4. 數學的本質:建立在不能再問的「公理」上 5. 歐式平
Thumbnail
行進中的球,因表面形狀相對速度方向不對稱,產生了不對稱的邊界層分離,以及使球不同位置受到的空氣作用力大小不同,最終導致空氣作用力的合力,出現「垂直速度方向的分力(f)」。 這個分力 f,源於表面形狀 s 的不對稱,而球若有旋轉,則每個時刻的 f 都可能會變化。 既然如此,那不如擴充表面形狀(s)
Thumbnail
行進中的球,因表面形狀相對速度方向不對稱,產生了不對稱的邊界層分離,以及使球不同位置受到的空氣作用力大小不同,最終導致空氣作用力的合力,出現「垂直速度方向的分力(f)」。 這個分力 f,源於表面形狀 s 的不對稱,而球若有旋轉,則每個時刻的 f 都可能會變化。 既然如此,那不如擴充表面形狀(s)
Thumbnail
輪胎轉動是用spin還是rotate?繞圓環是用turn、circle還是cycle?芭蕾舞轉圈、轉陀螺、開車轉彎、轉方向盤、滑鼠的鼠標轉圈圈到底要用哪個英文字?circle和cycle哪裡不同?如果你被煩到暈了,這篇用超清楚的規則幫你一次搞定。
Thumbnail
輪胎轉動是用spin還是rotate?繞圓環是用turn、circle還是cycle?芭蕾舞轉圈、轉陀螺、開車轉彎、轉方向盤、滑鼠的鼠標轉圈圈到底要用哪個英文字?circle和cycle哪裡不同?如果你被煩到暈了,這篇用超清楚的規則幫你一次搞定。
Thumbnail
這是上Krenz老師的透視課第三堂筆記。 這堂課的重點是「旋轉」。
Thumbnail
這是上Krenz老師的透視課第三堂筆記。 這堂課的重點是「旋轉」。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News