見出し画像

7-4 スプライト1 キャラクター

同人誌について

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

https://ruten.booth.pm/items/5518418

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

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


説明と全体コード

 「src/mymod/image/chara.py」の説明です。

 このモジュールで作る`Chara`クラスは、`pygame.sprite.Sprite`を継承します。`Chara`クラスは、キャラクターを描画するためのスプライトです。

 このクラスには、コンストラクター`__init__()`と`update()`以外に、次のようなメソッドを作ります。

Charaクラスのメソッド

 キャラクターの画像は、次の用途で利用します。

  • タイトル画面で、キャラクターを大きく表示。

  • マップ画面で、主人公キャラクターが移動する様子を表示。

  • バトル画面で、敵キャラクターを大きく表示。ダメージを与えると揺れる。

import pygame
from ..data.app import U, IMAGE_CHARA
from .util import load_chip

imgs: list[pygame.Surface] = []

# キャラクター
class Chara(pygame.sprite.Sprite):
    # 初期化
    def __init__(self, img_nums: list[int]):
        super().__init__()
        global imgs
        if len(imgs) == 0: imgs = load_chip(IMAGE_CHARA, True)  # 画像読み込み
        self.images = list(map(lambda n: imgs[n], img_nums))    # 抜粋
        self.image = self.images[0]
        self.rect = pygame.Rect(0, 0, U, U)
        self.is_shake = False
        self.base_x = 0
        self.base_y = 0

    # 位置
    def set_pos(self, x: int, y: int):
        self.base_x = self.rect.x = x
        self.base_y = self.rect.y = y

    # サイズ
    def set_size(self, rate: int):
        self.rect.width  = int(U * rate)
        self.rect.height = int(U * rate)

    # 揺らす
    def shake(self, is_shake: bool):
        self.is_shake = is_shake

    # 更新
    def update(self):
        t = pygame.time.get_ticks()     # 経過時間
        i = t // 500 % len(self.images)
        image = self.images[i]
        size = (self.rect.width, self.rect.height)
        self.image = pygame.transform.scale(image, size)

        self.rect.x = self.base_x
        self.rect.y = self.base_y
        if self.is_shake:
            t2 = t // 40
            self.rect.x += - U // 2 + int(U * (t2 * 11 % 13 / 13))
            self.rect.y += - U // 2 + int(U * (t2 * 11 % 17 / 17))

インポート部分

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

import pygame
from ..data.app import U, IMAGE_CHARA
from .util import load_chip

 `data.app`から、描画単位`U`と、キャラクター画像のパス`IMAGE_CHARA`を読み込みます。

 画像を分割して読み込むので、`util`の`load_chip`を読み込みます。

読み込んだ画像の保持

 読み込んだ画像を保持する変数`imgs`です。

imgs: list[pygame.Surface] = []

 キャラクターの画像は最初に1度だけ読み込んで分割して、この変数`imgs`に代入します。

コンストラクター

 クラスの作成からコンストラクターまでを示します。

# キャラクター
class Chara(pygame.sprite.Sprite):
    # 初期化
    def __init__(self, img_nums: list[int]):
        super().__init__()
        global imgs
        if len(imgs) == 0: imgs = load_chip(IMAGE_CHARA, True)  # 画像読み込み
        self.images = list(map(lambda n: imgs[n], img_nums))    # 抜粋
        self.image = self.images[0]
        self.rect = pygame.Rect(0, 0, U, U)
        self.is_shake = False
        self.base_x = 0
        self.base_y = 0

 コンストラクターではまず、親クラス`Sprite`の`__init__()`関数を実行します。

 続いて、`global imgs`で、関数外の変数`imgs`に値を設定可能にします。そして変数`imgs`の要素数が`0`なら、画像を読み込んで分割して、変数`imgs`に代入します。

 この変数`imgs`の画像から、`img_nums`の参照位置の画像を抜き出して、キャラクターで使う画像のリストを作り、`self.images`に代入します。

 次に、コンストラクター内で重要なのは`self.image`と`self.rect`です。これらの値は、`Sprite`クラスの処理で利用されます。

 `self.is_shake`は、画像を揺らしているかのフラグです。

 `self.base_x` `self.base_y`の値は、画像を揺らしたあと、元の位置に戻すのに使います。

位置

 位置を設定する`set_pos()`関数です。

    # 位置
    def set_pos(self, x: int, y: int):
        self.base_x = self.rect.x = x
        self.base_y = self.rect.y = y

 `self.rect.x` `self.rect.y`の値と、`self.base_x` `self.base_y`の値を変更します。

サイズ

 サイズを変える`set_size()`関数です。

    # サイズ
    def set_size(self, rate: int):
        self.rect.width  = int(U * rate)
        self.rect.height = int(U * rate)

 ここでは数値のみ変えて、実際の拡大縮小は`update()`関数の中でおこないます。

揺らす

 `shake()`関数にbool値を与えることで、揺らす状態を変えます。

    # 揺らす
    def shake(self, is_shake: bool):
        self.is_shake = is_shake

更新

 更新をおこなう`update()`関数です。

    # 更新
    def update(self):
        t = pygame.time.get_ticks()     # 経過時間
        i = t // 500 % len(self.images)
        image = self.images[i]
        size = (self.rect.width, self.rect.height)
        self.image = pygame.transform.scale(image, size)

        self.rect.x = self.base_x
        self.rect.y = self.base_y
        if self.is_shake:
            t2 = t // 40
            self.rect.x += - U // 2 + int(U * (t2 * 11 % 13 / 13))
            self.rect.y += - U // 2 + int(U * (t2 * 11 % 17 / 17))

 経過時間に応じて、取り出す画像を変えてアニメーションをおこないます。`500`ミリ秒ごとに、画像を切り替えます。

 また、`self.images`から取り出した画像を`pygame.transform.scale()`関数でサイズを変えて、`self.image`に代入します。

 描画位置は、いったん`self.base_x` `self.base_y`に設定します。

 その後、`self.is_shake`が`True`のときは、描画位置をガタガタと揺らします。


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

  • 7-5 スプライト2 マップ

  • 7-6 フォント

  • 7-7 ダイアログ


同人誌について

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

https://ruten.booth.pm/items/5518418

https://crocro.com/shop/item/python_pygame_rpg.html

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

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

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

https://crocro.com/write/python_pygame_rpg/

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

https://crocro.com/shop/

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