前の記事:
Python pygame (GUI プログラミング) モジュールの最も完全なチュートリアル (6)_Python-ZZY のブログ - CSDN ブログ
リスト:
README.md · Python-ZZY/Python-Pygame の最も完全なチュートリアル - Gitee.com
21 OpenGL と Pygame
OpenGL を知らない読者は、この章を飛ばしてください。
21.1 OpenGL の概要
参考文献: https://baike.baidu.com/item/OpenGL/238984
OpenGL は 2D および 3D レンダリング用の API で、主に C/C++ で使用されます。Python サードパーティ モジュール pyopengl は、OpenGL のサポートを提供します。
pygame で OpenGL を使用すると、一部の 3D 画像をレンダリングしたり、レンダリング速度を向上させることができます (OpenGL は GPU を使用するため)。OpenGL の基礎を持たない読者は自分で検索できるため、ここでは繰り返しません。
21.2 OpenGLをサポートするWindows
pygame で OpenGL を使用するには、set_mode メソッドを呼び出してウィンドウを設定するときに 2 つのフラグを渡すだけで済みます。
pg.DOUBLEBUF | pg.OPENGL
OPENGL は、このウィンドウが OpenGL レンダリングに使用されることを示します。DOUBLEBUF は、ウィンドウがダブル バッファ モードに設定されていることを意味します。これは OpenGL 描画に便利です。その後、OpenGL の他の機能は通常どおり使用できるようになります。
pg.display.set_mode(display, DOUBLEBUF | OPENGL)
22 の表面ピクセルとメモリ
参考文献:
https://pyga.me/docs/ref/pixelarray.html
https://pyga.me/docs/ref/bufferproxy.html
https://pyga.me/docs/ref/surfarray.html
https://pyga.me/docs/ref/pixelcopy.html
22.1 単一の表面ピクセルの設定と取得
Surface オブジェクトには、サーフェス内の単一ピクセルのカラー値を設定および取得するための set_at メソッドと get_at メソッドが用意されています。
pg.Surface.set_at((x, y), Color) -> None
pg.Surface.get_at((x, y)) -> Color
サーフェスの個々のピクセルを操作することで、次のようにサーフェスを微調整できます。
for x in range(image.get_width() // 2 + 1):
for y in range(image.get_height() // 2 + 1):
image.set_at((x * 2, y * 2), (0, 0, 0)) # 将偶数位置的点设为黑色
22.2 表面メモリのロック
前回の記事では、pg.draw モジュールを使用してグラフィックスを描画する方法を紹介しました。ただし、この描画方法はピクセル単位で処理するため、速度が遅くなる場合があります。pg.draw で大量の描画を行う場合、描画速度を向上させるためにサーフェス メモリをロックする必要があることがよくあります。サーフェスのロック期間中は pg.draw が元の速度の約 2 倍まで高速になりますが、ロック期間中のサーフェスはブリットなどのメソッドで処理できず、ブリットを呼び出すこともできないため、抽選が完了するとロックが解除されます。
Surface.lock() -> None
Surface.unlock() -> None
lock メソッドと lock メソッドは、それぞれサーフェスをロックおよびロック解除するために使用されます。最初にサーフェスをロックし、描画後にサーフェスのロックを解除します
surf.lock() # 锁定表面以提高速度,锁定期间只能操作像素而不能被blit
...
pg.draw.rect(surf, ...) # do some drawing
surf.set_at(...)
...
surf.unlock() # 重新解锁表面,这样就可以绘制到屏幕上
以下は、ロックを使用した後の pg.draw の速度の違いを示す例です。(コードの実行時間を測定するには timeit モジュールを使用します)
import pygame as pg
from timeit import timeit
def estimate(*args):
'''估算代码运行200次花费的时间'''
return timeit(*args, number=200, globals=globals())
def draw(surf):
'''在表面上进行绘制操作'''
pg.draw.rect(surf, (255, 255, 255), (0, 0, 200, 200), width=20)
pg.draw.polygon(surf, (255, 0, 0), ((20, 100), (100, 20), (180, 100), (100, 180)))
pg.draw.circle(surf, (255, 255, 255), (100, 100), 80, width=5)
surf.set_at((100, 100), (0, 0, 0))
def func():
'''没有锁定时的pg.draw调用'''
im = image.copy()
draw(im)
def func2():
'''加上锁定后的pg.draw调用'''
im = image.copy()
im.lock() # 锁定表面以提高速度,锁定期间只能操作像素而不能被blit
draw(im)
im.unlock() # 重新解锁表面,这样就可以绘制到屏幕上
pg.init()
screen = pg.display.set_mode((450, 300))
image = pg.Surface((200, 200))
print(estimate("func()"))
print(estimate("func2()"))
# 输出
0.020117499865591526
0.011690699961036444
22.3 ピクセル配列
pg.PixelArray オブジェクトは配列であり、サーフェス内のピクセルに直接アクセスできるため、より便利です。Surface オブジェクトの PixelArray オブジェクト生成後は自動的にサーフェスがロックされ、PixelArray オブジェクトが削除(del)されると自動的にサーフェスのロックが解除されます。
pg.PixelArray(Surface) -> PixelArray
サーフェスをパラメータとして PixelArray に渡し、そのサーフェスのピクセル配列を作成します。PixelArray は、numpy.array と同様に、インデックス付けとスライスによって管理できます。
2 タプル (x, y) を PixelArray オブジェクトへのインデックスとして使用すると、位置 (x, y) のピクセルのカラー値が設定されます。これは、サーフェス上で set_at 操作を直接実行することと同等です。カラー値は、整数 (16 進カラー形式)、pg.Color オブジェクト、または直接 (R、G、B) タプルにすることができますが、カラー名は使用できません。
pxarray[x, y] = 0xFF0000
pxarray[x, y] = pg.Color(255, 0, 0, 255)
pxarray[x, y] = (255, 0, 0)
## pxarray[x, y] = "red" # ValueError: sequence size mismatch
ピクセルを取得する場合は少し異なります。PixelArray は、すべてのピクセル カラーを特別な整数形式に変換します。これは、取得または比較する前に、Surface.map_rgb または Surface.unmap_rgb で変換する必要があります。このピクセル整数はサーフェスのビット深度と特定の関係があるため、PixelArray にバインドされたサーフェス上で map_rgb または unmap_rgb を呼び出す必要があります。そうしないと問題が発生する可能性があります。
Surface.map_rgb(Color) -> mapped_int
Surface.unmap_rgb(mapped_int) -> Color
unmap_rgb はピクセル整数を pg.Color オブジェクトに変換するために使用され、map_rgb はカラーをピクセル整数に変換するために使用されます。map_rgb オブジェクトは、pg.Color オブジェクトまたは (R、G、B) タプルのみをパラメーターとして渡すことができます。
ピクセル (100, 50) の色が赤かどうかを判断したい場合は、次のようにします。
image = ... # pg.Surface
pxarray = pg.PixelArray(image)
if pxarray[100, 50] == image.map_rgb((255, 0, 0)):
...
# 或者:
if image.unmap_rgb(pxarray[100, 50]) == (255, 0, 0):
...
PixelArray は添え字スライスもサポートしています。つまり、インデックス (x, y) タプル内の各項目はコロンで区切られます。たとえば、[0:50, 0] は、x 座標の範囲が 0 ~ 50 であり、y 座標が 0 の配列であることを意味します。この場合、返されるのは 1 要素のピクセル配列になります。これには、元の配列の x 座標が 0 ~ 50 で始まり、y 座標が 0 である部分が含まれます。例は次のとおりです。
pxarray[0:50, 0] = (255, 0, 0)
修正面は以下の通り、赤線が修正部分です
同様に、y を表すタプルの部分も変更できます。例えば:
pxarray[0:50, 0:100] = (255, 0, 0)
もちろん、色が固定されていない場合は、次のようにすることもできます。
pxarray[0:50, 0:100] = [(255, 0, 0), (255, 255, 0), (2, 2, 2), ...] # 省略了若干颜色
スライスにはストライドを含めることもできます。
pxarray[0:50:2, 0:100] = (255, 0, 0)
スライスする場合、その中の数字を省略することもでき、効果はリストのスライスと同じです。したがって、セクション 22.1 の例は次のように表すことができます。
pxarray[::2, ::2] = (0, 0, 0)
インデックスがタプルではなく、タプルの単一部分である場合、この部分は x 座標を表すとみなされ、y の値はデフォルトで :: になります。次の 2 行のコードは同じ意味を持ちます。
pxarray[0:50] = (255, 0, 0)
# 或者:
pxarray[0:50, ::] = (255, 0, 0)
# 或者:
pxarray[0:50, ...] = (255, 0, 0)
スライスする際、省略された部分を::または...に置き換えることができます。
pxarray[..., 0:50] = (255, 0, 0)
同様に、次のコードを使用すると、表面全体が赤で塗りつぶされることを意味し、fill メソッドと同じ効果があります。
pxarray[...] = (255, 0, 0)
サーフェス上のピクセル配列を変更した後、del メソッドを使用してピクセル配列を削除する必要があります。そうしないと、サーフェスは常にロックされ、ブリットできなくなります。変更が関数内に具体的に記述されている場合、それを削除する必要はなく、Python のガベージ コレクション メカニズムによって自動的に削除されます。完全な使用例は次のとおりです。
import pygame as pg
pg.init()
screen = pg.display.set_mode((450, 300))
clock = pg.time.Clock()
image = pg.image.load("logo.png")
pxarray = pg.PixelArray(image)
pxarray[::2, ::2] = (0, 0, 0)
del pxarray
while True:
screen.fill((0, 0, 0))
screen.blit(image, (0, 0))
for event in pg.event.get():
if event == pg.QUIT:
pg.quit()
clock.tick(60)
pg.display.flip()
操作効果はセクション 22.1 と同じです。
22.4 PixelArray オブジェクト メソッドのインデックス付け
表面 -> 表面
ピクセル配列で使用される表面
itemsize -> int
ピクセル配列内のバイト数。Pixel Array Surface.get_bytesize() 呼び出しと同じ結果。
人 -> 整数
ピクセル配列の次元 (1 または 2)。1 次元の場合、配列は行または列のピクセル値を表します。2D の場合、配列はサーフェス (またはサーフェスの一部) のピクセル値を表します。
形状 -> int のタプル
ピクセル配列の形状 (またはサイズ)。Pixel Array Surface.get_size() 呼び出しと同じ結果。
ストライド -> int のタプル
タプルまたは長さの ndim バイト数。ストライドに対応するインデックスを乗算すると、配列の先頭からのそのインデックスのオフセットが得られます。配列のストライドが負の場合、配列のストライドも負になります。
make_surface() -> 表面
ピクセルの配列から新しい Surface オブジェクトを生成します。
replace(color, repcolor, distance=0,weights=(0.299, 0.587, 0.114)) -> なし
ピクセル配列内の色を置き換えます。配列内の色を repcolor に置き換えます。また、ユークリッド加重距離式によるいくつかの類似色の置き換えもサポートしています。distance は 0 ~ 1 の浮動小数点数で、weight は R、G、B の色の重みを表します。
このメソッドはインプレースで変更し、新しい PixelArray オブジェクトを返しません。
extract(色, 距離=0, 重み=(0.299, 0.587, 0.114)) -> PixelArray
一致する色をすべて白に置き換え、一致しない色を黒に置き換えます。同様の置換もサポートされています。
このメソッドは、新しい PixelArray オブジェクトを返します。
比較(配列, 距離=0, 重み=(0.299, 0.587, 0.114)) -> PixelArray
別のピクセル配列と比較し、その 2 つの違いを表す新しい PixelArray オブジェクトを返します。同じ位置で同じ色であれば白、同じでなければ黒に設定されます。
transpose() -> PixelArray
配列の x、y を交換し、新しい PixelArray オブジェクトを返します。(最初に反時計回りに 90 度回転し、次に上下に反転することに相当します)
close() -> PixelArray
アレイの電源をオフにし、サーフェスのロックを解除します。
22.5 surface 配列モジュールのインデックス付け - Surface 配列と numpy 配列
Numpy は、一般的に使用されている pygame のサードパーティ ライブラリであり、一連の数学的演算を提供します。numpy を知らない読者は、このセクションを自分で読み飛ばしてください。
pg.surfarray モジュールは、Surface と numpy.array を変換するために使用されます。そのため、pg.surfarray は numpy モジュールに依存しており、numpy がインストールされていないとsurfarray を使用できません。
surfacearray の一般的な効果は PixelArray の効果と似ているため、ここでは詳しく説明しませんが、pg.surfarray のプロパティとメソッドは以下のとおりです。
array2d(表面) -> 配列
Surface 内のピクセルをコピーし、2 次元の numpy 配列を生成します。各ピクセルは整数のマップ値として表現され、Surface.unmap_rgb を使用して (r, g, b) に変換する必要があります。
ピクセル2d(表面) -> 配列
array2d と同じですが、Surface 内のピクセルをコピーする代わりに、PixelArray と同様に、各ピクセルが元の Surface に関連付けられた配列を直接返します。そのため、Surface をロックし、配列が削除されるまで待ってからロックを解除します。
array3d(表面) -> 配列
Surface 内のピクセルをコピーし、3 次元の numpy 配列を生成します。この配列は実際には 2 次元配列と同じ意味を持ちますが、各ピクセルは [r, g, b] リストで表されるため、3 次元になります。
ピクセル3d(表面) -> 配列
array3d と同じですが、Surface 内のピクセルをコピーせず、PixelArray と同様に、各ピクセルが元の Surface に関連付けられた配列を直接返します。そのため、Surface をロックし、配列が削除されるまで待ってからロックを解除します。
array_alpha(表面) -> 配列
2 次元配列を生成します。各ピクセルはピクセルのアルファ値、つまり (R, G, B, A) の A を表します。
ピクセル_アルファ(表面) -> 配列
array_alpha と同じですが、Surface 内のピクセルをコピーせず、PixelArray と同様に、各ピクセルが元の Surface に関連付けられた配列を直接返します。そのため、Surface をロックし、配列が削除されるまで待ってからロックを解除します。
array_red(表面) -> 配列
2 次元配列を生成します。各ピクセルはピクセルの Red 値、つまり (R、G、B、A) の R を表します。
同様に、array_green、array_blue メソッドもありますが、スペースを節約するためにここにはリストされていません。
ピクセル_赤 (表面) -> 配列
同様に、pixels_green、pixels_blue メソッドもありますが、スペースを節約するためにここにはリストされていません。
array_colorkey(表面) -> 配列
2 次元配列を生成し、各ピクセルがピクセルのカラーキーを表します。カラーキーの色と一致する場合は 0 (透明)、それ以外の場合は 255 (不透明) として表示されます。
make_surface(配列) -> 表面
2D または 3D 配列をサーフェスに変換します
blit_array(表面, 配列) -> なし
配列をサーフェスに変換し、サーフェス上に描画します。サーフェスと配列のサイズは同じでなければなりません。これは Surface.blit(pg.surfarray.ake_surface(array), (0, 0)) と同等ですが、より高速になります。
マップ配列(表面、配列3d) -> 配列2d
3次元配列を2次元配列に変換
22.6 BufferProxy オブジェクトのメソッド索引
BufferProxy は文字通りバッファ プロキシと訳され、表面上の最も原始的な情報を保存し、pygame モジュールの鍵となります。BufferProxy を直接呼び出してインスタンス化することもできますが、表面上の get_view および get_buffer メソッドを通じて使用することが一般的です。
Surface.get_buffer() -> BufferProxy
Surface.get_view(<kind>='2') -> BufferProxy
get_buffer はサーフェスのピクセル バッファーを生成します。BufferProxy と PixelArray の内容は実際には似ています。
get_view は、サーフェスの内部ピクセル バッファーを配列としてエクスポートします。kind 引数は、長さ 1 の文字列 '0'、'1'、'2'、'3'、'r'、'g'、'b'、または 'a' です。'0' は連続した非構造化バイト ビューを返し、'1' は (表面の幅*表面の高さ) の連続したピクセル配列を返し、「2」は (表面の幅、表面の高さ) の生のピクセル配列 (デフォルト) を返します。 '3' は (surface-width, surface-height, 3) RGB カラー配列を返します。'r'、'g'、'b'、'a' はそれぞれ、単一のカラー プレーン配列を返すことを意味します。「a」は、深さ = 32 のサーフェスでのみサポートされ、サーフェスの flags パラメータが SRCALPHA に設定されます。
どちらの方法でも、サーフェスが削除されるまでロックされます。
BufferProxy は低レベルすぎて、メモリの概念が多く含まれるため、作者はよく理解しておらず、基本的に使い方がわかりません。以下にそのメソッドとプロパティを直接リストします。
親 -> サーフェス
親 -> <親>
ピクセル バッファーによって使用されるサーフェス (またはインスタンス化時に BufferProxy に渡されるパラメーター)
長さ -> 整数
エクスポートされる有効なバイト数。非連続データ、つまりメモリの単一ブロックではないデータの場合、ギャップ内のバイトはカウントから除外されます。この属性は、Py_buffer の C 構造体の len フィールドに相当します。
生 -> バイト
ピクセルバッファのソースコード。
write(バッファ、オフセット=0)
親オブジェクトのデータのバイトを上書きします。データは連続した C または F である必要があります。そうでない場合は、ValueError が発生します。パラメータ バッファは str/bytes オブジェクトです。オプションのオフセットは、バッファ内で上書きを開始する開始位置 (バイト単位) を指定します。オフセットが負の場合、またはバッファ プロキシの長さの値以上の場合は、IndexException がスローされます。len(バッファ) > プロキシの場合。長さ + オフセットの場合、ValueError がスローされます。
23 パイゲーム探検
参考文献: https://pyga.me/docs/ref/pygame.html
23.1 pygameメインモジュールインデックス
最初にサブモジュールを紹介すると、最後の近くでメインの pygame モジュールを紹介するのが混乱する可能性があります。しかし実際には、pygame のメイン モジュールには特に重要な内容はありません。読者は pygame を学習する際に、メイン モジュールでよく使用される関数をすでに理解しているため、いくつかの関数の使用方法は次に整理されます。
メインの pygame モジュールで使用されそうなものは次の 4 つだけです (残りはほとんど役に立ちません)。
init() -> (numpass、numfail)
pygame のすべてのサブモジュールを初期化し、成功した初期化と失敗した初期化の数を返します。
実際、pygame の各サブモジュールには init メソッドと quit メソッドがあり、これらは単一のサブモジュールを初期化して終了するために使用されます。Pygame には多くの機能があり、単にゲームを作成するだけでなく、音楽の再生などにも使用される場合があります。pygame.mixer モジュールのみを使用する必要がある場合は、pygame 全体を初期化する必要はなく、pygame.init() の代わりに pygame.mixer.init() を呼び出すだけです。
quit() -> なし
init メソッドの逆で、pygame を終了します。このメソッドは pygame ウィンドウを閉じます。pg.quit メソッドを呼び出しても、Python プログラム全体は終了せず、pygame のみが終了します。Python プログラムが完全に終了することを確認するために、終了時に sys.exit を呼び出す必要がある場合があります。
register_quit(呼び出し可能) -> なし
機能を登録します。pygame.quit が呼び出されたときに呼び出されます。
エラー
pygame.error は Exception を継承し、pygame 関連の例外を示します。例外キャッチに使用できます。
23.2 環境変数
pygame の動作の一部は、環境変数、つまり os.environ の操作によって制御できます。以下は、一般的に使用される pygame 関連の環境変数とその使用法です。
PYGAME_DISPLAY
pygameの表示インデックス(つまり、pg.display.set_modeの表示パラメータ)。デフォルトは「0」です。
PYGAME_FORCE_SCALE
set_mode にズーム表示モードを強制的に使用します (「デフォルト」または「写真」)。「写真」が設定されている場合、スケーリングには、可能な場合は最も低速ですが最高品質の異方性スケーリング アルゴリズムが使用されます。pygame.display.set_mode() を呼び出す前に設定する必要があります
PYGAME_BLEND_ALPHA_SDL2
これにより、pygame はすべてのアルファ ブレンドに SDL2 ブリッターを使用するようになります。SDL2 レンダラーはデフォルトよりも高速な場合がありますが、異なる計算式を使用するため、最終的な色が異なる場合があります。インポートされたすべての pygame モジュールを初期化するには、pygame.init() を呼び出す前に設定する必要があります。
PYGAME_HIDE_SUPPORT_PROMPT
pygame起動時に出力されるプロンプトを非表示にするかどうかは、「1」に設定すると非表示になります。
PYGAME_CAMERA
「opencv」などのカメラのバックエンドを設定します。pg.camera が初期化される前に呼び出す必要があります。
SDL_IME_SHOW_UI
入力候補ボックスを表示するかどうか。pg.display.set_mode の前に呼び出す必要があります
SDL_VIDEO_CENTERED
ウィンドウを画面の中央に配置するかどうか。pg.display.set_mode の前に呼び出す必要があります
SDL_VIDEO_WINDOW_POS
pygame ウィンドウの位置 (左上隅) を「x, y」の形式で設定します。pg.display.set_mode の前に呼び出す必要があります
SDL_VIDEO_ALLOW_SCREENSAVER
デフォルトでは、pygame の実行中にスクリーン セーバーは無効になります。「1」に設定すると、スクリーン セーバー システムの表示が許可されることを意味します。
SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS
デフォルトでは、ウィンドウにフォーカスがない場合、ゲームパッドなどのデバイスは更新されません。ただし、この環境変数を使用すると、ウィンドウがバックグラウンドにあるときでもジョイスティックの更新を取得できます。pygame.init() を呼び出す前に設定する必要があります。
23.3 _sdl2
実験的な SDL2 機能の一部が pygame._sdl2 モジュールに含まれていますが、将来変更される可能性があります。_sdl2 にはいくつかのサブモジュールも含まれています。_sdl2 は pygame に自動的にインポートされません。
_sdl2 には次のモジュールが含まれています。
モジュール名 | 説明 |
コントローラ | コントローラー(ゲームパッドなど)の操作 |
触る | タッチスクリーン入力 |
窓 | pygameマルチウィンドウ |
ビデオ | 画像、テクスチャなどが含まれます。 |
終わっていません
この記事はまだ終わっていない可能性があります(次の記事にスキップすることも可能です)