チュートリアル1 — Hello world:メニュー、テキスト、サウンド
メニュー(プレイ、サウンド、終了)のあるタイトル画面と、矢印キーで動くテキスト、スペースキーで鳴るサウンドだけの、いちばん小さなJumPHPゲームです。ファイルは2つ。サンドボックスですぐに書き換えられますし、手元でbin/jumphp new hello-worldを実行して作ることもできます。
設定:config/game.yaml
game:
id: hello-world
title: "HELLO WORLD"
width: 320 # ゲームの解像度。画面のサイズに拡大されます
height: 180
start_scene: App\Scene\TitleScene
touch: { a: Space, b: Escape, start: Return } # スマートフォンでのパッドのボタン
smoke: # `bin/jumphp test`が画面なしで自動的にプレイする内容
scene: App\Scene\HelloScene
params: { demo: true }
キーについて:エンジンはすでにup down left right confirm back pauseを定義しています(矢印キー、Enter、Esc、ゲームパッド、タッチ操作)。アクションを追加するには、config/input.yamlに書きます。
actions:
jump: [Space, pad0:a, touch:tap]
タイトル画面:src/Scene/TitleScene.php
メニューはMenuSceneを継承して書きます。タイトルと各行を渡すだけで、あとはエンジンが引き受けます(描画、キーボード・ゲームパッド・指での移動、メニューのサウンド)。
final class TitleScene extends MenuScene
{
protected string $title = 'HELLO WORLD';
public function enter(array $params = []): void
{
parent::enter($params);
// PHPで作ったサウンド:音声ファイルは不要です
if (!$this->sound()->hasSfx('menu_move')) {
$this->sound()->synth('menu_move', Synth::tone(660, 0.04));
$this->sound()->synth('menu_confirm', Synth::sequence([[660, 0.05], [990, 0.08]]));
}
}
/** 各行:[ラベル, 右側に表示する値, Enterで実行する処理, 左右キーで実行する処理] */
protected function items(): array
{
$items = [
['PLAY', null, fn () => $this->scenes()->switchTo(HelloScene::class)],
['SOUND', fn () => $this->sound()->isMuted() ? 'OFF' : 'ON', fn () => $this->toggleSound(), fn () => $this->toggleSound()],
];
if (Platform::isDesktop()) {
$items[] = ['QUIT', null, fn () => $this->engine->quit()]; // ブラウザには「終了」はありません
}
return $items;
}
private function toggleSound(): void
{
$this->sound()->setMuted(!$this->sound()->isMuted());
$this->refresh(); // メニューが新しい値を表示し直します
}
}
menu_moveとmenu_confirmというサウンドは、メニューが自動的に鳴らします。ラベルはconfig/lang.yamlで翻訳されます(fr: { PLAY: JOUER })。
ゲーム本編:src/Scene/HelloScene.php
シーンには、大事なメソッドが3つあります。
enter($params):シーンの開始時に呼ばれます。ここですべてを初期状態に戻してください。同じシーンが何度も使われるからです。update($dt):1秒に60回呼ばれ、ゲームの状態を更新します。$dtは経過時間(秒)です。render($r):描画だけを行います。それ以外のことはしません。
final class HelloScene extends AbstractScene
{
private float $x = 0.0;
private float $y = 0.0;
public function enter(array $params = []): void
{
$this->x = $this->width() / 2;
$this->y = $this->height() / 2;
if (!$this->sound()->hasSfx('beep')) {
$this->sound()->synth('beep', Synth::sweep(440, 880, 0.12)); // 音が上がっていく「ピッ」
}
}
public function update(float $dt): void
{
if ($this->actions()->isPressed('back')) { // Esc:タイトルに戻る
$this->scenes()->switchTo(TitleScene::class);
return;
}
// axis()は-1、0、1のいずれか:毎秒90ピクセル
$this->x += $this->actions()->axis('left', 'right') * 90 * $dt;
$this->y += $this->actions()->axis('up', 'down') * 90 * $dt;
if ($this->actions()->isPressed('jump') || $this->actions()->isPressed('confirm')) {
$this->sound()->playSfx('beep');
}
}
public function render(Renderer $r): void
{
$r->clear([16, 16, 40]);
// 内蔵フォント(5 × 7ピクセル)を2倍に拡大し、中央揃え、黒い影つきで描画
$this->font()->draw($r, 'HELLO WORLD!', $this->x, $this->y, 2, [255, 220, 80], 'center', [0, 0, 0]);
}
}
実際のファイルには、サウンドのたびに飛び散る星、色が変わるテキスト、テスト用のデモモードも入っています。ゲームのソースで読めます。
試してみよう
- サンドボックスで:テキスト、色
[255, 220, 80]、速度、サウンド(Synth::tone(220, 0.3, 'triangle'))を変えて、▶ テストを押してください。 - 手元で:
bin/jumphp run hello-world、bin/jumphp test hello-world。