人工知能に関する断創録

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

カーソルの移動

マップを作る(2008/5/24)やマップのロード(2008/6/1)のようにマップのデータを数値で打ち込んでいくのは大変です。マップエディタ編では、お絵描きするような感じで簡単にマップを作成できるマップエディタを作っていきます。

今回はマップ内をカーソル(緑色の四角形)が移動するところまで作ってみます。Pygameではスクロールバーが使えないためカーソルでマップ内を移動します。RPG編のピクセルベーススクロール(2008/6/14)まで読んできた方なら前に似たコード見たなぁと思えるはずです。MapクラスはRPG編のMapとほとんど同じですし、CursorクラスはRPG編のPlayerにほぼ対応しています。

スクリプトを起動すると、矢印キーでカーソルが動かせます。

pymap01.zip
f:id:aidiary:20100807173120p:plain

メイン関数

SCR_RECT = Rect(0, 0, 800, 640)
GS = 32

def main():
    pygame.init()
    screen = pygame.display.set_mode(SCR_RECT.size)
    pygame.display.set_caption(u"PyMap 01 カーソルの移動")
    
    # イメージをロード
    Map.images.append(load_image("none.png"))   # 範囲外
    Map.images.append(load_image("water.png"))  # 海
    
    map = Map("new.map", 64, 64)  # 64x64(単位:マス)のマップ
    cursor = Cursor(0, 0)
    
    clock = pygame.time.Clock()
    while True:
        clock.tick(60)
        offset = calc_offset(cursor)
        cursor.update()
        map.draw(screen, offset)
        cursor.draw(screen, offset)
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()

メイン関数では、MapオブジェクトとCursorオブジェクトを作成しています。デフォルトのマップの大きさは64x64マスです。また、カーソルは (0,0) に置いておきます。Mapのイメージには

f:id:aidiary:20100807173318p:plain f:id:aidiary:20100807173319p:plain

という2つのイメージを登録しています。いずれたくさんのマップチップを使えるようにしますが、今回はこれだけです。

マップクラス

class Map:
    images = []
    def __init__(self, name, row, col):
        self.name = name
        self.row = row
        self.col = col
        self.default = 1  # デフォルトのマップチップ番号
        # デフォルトマップチップで初期化
        self.map = [[self.default for c in range(self.col)]
                                  for r in range(self.row)]
    def __str__(self):
        return "%s,%d,%d,%d" % (self.name, self.row, self.col, self.default)
    def draw(self, screen, offset):
        offsetx, offsety = offset
        # マップの描画範囲を計算
        startx = offsetx / GS
        endx = startx + SCR_RECT.width/GS + 2
        starty = offsety / GS
        endy = starty + SCR_RECT.height/GS + 2
        # マップの描画
        for y in range(starty, endy):
            for x in range(startx, endx):
                # マップの範囲外はマップチップ番号0で描画
                if x < 0 or y < 0 or x > self.col-1 or y > self.row-1:
                    screen.blit(self.images[0],
                                (x*GS-offsetx,y*GS-offsety))
                else:
                    screen.blit(self.images[self.map[y][x]],
                                (x*GS-offsetx,y*GS-offsety))

Mapクラスはオフセットを使っていることも含めてタイルベーススクロール(2008/6/7)のMapクラスとよく似ています。デフォルトのマップチップ番号を1にしていますが、これは

f:id:aidiary:20100807173319p:plain

です。起動するとマップは海で塗りつぶされてますね。またマップの範囲外は

f:id:aidiary:20100807173318p:plain

で塗りつぶしています。self.mapがマップチップ番号が入る二次元リストです。

 self.map = [[self.default for c in range(self.col)]
                           for r in range(self.row)]

このコードは少し見慣れないかもしれませんが、Pythonで2次元リストを作るときの定石です。row行col列で0で初期化した2次元リストを作りたい場合は、

 lst = [[0 for c in range(col)] for r in range(row)]

と書きます。(2,3)にアクセスしたい場合はlst[2][3]のように配列風の書き方が使えます。

カーソルクラス

class Cursor:
    COLOR = (0,255,0)  # 緑色
    WIDTH = 3  # 太さ
    def __init__(self, x, y):
        self.x, self.y = x, y
        self.rect = Rect(x*GS, y*GS, GS, GS)
    def update(self):
        # キー入力でカーソルを移動
        pressed_keys = pygame.key.get_pressed()
        if pressed_keys[K_DOWN]:
            self.y += 1
        elif pressed_keys[K_LEFT]:
            self.x -= 1
        elif pressed_keys[K_RIGHT]:
            self.x += 1
        elif pressed_keys[K_UP]:
            self.y -= 1
        self.rect = Rect(self.x*GS, self.y*GS, GS, GS)
    def draw(self, screen, offset):
        # オフセットを考慮してカーソルを描画
        offsetx, offsety = offset
        px = self.rect.topleft[0]
        py = self.rect.topleft[1]
        pygame.draw.rect(screen, self.COLOR,
                         (px-offsetx,py-offsety,GS,GS),
                         self.WIDTH)

最後にマップ内を移動するカーソルですが、これはRPG編のPlayerとほとんど同じです。違うところは画像で描画するのではなく、矩形で描画するところくらいです。draw()で緑色で幅が3の矩形を描いています。またupdate()でキー入力を検知して移動する処理を書いています。これでマップ内を自由に移動できるようになりました。次はマウスを使ってマップチップをお絵描きできるようにしてみます。