所謂3D,說到底就是利用透視原理,在2D的畫面上創造出有縱深錯覺(說白了也就是近大遠小)的畫面而已,畢竟,螢幕是平的,怎麼可能真的畫出距離呢?換句話說,計算機3D的本質還是2D,只不過額外多了很多東西。
在純pygame中,我們畫3D畫面就是透過計算在2D影像上畫一些大小不一的東西:)
距離的魔法
我們看現實中的東西,和我們看畫面上的東西,最大差別在於能感受現實物體的距離。而距離的產生,則是因為我們雙眼看到的東西是不同的,兩眼交替閉合,你會發現眼前的東西左右移動。一隻眼睛則很難正確的判斷距離,雖然比上眼睛還是能感覺到遠近,但更精細一點,比如很難把線穿過針眼。
我們在3D畫面上繪圖的時候,就要遵循這個規律,看看下面的程式碼。
import pygame from pygame.locals import * from random import randint class Star(object): def __init__(self, x, y, speed): self.x = x self.y = y self.speed = speed def run(): pygame.init() screen = pygame.display.set_mode((640, 480)) #, FULLSCREEN) stars = [] # 在第一幀,畫上一些星星 for n in xrange(200): x = float(randint(0, 639)) y = float(randint(0, 479)) speed = float(randint(10, 300)) stars.append( Star(x, y, speed) ) clock = pygame.time.Clock() white = (255, 255, 255) while True: for event in pygame.event.get(): if event.type == QUIT: return if event.type == KEYDOWN: return # 增加一顆新的星星 y = float(randint(0, 479)) speed = float(randint(10, 300)) star = Star(640., y, speed) stars.append(star) time_passed = clock.tick() time_passed_seconds = time_passed / 1000. screen.fill((0, 0, 0)) # 繪製所有的星 for star in stars: new_x = star.x - time_passed_seconds * star.speed pygame.draw.aaline(screen, white, (new_x, star.y), (star.x+1., star.y)) star.x = new_x def on_screen(star): return star.x > 0 # 星星跑出了畫面,就刪了它 stars = filter(on_screen, stars) pygame.display.update() if __name__ == "__main__": run()
這裡你還可以把FULLSCREEN加上,更有感覺。
這個程式給我的畫面,發揮一下你的想象,不是一片宇宙麼,無數的星雲穿梭,近的速度更快,遠的則很慢。而實際上看程式碼,我們只是畫了一些長短不同的線而已!雖然很簡單,還是用了不少不少python的技術,特別是函數語言程式設計的(小)技巧。不過強大的你一定沒問題:)但是pygame的程式碼,沒有任何沒講過的,為什麼這樣就能有3D的效果了?感謝你的大腦,因為它知道遠的看起來更慢,所以這樣的錯覺就產生了。
理解3D空間
3D空間的事情,基本就是立體幾何的問題,高中學一半應該就差不多理解了,這裡不多講了。你能明白下圖的小球在(7, 5, 10)的位置,換句話說,如果你站在原點,面朝Z軸方向。那麼小球就在你左邊7,上面5,前面10的位置。這就夠了~
使用3D向量
我們已經學習了二維向量來表達運動,在三維空間內,當然要使用三維的向量。其實和二維的概念都一樣,加減縮放啥的,這裡就不用三個元素的元組列表先演練一番了,直接祭出我們的gameobjects神器吧!
from gameobjects.vector3 import * A = Vector3(6, 8, 12) B = Vector3(10, 16, 12) print "A is", A print "B is", B print "Magnitude of A is", A.get_magnitude() print "A+B is", A+B print "A-B is", A–B print "A normalized is", A.get_normalized() print "A*2 is", A * 2
執行一下看看結果吧,有些無趣?確實,光數字沒法展現3D的美啊,下一次,讓我們把物體在立體空間內運動起來。