假設向量w=(wx, wy),這時候wx、wy就稱為w的分量(component)。如果要更清楚地區分指的是wx還是wy,會把wx叫做x分量(x-component),而wy就叫做y分量(y-component)。在pygame中,Vector2()
所建造的向量vec
,其x、y分量就寫成vec.x
、vec.y
。
現在來看看向量的加法要怎麼算。假設u=(ux, uy)、v=(vx, vy),則
u + v = (ux+vx, uy+vy)
也就是說,向量的加法,就只是把分量相加而已。
向量加法跟實數加法一樣,都滿足交換律(commutative rule)和結合律(associative rule):
交換律:u + v = v + u
結合律:u + (v + w) = (u + v) + w
這個用大白話來說就是:誰排前面誰排後面,誰先加誰後加,都不影響最後的結果。
綜合上節和這節的結果,1.1節Example 1.1的程式,可以改寫成如下使用向量的版本。
Example 1.2: Bouncing Ball with Vectors!
# python version 3.10.9
import sys
import pygame # version 2.3.0
pygame.init()
pygame.display.set_caption("Example 1.2: Bouncing Ball with Vectors")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RADIUS = 24 # 球的半徑
screen_size = WIDTH, HEIGHT = 640, 360
screen = pygame.display.set_mode(screen_size)
FPS = 60
frame_rate = pygame.time.Clock()
position = pygame.Vector2(100, 100)
velocity = pygame.Vector2(2.5, 2)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill(WHITE)
# 依據球的速度計算球的位置來移動球
position += velocity
# 檢查是不是碰到左、右邊界回彈
if (position.x > WIDTH) or (position.x < 0):
velocity.x = -velocity.x
# 檢查是不是碰到上、下邊界回彈
if (position.y > HEIGHT) or (position.y < 0):
velocity.y = -velocity.y
# 在位置(x, y)顯示球
pygame.draw.circle(screen, BLACK, position, RADIUS)
pygame.display.update()
frame_rate.tick(FPS)
Exercise 1.1
把Example 0.1改成用向量來寫。Walker
這個class改寫為
class Walker:
def __init__(self, x, y):
self.position = pygame.Vector2(x, y)
def show(self, screen, color=(0, 0, 0)):
pt = (int(self.position.x), int(self.position.y))
screen.set_at(pt, color)
def step(self):
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
self.position += pygame.Vector2(random.choice(directions))
Exercise 1.2
略
Exercise 1.3
假設球是在長、寬、高分別為LENGTH
、WIDTH
、HEIGHT
的方盒內運動。由於pygame並不支援3D繪圖,所以無法顯示動畫效果。不過,利用pygame提供的3D向量功能,還是可以計算出球的位置,以及是否碰到方盒邊界而回彈,這部分的程式如下:
# 檢查是不是碰到左、右邊界回彈
if (position.x > HEIGHT) or (position.x < 0):
velocity.x = -velocity.x
# 檢查是不是碰到前、後邊界回彈
if (position.y > WIDTH) or (position.y < 0):
velocity.y = -velocity.y
# 檢查是不是碰到上、下邊界回彈
if (position.z > HEIGHT) or (position.z < 0):
velocity.z = -velocity.z