這一節的標題是
Vectors inp5.js* Python
因為方格子標題字數限制,所以沒完整顯現
* p5.js 是原書使用的程式語言
一般我們會把向量畫成一枝箭的樣子,箭頭的方向,就是向量的方向;箭的長度,就是向量的大小;而在數學符號方面,一般是在文字上頭畫上箭號來表示向量,但有時候因為印刷排版的關係,也會在特別說明之後,用粗體字來表示向量。下圖顯示的,是從A點到B點的向量
那要怎麼把向量確實的數字算出來呢?其實挺簡單的。假設A的座標是(ax, ay),而B的座標是(bx, by),則
向量AB = (b_x-a_x, b_y-a_y)
也就是說,要算A到B的向量,只要把B的x、y座標分別減去A的x、y座標就可以了。計算上很簡單,但要注意順序,是用「終點」減去「起點」,向量有方向性,順序搞錯的話,方向會相反。
舉個簡單的例子。假設A的座標是(5, 3);而B的座標是(7, 2),則
向量AB = (7-5, 2-3) = (2, -1)
向量的計算很簡單,但是它真正的意義到底是什麼呢?簡單來說,向量告訴我們的,是從一個點要走到另一個點時,應該走的方向和距離。假設
向量AB = (vx, vy)
因為
向量AB = (bx-ax, by-ay)
所以
vx = bx - ax
vy = by - ay
也就是說
bx = ax + vx
by = ay + vy
因此,依照向量AB所指示的方向和距離,從A點分別沿著x軸和y軸的方向,移動vx和vy個單位,就會到達B點。所以,說得有學問一點,向量是兩個點之間的一種關係,透過這種關係,我們可以從一個點的位置找到另一個點的位置。這個觀念,在接下來模擬物體的運動時,就會用到。
向量跟座標之間有個很奇妙的關係,如果不事先說明,我們根本無法區分誰是誰。例如,(3, 7)到底是某個點的座標還是向量?你可以說它是個點的座標,但也可以說它是從原點(0, 0)到(3, 7)這個點之間的向量。如果把(x, y)看成是從原點到點(x, y)的向量,這時候這個向量有個特別的名稱,就叫做「位置向量」(position vector, location vector)。
利用位置向量,我們可以得到下面這個在模擬物體運動時,關於位置和速度間的關係:
對於每一幀(frame)而言
新的位置 = 目前位置 + 在目前位置時的速度
速度是向量,所以這個關係式,其實就是先前提到過的「向量是兩個點之間的一種關係,透過這種關係,我們可以從一個點的位置找到另一個點的位置」的應用。
那條位置和速度的關係式,看起來真是簡潔又優雅。不過,再多看個幾眼就會發現,在簡潔又優雅的背後,似乎有著什麼不太對勁的地方。速度不是要乘上時間,才會得到移動的距離嗎?但是裡頭沒看到時間啊!這時間哪去了?不知道花了多久的時間移動,怎麼可能會知道新的位置在哪?
其實,時間就藏在「對於每一幀」這句話裡頭。
在動畫或影片播放中有個很重要,玩遊戲的人超在乎的數字:fps (frame per second)。fps指的是每秒鐘播放的幀數,所以當我們說「對於每一幀」時,其實就是在說「每隔多少時間」。
當在電腦上建造模擬世界時,我們並不期待那個世界的時間流逝速度和真實世界的時間流逝速度是一樣的,我們在意的是那個世界看起來真不真實、畫面流不流暢。因為fps的高低,決定性地影響著畫面的播放速度,也就同時影響著我們看到的模擬世界的時間流逝速度。所以,在寫程式的時候,把播放每一幀畫面的時間間隔,當作是模擬世界的時間基本單位,會是很方便的做法。
有了模擬世界中的時間基本單位後,接下來勢必要問一個問題:模擬世界中的速度,單位是什麼?這問題的答案很簡單,既然速度的定義是單位時間內的位移量,那在模擬世界中,速度的單位就會是:播放每一幀畫面的時間間隔內的位移量。在模擬世界中,使用像素個數來衡量距離,會是比較方便的做法。所以,在我們的模擬世界中,速度的定義就會是:播放每一幀畫面的時間間隔內,位移了多少個像素。
搞清楚了速度的單位之後,那條位置和速度間的關係式就很容易瞭解了。在關係式中的
在目前位置時的速度
這一項,實際上應該寫成
在目前位置時的速度×1
後面那個最後被省略掉的1,指的就是模擬世界中的單位時間。所以,速度乘上單位時間,就會是單位時間內的位移,也就是從這幀畫面切換到下一幀畫面時,移動了多少個像素的距離。
位置和速度的關係式中,還有個要注意的地方。一般在日常生活中,我們不會去區分速度和速率有什麼不同。但實際上,速度和速率是不同的。速度的英文是velocity,有方向性;速率的英文是speed,沒有方向性。也就是說,速度(velocity)是向量,有方向性;而速率(speed)是純量(scalar),就是單純的數字而已,沒有方向性。所以,從這裡就可以看出來,那條位置和速度間的關係式中的「位置」,嚴格說來,指的其實是「位置向量」,因為向量和向量才可以進行相加運算。
有了上述位置和速度間的關係式之後,就可以用向量來簡化1.1節Example 1.1的程式了。不過因為Python並沒有內建向量的功能,所以需使用其他package的向量功能。
在Python相關,比較知名的package中,numpy
和pygame
都有計算向量的函數可以使用。不過,既然是用pygame
來製作動畫,那就用pygame
提供的函數,這樣程式寫起來應該會比較一致,也會比較容易閱讀。接下來,就利用pygame
提供的向量功能來簡化程式。
在1.1節Example 1.1的程式中,用來描述位置和速度的變數有
位置:x
、y
速度:xspeed
、yspeed
在pygame
中,可以利用Vector2()
和Vector3()
來建造二維和三維向量。這裡可以利用二維向量,把原來程式中的
x, y = 100, 100
xspeed, yspeed = 2.5, 2
改成
position = pygame.Vector2(100, 100)
velocity = pygame.Vector2(2.5, 2)
而那條位置和速度間的關係式,也就可以寫成
position = position + velocity
或寫成
position += velocity