見出し画像

7-2 スクリーン

同人誌について

 この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。

 同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで290ページの本になります。ぜひ、こちらもご購入ください。

(2024-03-28:ver1.0.4 に更新、2024-03-10:ver1.0.3 に更新)


説明と全体コード

 「src/mymod/image/screen.py」の説明です。画面描画の基礎になる関数群です。

 『Pygame』の例として紹介したプログラムでは、画面を作ったあと、スクリーンに直接描画をおこなっていました。この本で作るゲームでは、小さなバッファに描画をおこないます。そして、各フレームの最後に拡大してスクリーンに描画します。そうしたことをおこなうための関数群が、「screen.py」に入っています。

import pygame
from ..data.app import W, H, TITLE, IMAGE_ICON

buffer: pygame.Surface = pygame.Surface((W, H))

# ウィンドウの初期化
def init_win():
    # 開始画面サイズの計算と画面の作成
    d = pygame.display.get_desktop_sizes()[0]
    scale = min(d[0] * 0.8 // W, d[1] * 0.8 // H)   # 開始倍率
    size = (W * scale, H * scale)   # 開始画面サイズ
    pygame.display.set_mode(size, pygame.RESIZABLE) # 画面作成

    # ウィンドウの設定
    pygame.display.set_caption(TITLE)   # タイトルバー
    icon = pygame.image.load(IMAGE_ICON)
    pygame.display.set_icon(icon)   # アイコン

# バッファ取得
def get_buffer() -> pygame.Surface:
    return buffer

# 更新の前処理
def update_pre():
    pygame.display.update()     # 画面を更新

# 画面の消去
def clear():
    buffer.fill(pygame.Color(0, 0, 0))  # 画面を塗りつぶす

# 更新の後処理
def update_post():
    # 拡大率を計算して、バッファを拡大
    win = pygame.display.get_window_size()
    scale = min(win[0] / W, win[1] / H)
    dst = (W * scale, H * scale)
    scaled_buffer = pygame.transform.scale(buffer, dst)

    # オフセット位置を計算して描画
    offset = ((win[0] - dst[0]) / 2, (win[1] - dst[1]) / 2)
    screen = pygame.display.get_surface()
    screen.blit(scaled_buffer, offset)

    pygame.display.flip()       # 画面フリップ

インポート部分

 インポート部分を示します。

import pygame
from ..data.app import W, H, TITLE, IMAGE_ICON

 `data`パッケージから、横幅の`W`、高さの`H`、タイトルの`TITLE`、アイコン用画像のパスの`IMAGE_ICON`を読み込みます。

バッファの作成

 このモジュールでは、ゲーム画面を作るために小さな`Surface`を作り、そこに描画をおこないます。そのために用いる`Surface`を作り、変数`buffer`に格納します。

buffer: pygame.Surface = pygame.Surface((W, H))

ウィンドウの初期化

 次はウィンドウの初期化です。まずは画面作成の部分です。

# ウィンドウの初期化
def init_win():
    # 開始画面サイズの計算と画面の作成
    d = pygame.display.get_desktop_sizes()[0]
    scale = min(d[0] * 0.8 // W, d[1] * 0.8 // H)   # 開始倍率
    size = (W * scale, H * scale)   # 開始画面サイズ
    pygame.display.set_mode(size, pygame.RESIZABLE) # 画面作成

 `pygame.display.get_desktop_sizes()`関数でディスプレイのサイズを得ます。関数のあとに`[0]`を書いているのは、関数の戻り値のリストの0番目の要素(0番目のディスプレイ、主要なディスプレイ)を得ているためです。この値を変数`d`に代入します。

 次に、ディスプレイの横幅`d[0]`の`0.8`倍を、ゲーム画面の横幅`W`で割って整数にします。また、ディスプレイの高さ`d[1]`の`0.8`倍を、ゲーム画面の高さ`H`で割って整数にします。そして`min()`関数を使い、2つの値の小さい方を得て、開始時の拡大率`scale`に代入します。

 続いて、拡大率`scale`をもとに、開始画面サイズ`size`を計算します。そして`pygame.display.set_mode()`関数で画面を作成します。

 画面作成では、`pygame.display.set_mode()`の第2引数に、`pygame.RESIZABLE`を設定します。第2引数には、いくつかの設定を`|`繋ぎで書けます。ここでは、リサイズ可能にする`pygame.RESIZABLE`のみを書きます。

 リサイズ可能にしても、『Pygame』は描画サイズを自動で調整してくれません。そのため、自分で拡大描画する必要があります。

 次は、ウィンドウの設定です。

    # ウィンドウの設定
    pygame.display.set_caption(TITLE)   # タイトルバー
    icon = pygame.image.load(IMAGE_ICON)
    pygame.display.set_icon(icon)   # アイコン

 タイトルバーの文字を設定します。また、ウィンドウ左上用のアイコン画像(PNG画像)を読み込み、セットします。

バッファの取得、更新の前処理、画面の消

 次は、バッファの取得、更新の前処理、画面の消去といった小さな処理の関数です。

 処理自体はそれぞれ1行ですが、外部から抽象化して呼び出せるように関数化しています。

# バッファ取得
def get_buffer() -> pygame.Surface:
    return buffer

# 更新の前処理
def update_pre():
    pygame.display.update()     # 画面を更新

# 画面の消去
def clear():
    buffer.fill(pygame.Color(0, 0, 0))  # 画面を塗りつぶす

更新の後処理

 最後は更新の後処理です。

# 更新の後処理
def update_post():
    # 拡大率を計算して、バッファを拡大
    win = pygame.display.get_window_size()
    scale = min(win[0] / W, win[1] / H)
    dst = (W * scale, H * scale)
    scaled_buffer = pygame.transform.scale(buffer, dst)

    # オフセット位置を計算して描画
    offset = ((win[0] - dst[0]) / 2, (win[1] - dst[1]) / 2)
    screen = pygame.display.get_surface()
    screen.blit(scaled_buffer, offset)

    pygame.display.flip()       # 画面フリップ

 ウィンドウのサイズから拡大率を計算して、サイズを拡大したバッファを作成します。そして、画面の中央に描画するようにオフセット位置を計算して、スクリーンへの描画をおこないます。

 ウィンドウ サイズは`pygame.display.get_window_size()`関数で得ます。ウィンドウに内接する拡大率`scale`を計算して、拡大後のサイズ`dst`を求めます。このサイズ`dst`をもとに、バッファを拡大した`Surface`を、`pygame.transform.scale()`で得ます。

 スクリーンの`Surface`は、`pygame.display.get_surface()`関数で得ます。『Pygame』のサンプルでは、`pygame.display.set_mode()`の戻り値でスクリーンを得ていましたが、こうした関数でも得られます。


 次の内容については省略します。こちらは同人誌をご覧ください。

  • 7-3 ユーティリティ


同人誌について

 この連載は、同人誌『PythonとPygameで作る レトロ風RPG 全コード』を一部抜粋して編集したものです。

 同人誌本編には、ゲーム本体のソースコードや、各種のサンプルコード、Windowsで実行できるEXEファイルが付属しています。PDFで290ページの本になります。ぜひ、こちらもご購入ください。

(2024-03-28:ver1.0.4 に更新、2024-03-10:ver1.0.3 に更新)

 このnoteの記事と、Webページに一部抜粋版を掲載しています。

 技術系同人誌など まとめページ


この記事が気に入ったらサポートをしてみませんか?