現在我們有了一個 Pygame 窗口,在我們優雅地將它關閉之前它會一直打開。代碼清單 16-2 的第 3 行中的 [640, 480] 是窗口的大小,表示 640 像素寬、480 像素高。下面就在這裡面畫一些圖形。按照代碼清單 16-4 修改你的程序。
代碼清單 16-3 畫一個圓
什麼是翻轉
對於 Pygame 窗口中顯示的所有內容,Pygame 中的顯示對像(我們的顯示對像名為 screen
,這在代碼清單 16-3 的第 3 行創建)都會有這些內容的兩個副本。這樣做的原因是,開始動畫時,我們希望讓動畫盡可能流暢,速度盡可能快。所以不必在每次對圖形做一個小小的修改時都更新顯示,可以做很多修改後再「翻轉」(flip)到圖形的新版本。這樣就會一次顯示所有這些修改,而不是一個接一個地出現。這樣一來,我們就不會顯示出只畫了一半的圓(或外星人,或者其他任何東西)。
可以把這兩個副本當作一個「當前屏」和一個「下一屏」。當前屏就是我們現在看到的,下一屏是完成「翻轉」之後看到的。做完「下一屏」上的所有修改後,再翻轉到下一屏,就能看到這些改變。
如何建立一個圓
運行代碼清單 16-3 中的程序時,應該能看到如下圖這樣,靠近窗口左上角有一個紅色的圓。
毫不奇怪,pygame.draw.circle
函數會畫一個圓。必須告訴它以下 5 件事。
在哪個表面(surface)畫這個圓。(在這裡,要在第 3 行定義的表面上畫圓,名為
screen
,這就是顯示表面。)用什麼顏色來畫。(在這裡要用紅色,對應的值為 [255, 0, 0]。)
在什麼位置畫。(在這裡要位於 [100, 100],這表示從左上角向下 100 像素再向右 100 像素的位置)。
圓的大小。(這裡是 30,這是圓的半徑,也就是圓心到外圍邊界的距離,單位是像素。)
線寬。(如果
width = 0
,圓是完全填充的,這裡就採用了完全填充。)
下面再來更詳細地學習這 5 個方面。
術語箱
像素(pixel)這個詞是「圖像元素」(picture element)的簡寫。這表示屏幕上或圖像中的一點。如果在一個圖像瀏覽器中查看圖片,充分放大(讓圖像非常大),就可以看到單個的像素。下面是一張照片的正常視圖和放大視圖,在放大視圖中可以看到像素。
哇,你眼力真好!這些小線條實際上就是像素行。一般的計算機屏幕可能有 768 行像素,每行有 1024 個像素。我們就會說這個屏幕「分辨率是 1024×768」。有些屏幕的像素更多,有些可能比這要少。
Pygame 表面
在實際生活中如果我讓你畫一幅畫,你可能會先問「我在哪兒畫?」在 Pygame 中,我們要在一個表面上畫圖。顯示表面就是我們在屏幕上看到的表面,也就是代碼清單 16-3 中的 screen
。不過 Pygame 程序可以有多個表面,可以把圖像從一個表面複製到另一個表面。還可以對表面做一些處理,比如旋轉表面或者調整它們的大小(讓它們更大或更小)。
前面提到過,顯示表面有兩個副本。按軟件術語來講,我們說顯示表面是雙緩衝的(double-buffered)。正是因為這個原因,我們不會在屏幕上看到只畫了一半的形狀和圖像。我們會在緩衝區裡畫圓、外星人或者任何東西,然後「翻轉」顯示表面,來顯示已經完全繪製的圖像。
Pygame 中的顏色
Pygame 中使用的顏色系統是很多計算機語言和程序中通用的系統,稱為 RGB。這裡的 R、G 和 B 分別代表紅、綠和藍。
你可能在自然課上已經學過,通過結合或混合光的三原色(紅、綠和藍)可以得到任何顏色。計算機上也採用了同樣的做法。每個顏色(紅、綠和藍)對應一個從 0 到 255 的數。由一個包含 3 個整數的列表來給出顏色,每個數的範圍在 0 到 255 之間。如果所有數都是 0,就沒有任何顏色,這就是全黑,所以會得到黑色。如果三個數都是 255,會將 3 種顏色以最大亮度混合在一起,這就是白色。如果顏色是 [255, 0, 0],這就是純紅色,沒有綠色和藍色。純綠就是 [0, 255, 0],純藍是 [0, 0, 255]。如果所有 3 個數都一樣,比如 [150, 150,150],你會得到某種灰度。數字越小,灰度就越深,數字越大,灰度就越淺。
顏色名
Pygame 提供了一個命名顏色列表,如果你不想使用 [R, G, B] 記法,就可以使用這些命名顏色。定義好的顏色名有 600 多個。我不想在這裡全部列出,不過如果你想看看到底有哪些顏色,可以在你的硬盤上搜索一個名為 colordict.py 的文件,然後在文本編輯器中打開這個文件。
如果你想使用這些顏色名,必須在程序最前面增加下面這行代碼:
from pygame.color import THECOLORS然後,使用某個命名顏色時,可以這樣做(我們的畫圓例子中就是這樣做的):
pygame.draw.circle(screen, THECOLORS[\"red\"],[100,100], 30, 0)
到底怎麼回事?
為什麼是 255 呢?每個三原色(紅、綠、藍)都有 0 到 255 共 256 個不同的值。256 這個數字有什麼特別的呢?為什麼不是 200、300 或者 500 呢?
8 位總共正好能表示 256 個不同的值,也就是由 1 和 0 構成的 八位數的所有可能的組合。8 位也稱為一個字節,字節是有自己的地址的最小內存塊。計算機就是利用地址來查找某段內存的。
這就像在街道上一樣。你的房子或公寓有一個地址,不過你的房間沒有地址。房子就是街道上最小的「可尋址單位」。字節則是計算機內存中最小的「可尋址單位」。
也可以用 8 位以上來表示每種顏色,不過,8 位之後可用的位數可能就到 16 位(2 個字節)了,因為不完整的字節使用起來會不太方便。事實證明,根據人眼識別顏色的方式,用 8 位來表示實際可見的顏色完全足夠了。
由於有 3 個值(紅、綠、藍),每個值有 8 位,總共就是 24 位,所以這種表示顏色的方法也稱為「24 位顏色表示法」。對每個像素使用 24 位,每個三原色分別使用 8 位。
如果你想試驗一下,看看紅色、綠色和藍色如何結合來生成不同的顏色,可以試試 colormixer.py 程序,運行本書的安裝程序時會把這個程序放在 examples 文件夾下。利用這個程序,你可以嘗試紅、綠、藍的任意組合,看看能得到什麼顏色。
位置——屏幕坐標
如果想在屏幕上畫個東西或者放上一個東西,需要指定這個東西應當放在屏幕上的哪個位置。這裡有兩個數:一個對應 x 軸(水平方向),還有一個對應 y 軸(垂直方向)。在 Pygame 中,這兩個數從窗口左上角的 [0, 0] 坐標開始。
看到類似 [320, 240] 的一對數時,要知道第一個數表示水平方向,也就是相對於左邊界的距離。第二個數表示垂直方向,也就是相對於頂邊的距離。在數學和編程中,字母 x 通常用來表示水平距離,y 常用來表示垂直距離。
我們建立了一個 640 像素寬、480 像素高的窗口。如果希望在窗口正中間畫圓,需要在 [320, 240] 上繪製。這個位置離左邊界 320 像素,離上邊界 240 像素。
下面嘗試在窗口中間畫圓。運行代碼清單 16-4 中的程序。
代碼清單 16-4 把圓放在窗口中間
這裡使用坐標 [320, 240] 作為圓心。把運行代碼清單 16-3 的結果與運行代碼清單 16-4 時看到的結果做個比較,看看有什麼差別。
形狀大小
使用 Pygame 的 draw
函數畫形狀時,必須指定形狀的尺寸。對於圓來說,只有一個尺寸,也就是半徑。而像矩形之類的形狀,則必須指定長和寬。
Pygame 有一種特殊的對象,名為 rect
(這是「rectangle」(矩形)的簡寫),用來定義矩形區域。rect
要使用左上角坐標、寬和高來定義:
Rect(left, top, width, height)
這裡同時定義了位置和大小。下面是一個例子:
my_rect = Rect(250, 150, 300, 200)
這會創建一個矩形,它的左上角距離窗口左邊界 250 像素,距離窗口上邊界 150 像素,寬為 300 像素,高為 200 像素。下面來試試看。
用下面這行代碼替換代碼清單 16-4 中的第 5 行,看看結果是什麼:
矩形的位置和大小可以是一個簡單的數字列表(或元組),也可以是一個 Pygame 的 Rect
對象。所以還可以把前面一行替換為下面這兩行代碼:
my_list = [250, 150, 300, 200]pygame.draw.rect(screen, [255,0,0], my_list, 0)
或者
my_rect = pygame.Rect(250, 150, 300, 200)pygame.draw.rect(screen, [255,0,0], my_rect, 0)
這就是最後得到的矩形。我增加了一些尺寸標注來說明每個數字分別表示什麼含義。
注意這裡只向 pygame.draw.rect
傳遞了 4 個參數,因為 rect
用一個參數就表示了位置和大小。在 pygame.draw.circle
中,位置和大小分別由兩個不同的參數表示,所以需要傳遞 5 個參數。
像(Pygame)程序員一樣思考
如果用
Rect(left, top, width, height)
創建一個矩形,還可以使用其他一些屬性來移動和對齊這個 Rect:
4 條邊:
top
、left
、bottom
、right
4 個角
: topleft
、bottomleft
、topright
、bottomright
每條邊的中點:
midtop
、midleft
、midbottom
、midright
中心:
center
、centerx
、centery
尺寸:
size
、width
、height
這些屬性只是為了提供方便。所以,如果你想移動一個矩形,讓它的中心位於某個點,不必得出上坐標和左坐標分別是什麼;可以直接訪問中心位置。
線寬
畫形狀時最後需要指定的一點是線的粗細。在之前的例子中,我們使用的線寬都是 0,這會填充整個形狀。如果使用不同的線寬,會看到形狀的輪廓。
試著把線寬改為 2:
試試看有什麼結果。再試試其他線寬。
現代藝術
想不想讓計算機生成某種現代藝術?玩玩唄,試試代碼清單 16-5。也可以在代碼清單 16-4 的基礎上做些修改,或者乾脆從頭開始鍵入。
代碼清單 16-5 使用
draw.rect
實現藝術創作
import pygame, sys, randompygame.initscreen = pygame.display.set_mode([640,480])screen.fill([255, 255, 255])for i in range (100): width = random.randint(0, 250) height = random.randint(0, 100) top = random.randint(0, 400) left = random.randint(0, 500) pygame.draw.rect(screen, [0,0,0], [left, top, width, height], 1)pygame.display.fliprunning = Truewhile running: for event in pygame.event.get:if event.type == pygame.QUIT: running = Falsepygame.quit
運行這個程序,看看會得到什麼。應該能得到如下圖所示的結果:
你明白這個程序是怎麼工作的嗎?它會隨機畫 100 個大小不等、位置不同的矩形。為了讓它更有「藝術性」,再增加一些顏色,另外將線寬也設為隨機,如代碼清單 16-7 所示。
代碼清單 16-6 帶顏色的現代藝術
運行這個程序時,每次你都會看到不同的東西。如果有看著不錯的,可以給它起個富有想像力的名字,比如「機器之聲」,看看能不能把它賣到你們當地的美術館 !