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

人工知能に関する断創録

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



マップを作る

Pygame

前回、背景は青く塗りつぶしていただけだったので、今回は簡単なマップを作って表示してみます。ここで書いたスクリプトは拡張性をまったく考慮していません。本当はマップ専用のクラスを作って処理をきちんと分離し、マップもファイルから読み込むところですがそれはもっと後の回で取り上げます。

pyrpg02.zip
f:id:aidiary:20100605233456p:plain

サンプルスクリプト

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import sys
import os
 
SCR_RECT = Rect(0, 0, 640, 480)
ROW,COL = 15,20  # マップサイズ(15マスx20マス)
GS = 32  # マスのサイズ(ピクセル)
# マップデータ(0:草地、1:海)
map = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
 
def load_image(filename, colorkey=None):
    filename = os.path.join("data", filename)
    try:
        image = pygame.image.load(filename)
    except pygame.error, message:
        print "Cannot load image:", filename
        raise SystemExit, message
    image = image.convert()
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0,0))
        image.set_colorkey(colorkey, RLEACCEL)
    return image
 
def draw_map(screen):
    """マップを描画する"""
    for r in range(ROW):
        for c in range(COL):
            if map[r][c] == 0:
                screen.blit(grassImg, (c*GS,r*GS))
            elif map[r][c] == 1:
                screen.blit(waterImg, (c*GS,r*GS))
 
pygame.init()
screen = pygame.display.set_mode(SCR_RECT.size)
pygame.display.set_caption(u"PyRPG 02 マップを作る")
 
# イメージロード
playerImg = load_image("player1.png", -1)  # プレイヤー
grassImg = load_image("grass.png")         # 草地
waterImg = load_image("water.png")         # 水
 
while True:
    draw_map(screen)  # マップ描画
    screen.blit(playerImg, (0,0))  # プレイヤー描画
    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()

マップの構造

今回作るマップは草地には

f:id:aidiary:20100605233457p:plain

海には

を使います。スクリプト中でマップを定義しているのはmapという15x20の二次元リストです。二次元リストの1つ1つの要素がマップの 1マスにあたります。15は行数で20は列数です。

ROW,COL = 15,20  # マップサイズ(15マスx20マス)
GS = 32  # マスのサイズ(ピクセル)
# マップデータ(0:草地、1:海)
map = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]

目をこらしてよーく見ると何となくマップに見えますよね。今回は草地と海だけなので0と1しか使いませんが、森とか山とか使いたければ2とか3とか使っても大丈夫です。ただ、上のようにリスト形式で0とか1を打ち込んで書くのはむちゃくちゃ面倒です。後でお絵描きするようにマップが作れるマップエディタも作ります。

マップの描画

上のようなリストで定義されたマップを画面に描画してみます。その前に草地と海のマップチップをロードします。

grassImg = load_image("grass.png")         # 草地
waterImg = load_image("water.png")         # 水

マップチップは-1を指定して透明色をセットしていないことに注意してください。マップの描画はdraw_map()関数で行っています。

def draw_map(screen):
    """マップを描画する"""
    for r in range(ROW):
        for c in range(COL):
            if map[r][c] == 0:
                screen.blit(grassImg, (c*GS,r*GS))
            elif map[r][c] == 1:
                screen.blit(waterImg, (c*GS,r*GS))

ROWは行数、COLは列数、GSはGrid Sizeの略称でマップチップ(マス)のサイズです。20x15 のマップと書いた場合は、前が行数で後が列数とします。マップリストはmap[行][列]でアクセスします。マップ内の値(0か1)に応じてマップチップを画面に描いています。ここで注意しなければならないのはマップの行・列と画面座標の対応関係です。r行c列のマスの座標は (c*GS, r*GS) となります(下図参照)。

f:id:aidiary:20100605233459p:plain