原文:NumPy: Beginner’s Guide - Third Edition
協(xié)議:CC BY-NC-SA 4.0
譯者:飛龍
十一、玩轉(zhuǎn) Pygame
本章適用于希望使用 NumPy 和 Pygame 快速輕松創(chuàng)建游戲的開發(fā)人員。 基本的游戲開發(fā)經(jīng)驗(yàn)會有所幫助,但這不是必需的。
您將學(xué)到的東西如下:
- pygame 基礎(chǔ)
- matplotlib 集成
- 表面像素?cái)?shù)組
- 人工智能
- 動畫
- OpenGL
Pygame
Pygame 是 Python 框架,最初由 Pete Shinners 編寫, 顧名思義,可用于制作視頻游戲。 自 2004 年以來,Pygame 是免費(fèi)的開放源代碼,并獲得 GPL 許可,這意味著您基本上可以制作任何類型的游戲。 Pygame 構(gòu)建在簡單 DirectMedia 層(SDL)。 SDL 是一個 C 框架,可以訪問各種操作系統(tǒng)(包括 Linux,MacOSX 和 Windows)上的圖形,聲音,鍵盤和其他輸入設(shè)備。
實(shí)戰(zhàn)時(shí)間 – 安裝 Pygame
我們將在本節(jié)中安裝 Pygame。 Pygame 應(yīng)該與所有 Python 版本兼容。 在撰寫時(shí),Python3 存在一些不兼容問題,但很可能很快就會解決。
-
在 Debian 和 Ubuntu 上安裝:Pygame 可以在 Debian 檔案文件中找到。
-
在 Windows 上安裝:從 Pygame 網(wǎng)站下載適用于您正在使用的版本的 Python 的二進(jìn)制安裝程序。
-
在 Mac 上安裝 Pygame:適用于 MacOSX 10.3 及更高版本的二進(jìn)制 Pygame 包可在這個頁面中找到。
-
從源代碼安裝:Pygame 使用
distutils
系統(tǒng)進(jìn)行編譯和安裝。 要開始使用默認(rèn)選項(xiàng)安裝 Pygame,只需運(yùn)行以下命令:$ python setup.py
如果您需要有關(guān)可用選項(xiàng)的更多信息,請鍵入以下內(nèi)容:
$ python setup.py help
-
要編譯代碼,您的操作系統(tǒng)需要一個編譯器。 進(jìn)行設(shè)置超出了本書的范圍。 有關(guān)在 Windows 上編譯 Pygame 的更多信息,可以在這個頁面上找到。 有關(guān)在 MacOSX 上編譯 Pygame 的更多信息,請參考這里。
HelloWorld
我們將創(chuàng)建一個簡單的游戲,在本章中我們將進(jìn)一步改進(jìn) 。 與編程書籍中的傳統(tǒng)方法一樣,我們從Hello World!
示例開始。
實(shí)戰(zhàn)時(shí)間 – 創(chuàng)建一個簡單的游戲
重要的是要注意所謂的主游戲循環(huán),在該循環(huán)中所有動作都會發(fā)生,并使用Font
模塊渲染文本。 在此程序中,我們將操縱用于繪制的 Pygame Surface
對象,并處理退出事件。
-
首先,導(dǎo)入所需的 Pygame 模塊。 如果正確安裝了 Pygame,則不會出現(xiàn)任何錯誤,否則請返回安裝“實(shí)戰(zhàn)時(shí)間”:
import pygame, sys from pygame.locals import *
-
初始化 Pygame,按
300
像素創(chuàng)建400
的顯示,并將窗口標(biāo)題設(shè)置為Hello world!
:pygame.init() screen = pygame.display.set_mode((400, 300)) pygame.display.set_caption('Hello World!')
-
游戲通常會有一個游戲循環(huán),該循環(huán)將一直運(yùn)行直到發(fā)生退出事件為止。 在此示例中,僅在坐標(biāo)
(100, 100)
上設(shè)置帶有文本Hello world!
的標(biāo)簽。 文字的字體大小為 19,顏色為紅色:while True: sysFont = pygame.font.SysFont("None", 19) rendered = sysFont.render('Hello World', 0, (255, 100, 100)) screen.blit(rendered, (100, 100)) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update()
我們得到以下屏幕截圖作為最終結(jié)果:
以下是 HelloWorld 的完整代碼示例:
import pygame, sys from pygame.locals import * pygame.init() screen = pygame.display.set_mode((400, 300)) pygame.display.set_caption('Hello World!') while True: sysFont = pygame.font.SysFont("None", 19) rendered = sysFont.render('Hello World', 0, (255, 100, 100)) screen.blit(rendered, (100, 100)) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update()
剛剛發(fā)生了什么?
看起來似乎不多,但是我們在本節(jié)中學(xué)到了很多東西。 下表總結(jié)了通過審查的函數(shù):
函數(shù) | 描述 |
---|---|
pygame.init() |
此函數(shù)執(zhí)行初始化,您必須在調(diào)用其他 Pygame 函數(shù)之前調(diào)用它。 |
pygame.display.set_mode((400, 300)) |
此函數(shù)創(chuàng)建一個要使用的所謂的Surface 對象。 我們給這個函數(shù)一個表示表面尺寸的元組。 |
pygame.display.set_caption('Hello World!') |
此函數(shù)將窗口標(biāo)題設(shè)置為指定的字符串值。 |
pygame.font.SysFont("None", 19) |
此函數(shù)根據(jù)逗號分隔的字體列表(在本例中為無)和整數(shù)字體大小參數(shù)創(chuàng)建系統(tǒng)字體。 |
sysFont.render('Hello World', 0, (255, 100, 100)) |
此函數(shù)在Surface 上繪制文本。 最后一個參數(shù)是表示顏色的 RGB 值的元組。 |
screen.blit(rendered, (100, 100)) |
此函數(shù)使用Surface 。 |
pygame.event.get() |
此函數(shù)獲取Event 對象的列表。 事件表示系統(tǒng)中的特殊事件,例如用戶退出游戲。 |
pygame.quit() |
該函數(shù)清除由 Pygame 使用的資源。 退出游戲之前,請調(diào)用此函數(shù)。 |
pygame.display.update() |
此函數(shù)刷新表面。 |
動畫
大多數(shù)游戲,甚至是最靜態(tài)的游戲,都有一定程度的動畫效果。 從程序員的角度來看,動畫就是 ,無非就是在不同的時(shí)間在不同的位置顯示對象,從而模擬運(yùn)動。
Pygame 提供了一個Clock
對象,該對象管理每秒繪制多少幀。 這樣可以確保動畫與用戶 CPU 的速度無關(guān)。
實(shí)戰(zhàn)時(shí)間 – 使用 NumPy 和 Pygame 為對象設(shè)置動畫
我們將加載圖像,然后再次使用 NumPy 定義屏幕周圍的順時(shí)針路徑。
-
創(chuàng)建一個 Pygame 時(shí)鐘,如下所示:
clock = pygame.time.Clock()
-
作為本書隨附的源代碼的一部分,應(yīng)該有一張頭像。 加載此圖像并在屏幕上四處移動:
img = pygame.image.load('head.jpg')
-
定義一些數(shù)組來保存位置的坐標(biāo),我們希望在動畫過程中將圖像放置在這些位置。 由于我們將移動對象,因此路徑有四個邏輯部分:
right
,down
,left
和up
。 每個部分將具有40
等距步長。 將0
部分中的所有值初始化:steps = np.linspace(20, 360, 40).astype(int) right = np.zeros((2, len(steps))) down = np.zeros((2, len(steps))) left = np.zeros((2, len(steps))) up = np.zeros((2, len(steps)))
-
設(shè)置圖像位置的坐標(biāo)很簡單。 但是,需要注意一個棘手的問題-
[::-1]
表示法會導(dǎo)致數(shù)組元素的順序顛倒:right[0] = steps right[1] = 20 down[0] = 360 down[1] = steps left[0] = steps[::-1] left[1] = 360 up[0] = 20 up[1] = steps[::-1]
-
我們可以加入路徑部分,但是在執(zhí)行此操作之前,請使用
T
運(yùn)算符轉(zhuǎn)置數(shù)組,因?yàn)樗鼈兾凑_對齊以進(jìn)行連接:pos = np.concatenate((right.T, down.T, left.T, up.T))
-
在主事件循環(huán)中,讓時(shí)鐘以每秒 30 幀的速度計(jì)時(shí):
clock.tick(30)
搖頭的屏幕截圖如下:
您應(yīng)該能夠觀看此動畫的電影。 它也是代碼包(
animation.mp4
)的一部分。此示例的代碼幾乎使用了到目前為止我們學(xué)到的所有內(nèi)容,但仍應(yīng)足夠簡單以了解:
import pygame, sys from pygame.locals import * import numpy as np pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode((400, 400)) pygame.display.set_caption('Animating Objects') img = pygame.image.load('head.jpg') steps = np.linspace(20, 360, 40).astype(int) right = np.zeros((2, len(steps))) down = np.zeros((2, len(steps))) left = np.zeros((2, len(steps))) up = np.zeros((2, len(steps))) right[0] = steps right[1] = 20 down[0] = 360 down[1] = steps left[0] = steps[::-1] left[1] = 360 up[0] = 20 up[1] = steps[::-1] pos = np.concatenate((right.T, down.T, left.T, up.T)) i = 0 while True: # Erase screen screen.fill((255, 255, 255)) if i >= len(pos): i = 0 screen.blit(img, pos[i]) i += 1 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update() clock.tick(30)
剛剛發(fā)生了什么?
在本節(jié)中,我們了解了一些有關(guān)動畫的知識。 我們了解到的最重要的概念是時(shí)鐘。 下表描述了我們使用的新函數(shù):
函數(shù) | 描述 |
---|---|
pygame.time.Clock() |
這將創(chuàng)建一個游戲時(shí)鐘。 |
clock.tick(30) |
此函數(shù)執(zhí)行游戲時(shí)鐘的刻度。 此處,30 是每秒的幀數(shù)。 |
matplotlib
matplotlib
是一個易于繪制的開源庫,我們在第 9 章,“matplotlib 繪圖”中了解到。 我們可以將 matplotlib 集成到 Pygame 游戲中并創(chuàng)建各種繪圖。
實(shí)戰(zhàn)時(shí)間 – 在 Pygame 中使用 matplotlib
在本秘籍中,我們采用上一節(jié)的位置坐標(biāo),并對其進(jìn)行繪制。
-
要將 matplotlib 與 Pygame 集成,我們需要使用非交互式后端; 否則,默認(rèn)情況下,matplotlib 將為我們提供一個 GUI 窗口。 我們將導(dǎo)入主要的 matplotlib 模塊并調(diào)用
use()
函數(shù)。 在導(dǎo)入主 matplotlib 模塊之后以及在導(dǎo)入其他 matplotlib 模塊之前,立即調(diào)用此函數(shù):import matplotlib as mpl mpl.use("Agg")
-
我們可以在 matplotlib 畫布上繪制非交互式繪圖。 創(chuàng)建此畫布需要導(dǎo)入,創(chuàng)建圖形和子圖。 將數(shù)字指定為
3
乘3
英寸大。 在此秘籍的末尾可以找到更多詳細(xì)信息:import matplotlib.pyplot as plt import matplotlib.backends.backend_agg as agg fig = plt.figure(figsize=[3, 3]) ax = fig.add_subplot(111) canvas = agg.FigureCanvasAgg(fig)
-
在非交互模式下,繪制數(shù)據(jù)比在默認(rèn)模式下復(fù)雜一些。 由于我們需要重復(fù)繪圖,因此在函數(shù)中組織繪圖代碼是有意義的。 Pygame 最終在畫布上繪制了繪圖。 畫布為我們的設(shè)置增加了一些復(fù)雜性。 在此示例的末尾,您可以找到有關(guān)這些函數(shù)的更多詳細(xì)說明:
def plot(data): ax.plot(data) canvas.draw() renderer = canvas.get_renderer() raw_data = renderer.tostring_rgb() size = canvas.get_width_height() return pygame.image.fromstring(raw_data, size, "RGB")
下面的屏幕截圖顯示了正在運(yùn)行的動畫。 您還可以在代碼包(
matplotlib.mp4
)和 YouTube 上查看截屏視頻。更改后,我們將獲得以下代碼:
import pygame, sys from pygame.locals import * import numpy as np import matplotlib as mpl mpl.use("Agg") import matplotlib.pyplot as plt import matplotlib.backends.backend_agg as agg fig = plt.figure(figsize=[3, 3]) ax = fig.add_subplot(111) canvas = agg.FigureCanvasAgg(fig) def plot(data): ax.plot(data) canvas.draw() renderer = canvas.get_renderer() raw_data = renderer.tostring_rgb() size = canvas.get_width_height() return pygame.image.fromstring(raw_data, size, "RGB") pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode((400, 400)) pygame.display.set_caption('Animating Objects') img = pygame.image.load('head.jpg') steps = np.linspace(20, 360, 40).astype(int) right = np.zeros((2, len(steps))) down = np.zeros((2, len(steps))) left = np.zeros((2, len(steps))) up = np.zeros((2, len(steps))) right[0] = steps right[1] = 20 down[0] = 360 down[1] = steps left[0] = steps[::-1] left[1] = 360 up[0] = 20 up[1] = steps[::-1] pos = np.concatenate((right.T, down.T, left.T, up.T)) i = 0 history = np.array([]) surf = plot(history) while True: # Erase screen screen.fill((255, 255, 255)) if i >= len(pos): i = 0 surf = plot(history) screen.blit(img, pos[i]) history = np.append(history, pos[i]) screen.blit(surf, (100, 100)) i += 1 for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update() clock.tick(30)
剛剛發(fā)生了什么?
下表解釋了繪圖相關(guān)函數(shù):
函數(shù) | 描述 |
---|---|
mpl.use("Agg") |
此函數(shù)指定使用非交互式后端 |
plt.figure(figsize=[3, 3]) |
此函數(shù)創(chuàng)建一個3 x 3 英寸的圖形 |
agg.FigureCanvasAgg(fig) |
此函數(shù)在非交互模式下創(chuàng)建畫布 |
canvas.draw() |
此函數(shù)在畫布上繪制 |
canvas.get_renderer() |
此函數(shù)為畫布提供渲染器 |
表面像素
Pygame surfarray
模塊處理 Pygame Surface
對象與 NumPy 數(shù)組之間的轉(zhuǎn)換 。 您可能還記得,NumPy 可以快速有效地處理大型數(shù)組。
實(shí)戰(zhàn)時(shí)間 – 用 NumPy 訪問表面像素?cái)?shù)據(jù)
在本節(jié)中,我們將平鋪一個小圖像以填充游戲屏幕。
-
array2d()
函數(shù)將像素復(fù)制到二維數(shù)組中(對于三維數(shù)組也有類似的功能)。 將頭像圖像中的像素復(fù)制到數(shù)組中:pixels = pygame.surfarray.array2d(img)
-
使用數(shù)組的
shape
屬性從像素?cái)?shù)組的形狀創(chuàng)建游戲屏幕。 在兩個方向上將屏幕放大七倍:X = pixels.shape[0] * 7 Y = pixels.shape[1] * 7 screen = pygame.display.set_mode((X, Y))
-
使用 NumPy
tile()
函數(shù)可以輕松平鋪圖像。 數(shù)據(jù)需要轉(zhuǎn)換為整數(shù)值,因?yàn)?Pygame 將顏色定義為整數(shù):new_pixels = np.tile(pixels, (7, 7)).astype(int)
-
surfarray
模塊具有特殊函數(shù)blit_array()
在屏幕上顯示數(shù)組:pygame.surfarray.blit_array(screen, new_pixels)
以下代碼執(zhí)行圖像的平鋪:
import pygame, sys from pygame.locals import * import numpy as np pygame.init() img = pygame.image.load('head.jpg') pixels = pygame.surfarray.array2d(img) X = pixels.shape[0] * 7 Y = pixels.shape[1] * 7 screen = pygame.display.set_mode((X, Y)) pygame.display.set_caption('Surfarray Demo') new_pixels = np.tile(pixels, (7, 7)).astype(int) while True: screen.fill((255, 255, 255)) pygame.surfarray.blit_array(screen, new_pixels) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update()
剛剛發(fā)生了什么?
以下是我們使用的新函數(shù)和屬性的簡要說明:
函數(shù) | 描述 |
---|---|
pygame.surfarray.array2d(img) |
此函數(shù)將像素?cái)?shù)據(jù)復(fù)制到二維數(shù)組中 |
pygame.surfarray.blit_array(screen, new_pixels) |
此函數(shù)在屏幕上顯示數(shù)組值 |
人工智能
通常,我們需要模仿游戲中的智能行為。 scikit-learn
項(xiàng)目旨在提供一種用于機(jī)器學(xué)習(xí)的 API,而我最喜歡的是其精美的文檔。 我們可以使用操作系統(tǒng)的包管理器來安裝scikit-learn
,盡管此選項(xiàng)可能有效或無效,具體取決于您的操作系統(tǒng),但這應(yīng)該是最方便的方法。 Windows 用戶只需從項(xiàng)目網(wǎng)站下載安裝程序即可。 在 Debian 和 Ubuntu 上,該項(xiàng)目稱為python-sklearn
。 在 MacPorts 上,這些端口稱為py26-scikits-learn
和py27-scikits-learn
。 我們也可以從源代碼或使用easy_install
安裝。 PythonXY, Enthought 和 NetBSD。
我們可以通過在命令行中鍵入來安裝scikit-learn
:
$ [sudo] pip install -U scikit-learn
我們也可以鍵入以下內(nèi)容而不是前一行:
$ [sudo] easy_install -U scikit-learn
由于權(quán)限的原因,這可能無法正常工作,因此您可能需要在命令前面放置sudo
或以管理員身份登錄。
實(shí)戰(zhàn)時(shí)間 – 點(diǎn)的聚類
我們將生成一些隨機(jī)點(diǎn)并將它們聚類,這意味著彼此靠近的點(diǎn)將放入同一簇中。 這只是scikit-learn
可以應(yīng)用的許多技術(shù)之一。聚類是一種機(jī)器學(xué)習(xí)算法,旨在基于相似度對項(xiàng)目進(jìn)行分組。 接下來,我們將計(jì)算平方親和矩陣。親和度矩陣是包含親和度值的矩陣:例如,點(diǎn)之間的距離。 最后,我們將這些點(diǎn)與[??HTG2]中的AffinityPropagation
類聚類。
-
在
400 x 400
像素的正方形內(nèi)生成 30 個隨機(jī)點(diǎn)位置:positions = np.random.randint(0, 400, size=(30, 2))
-
使用到原點(diǎn)的歐式距離作為親和度度量來計(jì)算親和度矩陣:
positions_norms = np.sum(positions ** 2, axis=1) S = - positions_norms[:, np.newaxis] - positions_norms[np.newaxis, :] + 2 * np.dot(positions, positions.T)
-
給
AffinityPropagation
類上一步的結(jié)果。 此類使用適當(dāng)?shù)娜杭幪枠?biāo)記點(diǎn):aff_pro = sklearn.cluster.AffinityPropagation().fit(S) labels = aff_pro.labels_
-
為每個群集繪制多邊形。 涉及的函數(shù)需要點(diǎn)列表,顏色(將其繪制為紅色)和表面:
pygame.draw.polygon(screen, (255, 0, 0), polygon_points[i])
結(jié)果是每個群集的一堆多邊形,如下圖所示:
群集示例代碼如下:
import numpy as np import sklearn.cluster import pygame, sys from pygame.locals import * np.random.seed(42) positions = np.random.randint(0, 400, size=(30, 2)) positions_norms = np.sum(positions ** 2, axis=1) S = - positions_norms[:, np.newaxis] - positions_norms[np.newaxis, :] + 2 * np.dot(positions, positions.T) aff_pro = sklearn.cluster.AffinityPropagation().fit(S) labels = aff_pro.labels_ polygon_points = [] for i in xrange(max(labels) + 1): polygon_points.append([]) # Sorting points by cluster for label, position in zip(labels, positions): polygon_points[labels[i]].append(positions[i]) pygame.init() screen = pygame.display.set_mode((400, 400)) while True: for point in polygon_points: pygame.draw.polygon(screen, (255, 0, 0), point) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update()
剛剛發(fā)生了什么?
下表更詳細(xì)地描述了人工智能示例中最重要的行 :
函數(shù) | 描述 |
---|---|
sklearn.cluster.AffinityPropagation().fit(S) |
此函數(shù)創(chuàng)建AffinityPropagation 對象,并使用相似性矩陣執(zhí)行擬合 |
pygame.draw.polygon(screen, (255, 0, 0), point) |
給定表面,顏色(在這種情況下為紅色)和點(diǎn)列表,此函數(shù)繪制多邊形 |
OpenGL 和 Pygame
OpenGL 為二維和三維計(jì)算機(jī)圖形指定了 API。 API 由函數(shù)和常量組成。 我們將專注于名為PyOpenGL
的 Python 實(shí)現(xiàn)。 使用以下命令安裝PyOpenGL
:
$ [sudo] pip install PyOpenGL PyOpenGL_accelerate
您可能需要具有 root 訪問權(quán)限才能執(zhí)行此命令。 對應(yīng)于easy_install
的命令如下:
$ [sudo] easy_install PyOpenGL PyOpenGL_accelerate
實(shí)戰(zhàn)時(shí)間 – 繪制 Sierpinski 地毯
為了演示的目的,我們將使用 OpenGL 繪制一個 Sierpinski 地毯,也稱為 Sierpinski 三角形或 Sierpinski 篩子。 這是由數(shù)學(xué)家 Waclaw Sierpinski 創(chuàng)建的三角形形狀的分形圖案。 三角形是通過遞歸且原則上是無限的過程獲得的。
-
首先,首先初始化一些與 OpenGL 相關(guān)的原語。 這包括設(shè)置顯示模式和背景顏色。 本節(jié)末尾提供逐行說明:
def display_openGL(w, h): pygame.display.set_mode((w,h), pygame.OPENGL|pygame.DOUBLEBUF) glClearColor(0.0, 0.0, 0.0, 1.0) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) gluOrtho2D(0, w, 0, h)
-
該算法要求我們顯示點(diǎn),越多越好。 首先,我們將繪圖顏色設(shè)置為紅色。 其次,我們定義一個三角形的頂點(diǎn)(我稱它們?yōu)辄c(diǎn))。 然后,我們定義隨機(jī)索引,該隨機(jī)索引將用于選擇三個三角形頂點(diǎn)之一。 我們在中間的某個地方隨機(jī)選擇一個點(diǎn),實(shí)際上并不重要。 之后,在上一個點(diǎn)和隨機(jī)選取的一個頂點(diǎn)之間的一半處繪制點(diǎn)。 最后,刷新結(jié)果:
glColor3f(1.0, 0, 0) vertices = np.array([[0, 0], [DIM/2, DIM], [DIM, 0]]) NPOINTS = 9000 indices = np.random.random_integers(0, 2, NPOINTS) point = [175.0, 150.0] for i in xrange(NPOINTS): glBegin(GL_POINTS) point = (point + vertices[indices[i]])/2.0 glVertex2fv(point) glEnd() glFlush()
Sierpinski 三角形如下所示:
帶有所有導(dǎo)入的完整 Sierpinski 墊圈演示代碼如下:
import pygame from pygame.locals import * import numpy as np from OpenGL.GL import * from OpenGL.GLU import * def display_openGL(w, h): pygame.display.set_mode((w,h), pygame.OPENGL|pygame.DOUBLEBUF) glClearColor(0.0, 0.0, 0.0, 1.0) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) gluOrtho2D(0, w, 0, h) def main(): pygame.init() pygame.display.set_caption('OpenGL Demo') DIM = 400 display_openGL(DIM, DIM) glColor3f(1.0, 0, 0) vertices = np.array([[0, 0], [DIM/2, DIM], [DIM, 0]]) NPOINTS = 9000 indices = np.random.random_integers(0, 2, NPOINTS) point = [175.0, 150.0] for i in xrange(NPOINTS): glBegin(GL_POINTS) point = (point + vertices[indices[i]])/2.0 glVertex2fv(point) glEnd() glFlush() pygame.display.flip() while True: for event in pygame.event.get(): if event.type == QUIT: return if __name__ == '__main__': main()
剛剛發(fā)生了什么?
如所承諾的,以下是該示例最重要部分的逐行說明:
函數(shù) | 描述 |
---|---|
pygame.display.set_mode((w,h), pygame.OPENGL|pygame.DOUBLEBUF) |
此函數(shù)將顯示模式設(shè)置為所需的寬度,高度和 OpenGL 顯示 |
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) |
此函數(shù)使用遮罩清除緩沖區(qū)。 在這里,我們清除顏色緩沖區(qū)和深度緩沖區(qū)位 |
gluOrtho2D(0, w, 0, h) |
此函數(shù)定義二維正交投影矩陣,其坐標(biāo)為左,右,上和下剪切平面 |
glColor3f(1.0, 0, 0) |
此函數(shù)使用 RGB 的三個浮點(diǎn)值(紅色,綠色,藍(lán)色)定義當(dāng)前圖形顏色。 在這種情況下,我們將以紅色繪制 |
glBegin(GL_POINTS) |
此函數(shù)定義了圖元的頂點(diǎn)或圖元的組。 這里的原語是點(diǎn) |
glVertex2fv(point) |
此函數(shù)在給定頂點(diǎn)的情況下渲染點(diǎn) |
glEnd() |
此函數(shù)關(guān)閉以glBegin() 開頭的一段代碼 |
glFlush() |
此函數(shù)強(qiáng)制執(zhí)行 GL 命令 |
使用 Pygame 的模擬游戲
作為最后一個示例,我們將使用 Conway 的生命游戲模擬生命。 最初的生命游戲是基于一些基本規(guī)則。 我們從二維正方形網(wǎng)格上的隨機(jī)配置開始。 網(wǎng)格中的每個單元可以是死的或活著的。 此狀態(tài)取決于小區(qū)的鄰居。 您可以在這個頁面上詳細(xì)了解規(guī)則。在每個時(shí)間步上,都會發(fā)生以下轉(zhuǎn)換:
- 少于兩個活鄰居的活細(xì)胞死亡。
- 具有兩個或三個活鄰居的活細(xì)胞可以存活到下一代。
- 具有三個以上活鄰居的活細(xì)胞死亡。
- 具有恰好三個活鄰居的死細(xì)胞會成為活細(xì)胞。
卷積可用于求值游戲的基本規(guī)則。 卷積過程需要 SciPy 包。
實(shí)戰(zhàn)時(shí)間 – 模擬生命
以下代碼是生命游戲的實(shí)現(xiàn) ,并進(jìn)行了一些修改:
- 用鼠標(biāo)單擊一次會畫一個十字,直到我們再次單擊
-
r
鍵可將網(wǎng)格重置為隨機(jī)狀態(tài) -
b
鍵根據(jù)鼠標(biāo)位置創(chuàng)建塊 -
g
鍵創(chuàng)建滑翔機(jī)
代碼中最重要的數(shù)據(jù)結(jié)構(gòu)是一個二維數(shù)組,其中包含游戲屏幕上像素的顏色值。 該數(shù)組用隨機(jī)值初始化,然后針對游戲循環(huán)的每次迭代重新計(jì)算。 在下一部分中找到有關(guān)所涉及函數(shù)的更多信息。
-
要求值規(guī)則,請使用卷積,如下所示:
def get_pixar(arr, weights): states = ndimage.convolve(arr, weights, mode='wrap') bools = (states == 13) | (states == 12 ) | (states == 3) return bools.astype(int)
-
使用我們在第 2 章,“從 NumPy 基礎(chǔ)知識開始”中學(xué)習(xí)的基本索引技巧來畫十字:
def draw_cross(pixar): (posx, posy) = pygame.mouse.get_pos() pixar[posx, :] = 1 pixar[:, posy] = 1
-
用隨機(jī)值初始化網(wǎng)格:
def random_init(n): return np.random.random_integers(0, 1, (n, n))
以下是完整的代碼:
from __future__ import print_function import os, pygame from pygame.locals import * import numpy as np from scipy import ndimage def get_pixar(arr, weights): states = ndimage.convolve(arr, weights, mode='wrap') bools = (states == 13) | (states == 12 ) | (states == 3) return bools.astype(int) def draw_cross(pixar): (posx, posy) = pygame.mouse.get_pos() pixar[posx, :] = 1 pixar[:, posy] = 1 def random_init(n): return np.random.random_integers(0, 1, (n, n)) def draw_pattern(pixar, pattern): print(pattern) if pattern == 'glider': coords = [(0,1), (1,2), (2,0), (2,1), (2,2)] elif pattern == 'block': coords = [(3,3), (3,2), (2,3), (2,2)] elif pattern == 'exploder': coords = [(0,1), (1,2), (2,0), (2,1), (2,2), (3,3)] elif pattern == 'fpentomino': coords = [(2,3),(3,2),(4,2),(3,3),(3,4)] pos = pygame.mouse.get_pos() xs = np.arange(0, pos[0], 10) ys = np.arange(0, pos[1], 10) for x in xs: for y in ys: for i, j in coords: pixar[x + i, y + j] = 1 def main(): pygame.init () N = 400 pygame.display.set_mode((N, N)) pygame.display.set_caption("Life Demo") screen = pygame.display.get_surface() pixar = random_init(N) weights = np.array([[1,1,1], [1,10,1], [1,1,1]]) cross_on = False while True: pixar = get_pixar(pixar, weights) if cross_on: draw_cross(pixar) pygame.surfarray.blit_array(screen, pixar * 255 ** 3) pygame.display.flip() for event in pygame.event.get(): if event.type == QUIT: return if event.type == MOUSEBUTTONDOWN: cross_on = not cross_on if event.type == KEYDOWN: if event.key == ord('r'): pixar = random_init(N) print("Random init") if event.key == ord('g'): draw_pattern(pixar, 'glider') if event.key == ord('b'): draw_pattern(pixar, 'block') if event.key == ord('e'): draw_pattern(pixar, 'exploder') if event.key == ord('f'): draw_pattern(pixar, 'fpentomino') if __name__ == '__main__': main()
您應(yīng)該能夠從代碼包(
life.mp4
)或 YouTube 上觀看截屏視頻。 正在運(yùn)行的游戲的屏幕截圖如下:
剛剛發(fā)生了什么?
我們使用了一些 NumPy 和 SciPy 函數(shù),這些函數(shù)需要說明:
函數(shù) | 描述 |
---|---|
ndimage.convolve(arr, weights, mode='wrap') |
此函數(shù)在包裝模式下使用權(quán)重將卷積運(yùn)算應(yīng)用于給定數(shù)組。 該模式與數(shù)組邊界有關(guān)。 |
bools.astype(int) |
此函數(shù)將布爾數(shù)組轉(zhuǎn)換為整數(shù)。 |
np.arange(0, pos[0], 10) |
此函數(shù)以 10 為步長創(chuàng)建一個從 0 到pos[0] 的數(shù)組。因此,如果pos[0] 等于 1000,我們將得到 0、10、20,… 990。 |
總結(jié)
您可能會發(fā)現(xiàn)本書中提到 Pygame 有點(diǎn)奇怪。 但是,閱讀本章后,我希望您意識到 NumPy 和 Pygame 可以很好地結(jié)合在一起。 畢竟,游戲涉及大量計(jì)算,因此 NumPy 和 SciPy 是理想的選擇,并且它們還需要scikit-learn
中提供的人工智能功能。 無論如何,制作游戲都很有趣,我們希望最后一章相當(dāng)于十道菜后的精美甜點(diǎn)或咖啡! 如果您仍然渴望更多,請查看《NumPy Cookbook 第二版》, Ivan Idris,Packt Publishing,在本書的基礎(chǔ)上以最小的重疊為基礎(chǔ)。
附錄 A:小測驗(yàn)答案
第 1 章,NumPy 快速入門
小測驗(yàn) – arange()
函數(shù)的功能
arange(5) 做什么? |
它創(chuàng)建一個 NumPy 數(shù)組,其值為從 0-4 創(chuàng)建的 NumPy 數(shù)組的值,0、1、2、3 和 4 |
第 2 章,從 NumPy 基本原理開始
小測驗(yàn) – ndarray
的形狀
ndarray 的形狀如何存儲? |
它存儲在一個元組中 |
第 3 章,熟悉常用函數(shù)
小測驗(yàn) - 計(jì)算加權(quán)平均值
哪個函數(shù)返回?cái)?shù)組的加權(quán)平均值? | average |
第 4 章,為您帶來便利的便利函數(shù)
小測驗(yàn) - 計(jì)算協(xié)方差
哪個函數(shù)返回兩個數(shù)組的協(xié)方差? | cov |
第 5 章,使用矩陣和ufunc
小測驗(yàn) – 使用字符串定義矩陣
mat 和bmat 函數(shù)接受的字符串中的行分隔符是什么? |
分號 |
第 6 章,深入探索 NumPy 模塊
小測驗(yàn) - 創(chuàng)建矩陣
哪個函數(shù)可以創(chuàng)建矩陣? | mat |
第 7 章,探索特殊例程
小測驗(yàn) - 生成隨機(jī)數(shù)
哪個 NumPy 模塊處理隨機(jī)數(shù)? | random |
第 8 章,通過測試確保質(zhì)量
小測驗(yàn) - 指定小數(shù)精度
assert_almost_equal 函數(shù)的哪個參數(shù)指定小數(shù)精度? |
decimal |
第 9 章,matplotlib 繪圖
小測驗(yàn) – plot()
函數(shù)
plot 函數(shù)有什么作用? |
它既不執(zhí)行 1、2 也不執(zhí)行 3 |
第 10 章,當(dāng) NumPy 不夠用時(shí) – Scipy 和更多
小測驗(yàn) - 加載.mat
文件
哪個函數(shù)加載.mat 文件? |
loadmat |
附錄 B:其他在線資源
本附錄包含指向相關(guān)網(wǎng)站的鏈接。
Python 教程
- Think Python 中文第二版↗
- 笨辦法學(xué) Python · 續(xù) 中文版
- PythonSpot 中文系列教程
- PythonBasics 中文系列教程
- PythonGuru 中文系列教程
- Python 分布式計(jì)算↗
數(shù)學(xué)教程
- MIT 公開課課本/筆記
- MIT 18.06 線性代數(shù)筆記↗
- MIT 18.03 寫給初學(xué)者的微積分
數(shù)據(jù)科學(xué)文檔
- Numpy 技術(shù)棧中文文檔
- NumPy 1.11 中文文檔?
- Pandas 0.19.2 中文文檔?
- Matplotlib 2.0 中文文檔?
- statsmodels 中文文檔?
- seaborn 0.9 中文文檔?
- SimuPy 中文文檔↗
數(shù)據(jù)科學(xué)教程
- 斯坦福公開課課本/筆記
- 斯坦福 STATS60 課本:21 世紀(jì)的統(tǒng)計(jì)思維?
- 斯坦福博弈論中文筆記?
- UCB 公開課課本/筆記
- UCB Data8 課本:計(jì)算與推斷思維?
- UCB Prob140 課本:面向數(shù)據(jù)科學(xué)的概率論?
- UCB DS100 課本:數(shù)據(jù)科學(xué)的原理與技巧?
- ApacheCN 數(shù)據(jù)科學(xué)譯文集?
- TutorialsPoint NumPy 教程
- 復(fù)雜性思維 中文第二版
- 利用 Python 進(jìn)行數(shù)據(jù)分析 · 第 2 版
- fast.ai 數(shù)值線性代數(shù)講義 v2
- Pandas Cookbook 帶注釋源碼
- 數(shù)據(jù)科學(xué) IPython 筆記本
- UCSD COGS108 數(shù)據(jù)科學(xué)實(shí)戰(zhàn)中文筆記
- USF MSDS501 計(jì)算數(shù)據(jù)科學(xué)中文講義
- 數(shù)據(jù)可視化的基礎(chǔ)知識
- Joyful Pandas↗
附錄 C:NumPy 函數(shù)的參考
本附錄包含有用的 NumPy 函數(shù)及其說明的列表。
-
numpy.apply_along_axis
(func1d, axis, arr, *args
):沿arr
的一維切片應(yīng)用函數(shù)func1d
。 -
numpy.arange([start,] stop[, step,], dtype=None)
:創(chuàng)建一個 NumPy 數(shù)組,它在指定范圍內(nèi)均勻間隔。 -
numpy.argsort(a, axis=-1, kind='quicksort', order=None)
:返回對輸入數(shù)組進(jìn)行排序的索引。 -
numpy.argmax(a, axis=None)
:返回沿軸的最大值的索引。 -
numpy.argmin(a, axis=None)
:返回沿軸的最小值的索引。 -
numpy.argwhere(a)
:查找非零元素的索引。 -
numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)
:從類似數(shù)組的序列(例如 Python 列表)創(chuàng)建 NumPy 數(shù)組。 -
numpy.testing.assert_allclose((actual, desired, rtol=1e-07, atol=0, err_msg='', verbose=True)
:如果兩個對象在指定的精度下不相等,則引發(fā)錯誤。 -
numpy.testing.assert_almost_equal()
:如果兩個數(shù)字在指定的精度下不相等,則引發(fā)異常。 -
numpy.testing.assert_approx_equal()
:如果兩個數(shù)字在某個有效數(shù)字下不相等,則引發(fā)異常。 -
numpy.testing.assert_array_almost_equal()
:如果兩個數(shù)組在指定的精度下不相等,則引發(fā)異常。 -
numpy.testing.assert_array_almost_equal_nulp(x, y, nulp=1)
:將數(shù)組與其最低精度單位(ULP)。 -
numpy.testing.assert_array_equal()
:如果兩個數(shù)組不相等,則引發(fā)異常。 -
numpy.testing.assert_array_less()
:如果兩個數(shù)組的形狀不同,并且第一個數(shù)組的元素嚴(yán)格小于第二個數(shù)組的元素,則會引發(fā)異常。 -
numpy.testing.assert_array_max_ulp(a, b, maxulp=1, dtype=None)
:確定數(shù)組元素最多相差 ULP 的指定數(shù)量。 -
numpy.testing.assert_equal()
:測試兩個 NumPy 數(shù)組是否相等。 -
numpy.testing.assert_raises()
:如果使用定義的參數(shù)調(diào)用的可調(diào)用對象未引發(fā)指定的異常,則失敗。 -
numpy.testing.assert_string_equal()
:斷言兩個字符串相等。 -
numpy.testing.assert_warns()
:如果未引發(fā)指定的警告,則失敗。 -
numpy.bartlett(M)
:返回帶有M
點(diǎn)的 Bartlett 窗口。 此窗口類似于三角形窗口。 -
numpy.random.binomial(n, p, size=None)
:從二項(xiàng)分布中抽取隨機(jī)樣本。 -
numpy.bitwise_and(x1, x2[, out])
:計(jì)算數(shù)組的按位AND
。 -
numpy.bitwise_xor(x1, x2[, out])
:計(jì)算數(shù)組的按位XOR
。 -
numpy.blackman(M)
:返回一個具有M
點(diǎn)的布萊克曼窗口,該窗口接近最佳值,并且比凱撒窗口差。 -
numpy.column_stack(tup)
:堆疊以元組列形式提供的一維數(shù)組 。 -
numpy.concatenate ((a1, a2, ...), axis=0)
:將數(shù)組序列連接在一起。 -
numpy.convolve(a, v, mode='full')
:計(jì)算一維數(shù)組的線性卷積。 -
numpy.dot(a, b, out=None)
:計(jì)算兩個數(shù)組的點(diǎn)積。 -
numpy.diff(a, n=1, axis=-1)
:計(jì)算給定軸的 N 階差。 -
numpy.dsplit(ary, indices_or_sections)
:沿著第三軸將數(shù)組拆分為子數(shù)組。 -
numpy.dstack(tup)
:沿第三軸堆疊以元組形式給出的數(shù)組。 -
numpy.eye(N, M=None, k=0, dtype=<type 'float'>)
:返回單位矩陣。 -
numpy.extract(condition, arr)
:使用條件選擇數(shù)組的元素。 -
numpy.fft.fftshift(x, axes=None)
:將信號的零頻率分量移到頻譜的中心。 -
numpy.hamming(M)
:返回帶有M
點(diǎn)的漢明窗口。 -
numpy.hanning(M)
:返回具有M
點(diǎn)的漢寧窗口。 -
numpy.hstack(tup)
:水平堆疊以元組形式給出的數(shù)組。 -
numpy.isreal(x)
:返回一個布爾數(shù)組,其中True
對應(yīng)于輸入數(shù)組的實(shí)數(shù)(而不是復(fù)數(shù))元素。 -
numpy.kaiser(M, beta)
:對于給定的beta
參數(shù),返回帶有M
點(diǎn)的凱撒窗口。 -
numpy.load(file, mmap_mode=None)
:從.npy
,.npz
,或腌制中加載 NumPy 數(shù)組或腌制對象。 內(nèi)存映射的數(shù)組存儲在文件系統(tǒng)中,不必完全加載到內(nèi)存中。 這對于大型數(shù)組尤其有用。 -
numpy.loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)
:將文本文件中的數(shù)據(jù)加載到 NumPy 數(shù)組中。 -
numpy.lexsort (keys, axis=-1)
:使用多個鍵進(jìn)行排序。 -
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
:返回在間隔內(nèi)均勻間隔的數(shù)字。 -
numpy.max(a, axis=None, out=None, keepdims=False)
:沿軸返回?cái)?shù)組的最大值。 -
numpy.mean(a, axis=None, dtype=None, out=None, keepdims=False)
:沿給定軸計(jì)算算術(shù)平均值。 -
numpy.median(a, axis=None, out=None, overwrite_input=False)
:沿給定軸計(jì)算中位數(shù) 。 -
numpy.meshgrid(*xi, **kwargs)
:返回坐標(biāo)向量的坐標(biāo)矩陣。 例如:In: numpy.meshgrid([1, 2], [3, 4]) Out: [array([[1, 2], [1, 2]]), array([[3, 3], [4, 4]])]
-
numpy.min(a, axis=None, out=None, keepdims=False)
:沿軸返回?cái)?shù)組的最小值。 -
numpy.msort(a)
:返回沿第一軸排序的數(shù)組的副本。 -
numpy.nanargmax(a, axis=None)
:返回給定一個忽略 NaN 的軸的最大值的索引。 -
numpy.nanargmin(a, axis=None)
:返回給定的軸的最小值索引,忽略 NaN。 -
numpy.nonzero(a)
:返回非零數(shù)組元素的索引。 -
numpy.ones(shape, dtype=None, order='C')
:創(chuàng)建指定形狀和數(shù)據(jù)類型的 NumPy 數(shù)組,包含 1s。 -
numpy.piecewise(x, condlist, funclist, *args, **kw)
:分段求值函數(shù)。 -
numpy.polyder(p, m=1)
:將多項(xiàng)式微分為給定階數(shù)。 -
numpy.polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False)
:執(zhí)行最小二乘多項(xiàng)式擬合。 -
numpy.polysub(a1, a2)
:減去多項(xiàng)式。 -
numpy.polyval(p, x)
:以指定值求值多項(xiàng)式。 -
numpy.prod(a, axis=None, dtype=None, out=None, keepdims=False)
:返回指定軸上數(shù)組元素的乘積 。 -
numpy.ravel(a, order='C')
:展平數(shù)組,或在必要時(shí)返回副本。 -
numpy.reshape(a, newshape, order='C')
:更改 NumPy 數(shù)組的形狀 。 -
numpy.row_stack(tup)
:逐行堆疊數(shù)組。 -
numpy.save(file, arr)
:以 NumPy.npy
格式將 NumPy 數(shù)組保存到文件中。 -
numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# ')
:將 NumPy 數(shù)組保存到文本文件。 -
numpy.sinc(a)
:計(jì)算sinc
函數(shù)。 -
numpy.sort_complex(a)
:首先以實(shí)部,然后是虛部對數(shù)組元素進(jìn)行排序。 -
numpy.split(a, indices_or_sections, axis=0)
:將數(shù)組拆分為子數(shù)組。 -
numpy.std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False)
:沿給定軸返回標(biāo)準(zhǔn)差。 -
numpy.take(a, indices, axis=None, out=None, mode='raise')
:使用指定的索引從數(shù)組中選擇元素。 -
numpy.vsplit(a, indices_or_sections)
:將數(shù)組垂直拆分為子數(shù)組。 -
numpy.vstack(tup)
:垂直堆疊數(shù)組。 -
numpy.where(condition, [x, y])
:基于布爾條件從輸入數(shù)組中選擇數(shù)組元素。文章來源:http://www.zghlxwxcb.cn/news/detail-414986.html -
numpy.zeros(shape, dtype=float, order='C')
:創(chuàng)建指定形狀和數(shù)據(jù)類型的 NumPy 數(shù)組,其中包含零。文章來源地址http://www.zghlxwxcb.cn/news/detail-414986.html
到了這里,關(guān)于NumPy 初學(xué)者指南中文第三版:11~14的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!