読者です 読者をやめる 読者になる 読者になる

人工知能に関する断創録

人工知能、認知科学、心理学、ロボティクス、生物学などに興味を持っています。このブログでは人工知能のさまざまな分野について調査したことをまとめています。最近は、機械学習・Deep Learningに関する記事が多いです。



メッセージウィンドウの表示

Pygame

今回から4回にわたってメッセージウィンドウを実装します。まずは、ドラクエのような黒い背景に白い枠のウィンドウを表示してみることから始めます。今回作成するWindowクラスはメッセージウィンドウだけではなく、コマンドウィンドウ、ステータスウィンドウなどすべてのウィンドウの基礎になります。スペースキーを押すとウィンドウが表示され、もう一度押すと消えます。

pyrpg13.zip
f:id:aidiary:20100731152943p:plain

ウィンドウの表示

ウィンドウはWindowクラスで実装されています。Windowクラスの詳細に入る前に使い方から見てみます。下のコードはmain()関数のメインループです。

   # ウィンドウ
    wnd = Window(Rect(140,334,360,140))
    while True:
        clock.tick(60)
        # ウィンドウ表示中は更新を中止
        if not wnd.is_visible:
            map.update()
        offset = calc_offset(player)
        map.draw(screen, offset)
        wnd.draw(screen)  # ウィンドウの描画
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
            if event.type == KEYDOWN and event.key == K_ESCAPE:
                sys.exit()
            if event.type == KEYDOWN and event.key == K_SPACE:
                if wnd.is_visible:  # ウィンドウ表示中
                    wnd.hide()  # ウィンドウを隠す
                else:
                    wnd.show()  # ウィンドウを表示

Windowオブジェクトを作成してwndに格納しています。Windowクラスの引数はウィンドウの領域を表すRectオブジェクトです。この場合は、左上の座標が(140, 334)で幅が360、高さが140の矩形範囲にウィンドウを表示することを意味しています。

ウィンドウはwnd.draw()で描画しています。これではつねにウィンドウが表示されてしまうと思うかもしれませんが、ウィンドウの内部で表示するかしないかを判定するフラグを作って表示しない場合はdraw()しないようにしています。

    def draw(self, screen):
        """ウィンドウを描画"""
        if self.is_visible == False: return
        pygame.draw.rect(screen, (255,255,255), self.rect, 0)
        pygame.draw.rect(screen, (0,0,0), self.inner_rect, 0)

is_visibleが表示するかしないかのフラグです。is_visibleがFalseのときはすぐreturnされるので描画されません。

            if event.type == KEYDOWN and event.key == K_SPACE:
                if wnd.is_visible:  # ウィンドウ表示中
                    wnd.hide()  # ウィンドウを隠す
                else:
                    wnd.show()  # ウィンドウを表示

イベントハンドラで、スペースキーを押したときにウィンドウの表示と非表示を切り替えています。

        if not wnd.is_visible:
            map.update()

この部分は、ウィンドウが表示されている間、キャラクターが動けないようにする処理です。条件のif文をはずすとウィンドウを表示中でもキャラクターが自由に動いてしまいます。話しているあいだにどっか行かれたらちょっとやなので動けないようにしました(笑)

ウィンドウクラスの詳細

次にWindowクラスの詳細を見ていきます。ウィンドウは下図のように2つの矩形を重ね合わせた構造になっています。白で塗りつぶした外側の大きい矩形(rect)の上に黒で塗りつぶした内側の少し小さな矩形(inner_rect)を描画しています。こうすると白枠を持つウィンドウができるわけです。

f:id:aidiary:20100731152944p:plain

class Window:
    """ウィンドウの基本クラス"""
    EDGE_WIDTH = 4  # 白枠の幅
    def __init__(self, rect):
        self.rect = rect  # 一番外側の白い矩形
        # 内側の黒い矩形
        self.inner_rect = self.rect.inflate(-self.EDGE_WIDTH*2,
                                            -self.EDGE_WIDTH*2)
        self.is_visible = False  # ウィンドウを表示中か?
    def draw(self, screen):
        """ウィンドウを描画"""
        if self.is_visible == False: return
        pygame.draw.rect(screen, (255,255,255), self.rect, 0)
        pygame.draw.rect(screen, (0,0,0), self.inner_rect, 0)
    def show(self):
        """ウィンドウを表示"""
        self.is_visible = True
    def hide(self):
        """ウィンドウを隠す"""
        self.is_visible = False

内側の小さな黒い矩形はpygame.Rect.inflate()という関数で作っています。これは、矩形の中心を維持したまま指定した引数の分だけ小さな矩形を返す関数です。上の例では、X方向に8ピクセル、Y方向に8 ピクセル小さな矩形を返しています。draw()では、白い矩形(rect)→黒い矩形(inner_rect)の順で描画しています。

これでウィンドウを好きな位置に表示できるようになりました!次はキャラクターと会話するときに表示されるメッセージウィンドウを作っていきます。