2024-07-01|閱讀時間 ‧ 約 29 分鐘

The Nature of Code閱讀心得與Python實作:1.4 More Vector Math

pygame的Vector2()、Vector3()支援許多向量的運算,例如

vec + vec
vec - vec
vec * number
number * vec
vec / number
vec // number
vec += vec
vec -= vec
vec *= number
vec /= number
vec //= number
round(vec, ndigits=0)
vec * vec 等同於 dot()
cross()
magnitude() 等同於 length()
normalize()
scale_to_length()

更多更詳細的向量運算,可查閱pygame的說明文件

接下來,就來看看向量的減法、乘法、除法實際上是怎麼計算的。

先來看向量的減法。假設

u = (ux, uy)
v = (vx, vy)

u - v = u + (-v) = (ux, uy) + (-vx, -vy) = (ux - vx, uy - vy)

因為-v是個大小和v相等,但方向相反的向量,所以,減掉一個向量,其實就是加上一個方向相反的向量而已。

下面這個例子,是要在滑鼠游標位置和畫面中心點間畫出直線,而這條直線所代表的,就是畫面中心點到滑鼠游標位置的向量。
Example 1.3: Vector Subtraction


# python version 3.10.9
import sys

import pygame # version 2.3.0

pygame.init()


pygame.display.set_caption("Example 1.3: Vector Subtraction")

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

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

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

center = pygame.Vector2(WIDTH//2, HEIGHT//2)

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

screen.fill(WHITE)

mouse = pygame.Vector2(pygame.mouse.get_pos())

pygame.draw.line(screen, BLACK, center, mouse, 5)
pygame.draw.line(screen, GRAY, (0, 0), center, 5)
pygame.draw.line(screen, GRAY, (0, 0), mouse, 5)

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

這個例子在原書中的做法,是使用向量減法算出從畫面中心點到滑鼠游標位置的向量,接著將座標系統的原點平移到畫面中心點,最後畫出新的原點到向量間的直線。因為pygame並沒有轉換座標系統的函數可供使用,所以就直接畫出從畫面中心到滑鼠游標位置的線段。這個例子,對pygame而言,並不是那麼適合用來展現向量減法的用途和好處。

接下來介紹向量的乘法。

向量的乘法指的是向量乘上一個實數,也就是縮放向量的大小。假設要把u縮放α倍,做法如下:

u × α = (ux, uy) × α = (uxα, uyα)

這也就是說,要縮放向量,只要同時把各個分量乘上相同的縮放倍數就可以了。

向量乘法滿足交換率、結合律和分配率(distributive rule):

交換率:u × α = α × u
結合律:(α × β) × u = α × (β × u)
分配律:
(α + β) × u = α × u + β × u
(u + v) × α = u × α + v × α

下面這個例子,是從畫面中心點到滑鼠游標位置畫出一條線段,然後將其縮短1/2。

Example 1.4: Multiplying a Vector

# python version 3.10.9
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 1.4: Multiplying a Vector")

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

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

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

center = pygame.Vector2(WIDTH//2, HEIGHT//2)

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

screen.fill(WHITE)

mouse = pygame.Vector2(pygame.mouse.get_pos())

pygame.draw.line(screen, GRAY, center, mouse, 3)

endpoint = center + 0.5*(mouse - center)
pygame.draw.line(screen, BLACK, center, endpoint, 5)

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

程式的重點在於端點的求法。以向量的觀點來看,端點為

endpoint = center + 0.5*(mouse - center)

如果純粹以座標的觀點來看,端點為

endpoint = 0.5*(mouse + center)

事實上,這兩個不同觀點算出來的,是一模一樣的東西,只是呈現的方式不同罷了。

結束這節前,也來看一下除法的計算方式。和乘法一樣,除法的計算方式也是依各分量分別計算就可以了,也就是說

u / α = (ux, uy) / α = (ux/α, uy/α)

除法和乘法其實是一體兩面,因為

u / α = (1/α)×u

分享至
成為作者繼續創作的動力吧!
Daniel Shiffman所著「The Nature of Code」一書的閱讀心得,並用python及pygame來實作範例及練習題。 原書網頁版:https://natureofcode.com/
© 2024 vocus All rights reserved.