JA

チュートリアル3 — プラットフォームゲーム:レベル、衝突判定、カメラ

文字の行で書くレベル

まずは、コードの中に直接レベルを書きます。16 × 16ピクセルのタイル1枚が、1文字に対応します。

private const LEVEL = [
    '..........................C.C.C.........',
    '.........................=======........',
    '...P....................................',
    '#########............C......######......',
    '#########..........#####...########.....',
    '########################################',
];

$this->map = ArrayLoader::fromRows(self::LEVEL,
    legend: ['#' => 1, '=' => 2, '/' => 3, '\\' => 4],     // タイル
    objects: ['P' => 'start', 'C' => 'coin'],                // レベルに置くオブジェクト
    tileWidth: 16, tileset: 'generated:tiles');
$tileset = $this->map->tilesets[0];
$tileset->masks[1] = CollisionMask::oneWay();                // '=' :下からはすり抜けてジャンプできる
$tileset->masks[2] = CollisionMask::slope(16, 16, 1, 16);    // '/' :坂道

ゲームが大きくなったら、Tiledでレベルを作りましょう: TiledJsonLoader::load($this->engine->config->path('assets/maps/niveau1.tmj'))。

衝突判定

シーンのコンストラクタにサービスを注入します(自動的に提供されます)。

public function __construct(
    private TileMapRenderer $tiles,
    private CollisionSystem $collisions,
    private EntityManager $entities,
) {
}

毎フレーム、速度を設定してから、衝突判定システムで移動させます。システムは1ピクセルずつ進み、壁で止まり、地面に着地し、坂を上り、$player->onGroundを設定します。

$this->player->control($move, $jump, $held, $dt);
$this->player->update($dt);
$this->collisions->move($this->player, $this->map, $dt);

レベルの外に落ちたとき:$this->collisions->on('fell', fn () => $this->respawn());(enter()の中で、 $this->collisions->removeAllListeners()の後に書きます)。

コイン

レベルのオブジェクトは、エンティティになります。

$this->entities->clear();
$this->entities->register('coin', Coin::class);
$this->entities->spawnFromMap($this->map);

// update()の中で:
$this->entities->update($dt, $this->camera);
foreach ($this->entities->overlapping($this->player->getBoundingBox()) as $entity) {
    if ($entity instanceof Coin) {
        $entity->kill();                    // 自動的に取り除かれます
        $this->coins++;
        $this->sound()->playSfx('coin');
    }
}

カメラ

$this->camera = new Camera($this->width(), $this->height());
$this->camera->setBounds(0, 0, $this->map->pixelWidth(), $this->map->pixelHeight());
$this->camera->follow($this->player, 0.15, 0.3);    // 画面の中央に「遊び」の範囲を設ける

// update():$this->camera->update($dt);
// render():すべてをカメラの位置の分だけずらして描画する
$cx = $this->camera->getX();
$cy = $this->camera->getY();
$this->tiles->renderBackground($r, $this->map, $cx, $cy, $this->time);
$this->entities->render($r, $this->camera);
$this->player->render($r, $cx, $cy);
$this->tiles->renderForeground($r, $this->map, $cx, $cy, $this->time);

$this->camera->shake(4, 0.3)で、画面が揺れます。完成版のゲームは、JumPHPのスケルトン(src/Scene/PlayScene.php)です。bin/jumphp new mon-jeuで、そのまま改造できる形で手に入ります。