튜토리얼 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를 이미 정의해 두었어요(방향키, 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
장면에는 핵심 메서드가 세 개 있어요.
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.
다음: 움직이고 애니메이션하는 캐릭터.