人工知能に関する断創録

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

バイナリマップのロード

マップエディタ編のマップの保存で作成したバイナリマップを読み込めるようにします。またキャラクターチップとマップチップを大幅強化してキャラクターチップとマップチップ(2008/6/24)がすべて使えるように拡張します。

pyrpg17.zip
f:id:aidiary:20100807171848p:plain

キャラクターチップのロード

まずキャラクターチップとマップチップをロードする処理を見てみます。今までmain()で下のように1つずつロードしていました。このやり方で全員分をロードするのははげしく大変です。

    # キャラクターイメージをロード
    Character.images["player"] = \
        split_image(load_image("player.png"))
    Character.images["king"] = \
        split_image(load_image("king.png"))
    Character.images["minister"] = \
        split_image(load_image("minister.png"))
    Character.images["soldier"] = \
        split_image(load_image("soldier.png"))
    Character.images["black_cat"] = \
        split_image(load_image("black_cat.png"))
    # マップチップをロード
    Map.images[0] = load_image("grass.png") # 草地
    Map.images[1] = load_image("water.png")  # 水
    Map.images[2] = load_image("forest.png") # 森
    Map.images[3] = load_image("hill.png")   # 丘
    Map.images[4] = load_image("mountain.png")  # 山

そんなわけでキャラクターやマップの情報はファイルに保存しておき、ファイルから一括ロードするように修正します。その結果、main()は下のようにすっきりできます。

    # キャラクターチップをロード
    load_charachips("data", "charachip.dat")
    # マップチップをロード
    load_mapchips("data", "mapchip.dat")

charachip.datとmapchip.datがそれぞれキャラクターチップとマップチップの情報を入れたファイルです。charachip.datは下のように使用できるキャラクターIDとキャラクター名を格納したファイルです。これはキャラクターチップとマップチップ(2008/6/24)の番号や名前と一致します。

 0,swordman_male
 1,swordman_female
 2,mercenary_male
 3,mercenary_female
 4,elf_male1
 5,elf_female1
 6,knight_male
 7,knight_female
 8,fighter_male
 9,fighter_female
 10,magician_male

load_charachips()は上のファイルを読み込んですべてのキャラクターチップ画像を読み込んでCharacter.imagesに格納する関数です。

def load_charachips(dir, file):
    """キャラクターチップをロードしてCharacter.imagesに格納"""
    file = os.path.join(dir, file)
    fp = open(file, "r")
    for line in fp:
        line = line.rstrip()
        data = line.split(",")
        chara_id = int(data[0])
        chara_name = data[1]
        Character.images[chara_name] =
          split_image(load_image("charachip", "%s.png" % chara_name))
    fp.close()

ファイルを一行ずつ読み込んで画像をセットしています。forループでまわすことで全員分のload_image()を書く必要がなくなったので多くのキャラクターを読み込むのが簡単になっています。またキャラクターを追加したければcharachip.datに追加するだけなので拡張も容易です。

マップチップのロード

マップチップもキャラクターチップとほとんど同じですが、移動可能かや背景色を透明にするか?など追加オプションがあります。mapchip.datは下のようなファイルです。

 0,none,0,0
 1,darkness,1,0
 2,sky,1,0
 3,grass,1,0
 4,flat,1,0
 5,water,0,0
 6,forest,1,0
 7,hill,1,0
 8,mountain,0,0
 9,snow,1,0
 10,desert,1,0

実はこれはマップエディタ編のマップチップパレットで使ったファイルとまったく同じものです。左からマップチップID、マップチップ名、移動可能か、背景色を透明にするかを表しています。 load_mapchips()は上のファイルを読み込んですべてのマップチップ画像や移動可能かを読み込んでMap.imagesや Map.movable_typeに格納する関数です。

TRANS_COLOR = (190,179,145)  # マップチップの透明色

def load_mapchips(dir, file):
    """マップチップをロードしてMap.imagesに格納"""
    file = os.path.join(dir, file)
    fp = open(file, "r")
    for line in fp:
        line = line.rstrip()
        data = line.split(",")
        mapchip_id = int(data[0])
        mapchip_name = data[1]
        movable = int(data[2])  # 移動可能か?
        transparent = int(data[3])  # 背景を透明にするか?
        if transparent == 0:
            Map.images.append(load_image(
              "mapchip", "%s.png" % mapchip_name))
        else:
            Map.images.append(load_image(
              "mapchip", "%s.png" % mapchip_name, TRANS_COLOR))
        Map.movable_type.append(movable)
    fp.close()

背景色を透明にするかによってload_image()の引数を変えています。load_image()に透明色を指定するとそれが透明になります。詳しくはイメージを描画する(2008/5/5)を参照してください。キャラクターチップとマップチップ(2008/6/24)にも書いたのですが透明色は (190, 179, 145) で茶色っぽい色です。これはオリジナル画像のDotWorldさんが使っていた色をそのまま使ったためです。Map.movable_typeは今回初めて追加しました。これは、マップチップが移動可能かを格納するリストです。これによってis_movable()を下のように修正しました。

    def is_movable(self, x, y):
        """(x,y)は移動可能か?"""
        # マップ範囲内か?
        if x < 0 or x > self.col-1 or y < 0 or y > self.row-1:
            return False
        # マップチップは移動可能か?
        if self.movable_type[self.map[y][x]] == 0:
            return False
        # キャラクターと衝突しないか?
        for chara in self.charas:
            if chara.x == x and chara.y == y:
                return False
        return True

マップチップが移動可能か?をファイルから読み込んだmovable_typeで判断しています。

バイナリマップファイルのロード

最後にバイナリマップファイルをロードする処理です。Map.load()です。読み込み方はマップエディタ編のマップの読み込みとほとんど同じです。

    def load(self):
        """バイナリファイルからマップをロード"""
        file = os.path.join("data", self.name + ".map")
        fp = open(file, "rb")
        # unpack()はタプルが返されるので[0]だけ抽出
        self.row = struct.unpack("i",
            fp.read(struct.calcsize("i")))[0]  # 行数
        self.col = struct.unpack("i",
            fp.read(struct.calcsize("i")))[0]  # 列数
        self.default = struct.unpack("B",
            fp.read(struct.calcsize("B")))[0]  # デフォルトマップチップ
        # マップ
        self.map = [[0 for c in range(self.col)]
                       for r in range(self.row)]
        for r in range(self.row):
            for c in range(self.col):
                self.map[r][c] = struct.unpack("B",
                    fp.read(struct.calcsize("B")))[0]
        fp.close()

プレイヤー変更

気づいた方もいると思いますが、プレイヤーキャラクターを変えてみました。main()の

      player = Player("elf_female2", (1,1), DOWN)

のelf_female2のところをキャラクターチップのお好きなキャラクター名に変えてみてください。絵が変わります。