튜토리얼 3 — 플랫폼 게임: 레벨, 충돌, 카메라
한 줄씩 적는 레벨
처음에는 레벨을 코드에 직접 적어요. 16 × 16 픽셀 타일 하나가 문자 하나예요.
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,
) {
}
매 프레임 속도를 정한 다음 충돌 시스템으로 이동시켜요. 충돌 시스템은 한 픽셀씩 나아가며 벽에서 멈추고, 바닥에 착지하고, 경사로를 오르고, $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를 실행하면 바로 수정할 수 있는 상태로 받을 수 있어요.