ZH

教程 1 — Hello world:一个菜单、一段文字、一个音效

最小的 JumPHP 游戏:一个带菜单的标题画面(开始、声音、退出),然后是一段可以用方向键移动的文字,按空格键会发出一个音效。只有两个文件。你可以马上在沙盒中修改它,也可以在自己电脑上用 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(方向键、回车、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]]));
        }
    }

    /** 各行:[标签, 右侧显示的值, 按回车时的动作, 按左 / 右时的动作] */
    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

一个场景有三个核心方法:

  • enter($params):场景开始。请在这里把一切重置:同一个场景会被多次使用;
  • update($dt):每秒 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。

下一篇:会移动、会动画的角色。