コンテンツにスキップ

3 迷路ゲーム

迷路ゲームを作成します(maze.py)。 迷路内の鍵を取得しドアを開けてゴールを目指します。鍵は2つあり、2つとも取得しなければなりません。

3.1 マップ

64×64の画像を用意し、この画像をタイルとして縦12枚、横12枚に並べます。 ですので、幅と高さは64×12になります。これらを定数にします、

import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "100,100"
import pgzrun
from pgzero.builtins import *

TILE_SIZE = 64
ROW_COUNT = 12 #行数
COL_COUNT = 12
WIDTH = TILE_SIZE * ROW_COUNT
HEIGHT = TILE_SIZE * COL_COUNT

画像は empty、wall、key, door,goal の5種類です。それをどう配置するかを2次元リストで表します。

tiles = ['empty', 'wall', 'goal', 'key', 'door']

maze = [
    [1,1,1,1,1,1,1,1,1,1,1,1],
    [1,0,0,0,0,0,1,1,0,0,3,1],
    [1,0,1,0,1,0,1,1,0,1,0,1],
    [1,0,1,0,0,0,0,0,0,0,0,1],
    [1,0,1,0,1,1,1,1,1,0,1,1],  
    [1,0,0,0,0,0,0,0,0,0,1,1],
    [1,0,1,0,1,1,0,1,0,1,1,1],
    [1,0,1,0,0,0,3,1,0,0,4,1],
    [1,0,1,0,1,0,1,1,1,1,0,1],
    [1,0,0,0,0,0,1,1,1,1,0,1],
    [1,1,1,1,1,1,1,1,1,1,2,1],
    [1,1,1,1,1,1,1,1,1,1,1,1]
]

これを描画する関数draw_mazeを作成します。for文で0~12の繰り返しを行と列で行います。そのxとy座標を計算し、そこのタイルの画像を表示します。 screen.blit(画像, 座標)で表示できます。

def draw_maze():
    for row in range(ROW_COUNT):
        for col in range(COL_COUNT):
            x = col * TILE_SIZE
            y = row * TILE_SIZE
            tile_type = maze[row][col]
            screen.blit(tiles[tile_type], (x, y))

これをdraw関数で呼び出します。

def draw():
    screen.clear()
    draw_maze()

pgzrun.go()

3.2 プレイヤーの表示と移動

プレイヤーを用意します。初期位置は(1,1)です。ここに配置するため、anchorで基準点を左上にしています。

player = Actor("player", anchor=(0, 0), pos=(1 * TILE_SIZE, 1 * TILE_SIZE))

これをdrawで描画します。

player.draw()

キーボードで移動できるようにします。 まず、元の座標と押したキーから新たな座標を計算するnew_position関数を作成します。

def new_position(row, col, key):
    new_row, new_col = row, col
    # 移動    
    if key == keys.UP:
        new_row = row - 1
    elif key == keys.DOWN:
        new_row = row + 1
    elif key == keys.LEFT:
        new_col =  col - 1
    elif key == keys.RIGHT:
        new_col = col + 1
    return new_row, new_col

これをon_key_downで呼び出します。現在位置はplayerのx、y座標をタイル幅で割って取得します。

def on_key_down(key):
    # 現在位置取得
    row = int(player.y / TILE_SIZE)
    col = int(player.x / TILE_SIZE)

    new_row, new_col = new_position(row, col, key)

移動先のタイルがempty(空)の場合、そこに移動します。

    new_tile = maze[new_row][new_col] # 移動先タイル
    if new_tile == 0: # empty
        x = new_col * TILE_SIZE
        y = new_row * TILE_SIZE
        player.x = x
        player.y = y

3.3 鍵とドア

鍵をいくつ持っているかの属性key_countをプレイヤーに設定します。

player.key_count = 0

鍵のマスに来たときに鍵の数を1増やします。 on_key_downのif文に追加します。鍵のマスは空きマスに変えます。

elif new_tile == 2: # key
    player.key_count += 1
    maze[new_row][new_col] = 0

ドアのところまで来たときに鍵を2つ持っていたらドアを空きマスに変えます。

elif new_tile == 3 and player.key_count == 2: # door
    maze[new_row][new_col] = 0

これで鍵を2つ保持していたら、ドアを開けることが出来ます。

3.4 ゴール処理

ゲームの状態を表すstatusをプレイヤーに設定します。これはplayとgoalのどちらかです。

player.status = 'play'

ゴールのマスに来たときに状態をgoalに変更します。 on_key_downのif文に追加します。

elif new_tile == 4: # goal
    player.status = 'goal'

ゴールしたら動けないようにします。

def on_key_down(key):
    if player.status != 'play':
        return

draw関数にゴールの表示を加えます。

    if player.status == 'goal':
        screen.draw.text("GOAL!!", midtop=(WIDTH//2, HEIGHT//2), fontsize=60, color='white')

3.5 アニメーション

現在、キャラクターが移動するときには、plyaerのxとyを更新しています。

    if new_tile == 0: # empty
        x = new_col * TILE_SIZE
        y = new_row * TILE_SIZE
         # この部分
        player.x = x
        player.y = y

これをanimate関数でアニメーション処理に変更します。アニメーション処理とはActor の属性(位置・透明度・角度など)を一定時間かけて変化させるためのものです。 animate(アクター, pos=位置, tween=変化方法, duration=時間)で指定します。

         animate(player, pos=(x, y), tween='decelerate', duration=0.1)

tweenは以下を指定できます

  • accelerate : だんだん速く動く
  • decelerate : だんだん遅くなる
  • bounce : バウンドするような動き
  • linear : 一定速度(デフォルト)