人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

ウィンドウを表示する

まずは、すべてのゲームのひな形となるウィンドウを作成するプログラムです。ここでは、Pygameの初期化、メイン画面の作成、ゲームループなどを解説します。

f:id:aidiary:20100605082525p:plain

サンプルスクリプト

window.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import sys
 
SCREEN_SIZE = (640, 480)  # 画面サイズ
 
# Pygameを初期化
pygame.init()
# SCREEN_SIZEの画面を作成
screen = pygame.display.set_mode(SCREEN_SIZE)
# タイトルバーの文字列をセット
pygame.display.set_caption(u"ウィンドウの作成")
 
# ゲームループ
while True:
    screen.fill((0,0,255))   # 画面を青色で塗りつぶす
    pygame.display.update()  # 画面を更新
    # イベント処理
    for event in pygame.event.get():
        if event.type == QUIT:  # 終了イベント
            sys.exit()

プログラムの実行方法

Windowsをお使いなら上のプログラムをwindow.pyというファイルに保存して、ダブルクリックすれば実行できるはずです。上のプログラムをそのまま使う場合は、文字コードをutf-8にして保存してください。もし、シフトJISやEUC-JPを使いたい場合はファイルのエンコードを参照のこと。

ダブルクリックするとコマンドプロンプトもいっしょに表示されてしまいます。それがいやな場合は、window.pywというように拡張子をpywにしてダブルクリックしてみてください。コマンドプロンプトが表示されなくなります。LinuxやMacならターミナルを開いて python window.pyとコマンドを打てば実行できます。

ファイルのエンコード

# -*- coding: utf-8 -*-

は、スクリプトファイルの日本語文字コードにutf-8を使うことを意味しています。としてください。上のような変な記号の代わりに

# coding: utf-8

でもOKです。スクリプトで日本語を使わなければこの行はいりません。またスクリプトを実行すると

 UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

のようなエラーが出る場合があります(たぶん出ても見えずに一瞬でウィンドウが閉じてしまいます)。その場合は、Pythonのsite-packageディレクトリ(WindowsならC:\Python27\Lib\site-packages)に以下のスクリプトを書いたsitecustomize.pyというファイルを作ってください。

import sys
sys.setdefaultencoding('utf-8')

Pythonを使う場合は文字コードをutf-8で統一することをおすすめします。Windows付属のメモ帳はutf-8のファイルを開くと文字化けしますが、サクラエディタなど使うとutf-8でも何の問題なく開けます。ただ初めてファイルを保存するときはutf-8を選択しないといけないのが少しめんどくさいですが・・・

Pygameの初期化

ここから本格的にPygameの解説に入ります。まず、スクリプトの最初の2行

import pygame
from pygame.locals import *

は、Pygameを使う場合に必須のモジュールをインポートしています。画像を扱うpygame.image、図形を描画するpygame.draw、マウスを扱うpygame.mouseといったPygameの基本的なモジュールはすべてpygameの下に集まっています。これをインポートしないと始まりません。次の行の pygame.localsはpygameのさまざまな定数を格納したモジュールです。たとえば、QUITという定数は本当はpygame.locals.QUITです。ただこんな長いのを毎回書くのが面倒なのでfrom文でインポートしてQUITと省略して書けるようにしています。

# Pygameを初期化
pygame.init()

pygame.init()は、Pygameの各モジュールを初期化する関数です。Pygameのモジュールを使う前に実行する必要があります。

メイン画面の作成

SCREEN_SIZE = (640, 480)  # 画面サイズ

# SCREEN_SIZEの画面を作成
screen = pygame.display.set_mode(SCREEN_SIZE)
# タイトルバーの文字列をセット
pygame.display.set_caption(u"ウィンドウの作成")

pygame.display.set_mode()関数でメイン画面を作成します。引数には画面サイズをタプルで渡します。この場合は、640x480の画面ができます。Pygameでは画像を描画できる場所をSurfaceと呼んでいます(英語の発音はサーファス、サーフェイスではない!)。絵を描けるキャンバスみたいなイメージです。後で見るようにイメージをロードするなどしてSurfaceはたくさん作ることができますが、メイン画面を表すSurface(Display Surface)はただ1つだけでset_mode()で作ります。set_mode()の戻り値はSurface オブジェクトです。screenという変数に格納しておきます。pygame.display.set_caption()関数を使うとメインウィンドウのタイトルバーにキャプションを設定できます。

ゲームループ

# ゲームループ
while True:
    screen.fill((0,0,255))   # 画面を青色で塗りつぶす
    pygame.display.update()  # 画面を更新
    # イベント処理
    for event in pygame.event.get():
        if event.type == QUIT:  # 終了イベント
            sys.exit()

このスクリプトの中でもっとも重要なのがゲームループです。これがないとスクリプトが一瞬で終了してしまいます。ゲームループは無限ループです。つまり、ずっとぐるぐる回ってwhile文の中身を処理し続けます。一般的にゲームプログラムはイベントドリブンという方式を取ります。これは、ゲームループをずーーーとまわしておいて、ユーザからの要求(イベント)が来るたびに処理する方法です。イベントとはマウスクリックしたメニューを選択したキー入力したなどユーザの要求の他に画面を描画しろなどOSの要求もあります。ゲームループは下のような構造が一般的です。

    while True:
        ゲームオブジェクトの更新
        ゲームオブジェクトのレンダリング(描画)
        画面の更新
        イベント処理

イベント処理は一番はじめにくる場合もありますが、どっちでもいいです。ただ、ゲームオブジェクトの更新→レンダリング→画面の更新はたいていこの順番です。ゲームオブジェクトの更新とは、RPGでキャラクターの位置を移動するなどを指します。レンダリングではバックバッファ(オフスクリーンともいう)と呼ばれるメモリ上のSurfaceにゲームオブジェクトを配置します。この時点ではまだ画面に表示されません。最後に画面を更新することでバックバッファが画面に表示されます。このように間にバックバッファをはさむことでちらつきを防止する方法はダブルバッファリングと呼ばれます。C++やJavaは自分でバックバッファを用意する必要がありますが、Pygameは自動的にやってくれます。アニメーションで詳しく説明します。

pygame.Surface.fill()は、Surfaceを単色で塗りつぶす関数です。screenは Surfaceオブジェクトでしたね。引数には (Red, Green, Blue) をタプルで指定します。それぞれ0〜255の値を取り、RGBを組み合わせることでいろんな色が作れます。たとえば、(0,0,255) は青です。ためしに画面を別の色で塗りつぶしてみてください。

pygame.display.update()は、先ほど説明した画面を更新する関数です。

最後のイベント処理では、終了イベント(QUIT)がきたときにsys.exit()でスクリプトを終了しています。sys.exit()は Pygameの関数ではなく、Pythonの関数です。QUITはウィンドウの×ボタンを押したときなどに発生します。これがあるおかげで無限ループから抜け出してスクリプトを終了できます。もしないと強制終了しないと止まりません。

このウィンドウを表示するスクリプトは、土台として何回も使います。コピペして再利用すると楽です。