はじめに
「いつかゲームを作ってみたい」と思いながら、UnityやUnreal Engineの学習コストの高さに尻込みした経験はありませんか。エディタの使い方を覚え、C#やC++を学び、ビルド設定と格闘して……気づけば肝心のゲームを1行も作らないまま挫折してしまう。そんな話は珍しくありません。
普段JavaScriptを書いているWebエンジニアなら、もっと近道があります。KAPLAYを使えば、ブラウザとテキストエディタだけで、本当に数十行のコードから動くゲームが作れるのです。実際に触ってみたところ、「遊ぶように作れる」という表現がぴったりの体験だったので、この記事でその魅力を紹介します。
とはいえ、説明を読むよりも実際に動かした方が早いと思います。矢印キーでキャラクターを動かしてコインを集めるミニゲームを、この記事内でそのまま触れるようにしてあります。先に挙動を確認したい方はこちらからどうぞ。
KAPLAYとは
KAPLAY(カプレイ)は、JavaScript/TypeScript向けのオープンソース2Dゲームライブラリです。かつてReplit社が開発していた人気ライブラリ「Kaboom.js」のメンテナンス終了を受けて、コミュニティが開発を引き継いだ後継プロジェクトで、現在も活発に更新が続いています。
「fun-first(楽しさ第一)」を掲げており、ゲームを作る過程そのものがゲームのように楽しいことを重視した設計になっています。
主な特徴
- 直感的なコンポーネントベースAPI -
add([sprite("bean"), pos(80, 40), body()])のように、機能を配列で組み合わせるだけでゲームオブジェクトが完成します - 物理エンジン・衝突判定を標準搭載 - 重力、ジャンプ、当たり判定といったゲームの基本要素が組み込み済みで、外部ライブラリは不要です
- TypeScript完全対応 - 型定義が同梱されており、エディタの補完を受けながら快適に開発できます
- KAPLAYGROUNDで即体験 - ブラウザ上のプレイグラウンドに90以上のサンプルが用意されており、インストールせずに試せます
インストール
一番手軽なのは、公式のスキャフォールディングツールを使う方法です。
npx create-kaplay my-game
cd my-game
npm run dev
既存プロジェクトに追加する場合は、各パッケージマネージャーでインストールできます。
# npm
npm install kaplay
# yarn
yarn add kaplay
# pnpm
pnpm add kaplay
ビルドツールを使わずに試したい場合は、CDNから直接読み込むこともできます。
<script src="https://unpkg.com/kaplay@3001/dist/kaplay.js"></script>
KAPLAYのサンプルを動かす
KAPLAYの雰囲気をつかむには、説明を読むより先にキャンバス上でキャラクターを動かしてみるのが一番です。以下のサンプルは、矢印キー(↑↓←→)でプレイヤー(赤い四角)を動かし、ランダムに配置した黄色いコインに触れるとonCollide()が発火してスコアが加算される、というシンプルなミニゲームです。使っているAPIは、ゲームオブジェクトを生成するadd()、当たり判定を付けるarea()、色を指定するcolor()、キー入力を毎フレーム検知するonKeyDown()、そして衝突を検知するonCollide()です。
要点だけを抜き出すと、次のようになります。
const player = add([
rect(32, 32),
pos(80, 80),
area(),
color(255, 90, 90),
"player",
]);
const SPEED = 240;
onKeyDown("left", () => player.move(-SPEED, 0));
onKeyDown("right", () => player.move(SPEED, 0));
// "coin"タグを持つオブジェクトと衝突したら発火
player.onCollide("coin", (coin) => {
destroy(coin);
score += 1;
});
実際に動かせるサンプルが以下です。矢印キーでプレイヤーを動かして、5つのコインをすべて集めてみてください。
このように、KAPLAYではonKeyDown()とonCollide()を組み合わせるだけで「動かす」「当たったら反応する」という2Dゲームの基本ループが数十行で完成します。上のコードのSPEEDの値を大きくすると移動速度が上がり、forループの回数を増やすとコインの個数が増えてより長く遊べるミニゲームになります。
基本的な使い方
まずは「スペースキーでジャンプするキャラクター」を作ってみましょう。これだけのコードで、重力・地面・ジャンプが揃ったゲームの土台が動きます。
import kaplay from "kaplay";
// ゲームの初期化(キャンバスが自動生成されます)
kaplay({
background: "#87ceeb",
});
// 公式マスコット「bean」のスプライトを読み込み
loadSprite("bean", "https://play.kaplayjs.com/bean.png");
// 重力を設定
setGravity(1600);
// プレイヤーを追加
const player = add([
sprite("bean"), // 見た目
pos(120, 80), // 初期位置
area(), // 当たり判定
body(), // 物理挙動(重力の影響を受ける)
]);
// 地面を追加
add([
rect(width(), 48), // 画面幅いっぱいの矩形
pos(0, height() - 48),
area(),
body({ isStatic: true }), // 動かない物体
color(127, 200, 255),
]);
// スペースキーでジャンプ
onKeyPress("space", () => {
if (player.isGrounded()) {
player.jump();
}
});
注目してほしいのは add() に渡している配列です。KAPLAYでは、sprite() や body() といったコンポーネントを組み合わせてゲームオブジェクトを定義します。「見た目が欲しければ sprite()、物理挙動が欲しければ body() を足す」というシンプルなルールなので、覚えることが非常に少なく済みます。
実践的なユースケース
次は一歩進めて、障害物を避け続けるミニゲームを作ってみます。スコア表示、ゲームオーバー、リトライまで含めた「遊べる」構成です。
import kaplay from "kaplay";
kaplay({ background: "#1f102a" });
loadSprite("bean", "https://play.kaplayjs.com/bean.png");
setGravity(2400);
// ゲーム本編のシーン
scene("game", () => {
let score = 0;
const player = add([
sprite("bean"),
pos(80, 40),
area(),
body(),
]);
// 地面
add([
rect(width(), 48),
pos(0, height() - 48),
area(),
body({ isStatic: true }),
color(72, 61, 139),
]);
onKeyPress("space", () => {
if (player.isGrounded()) {
player.jump(900);
}
});
// 一定間隔で障害物を生成
loop(1.2, () => {
add([
rect(48, rand(24, 72)),
pos(width(), height() - 48),
anchor("botleft"),
area(),
move(LEFT, 320), // 左方向へ移動
offscreen({ destroy: true }), // 画面外に出たら削除
color(238, 143, 203),
"obstacle", // タグを付けておく
]);
});
// 障害物に当たったらゲームオーバー
player.onCollide("obstacle", () => {
go("gameover", score);
});
// スコア表示
const scoreLabel = add([text("0"), pos(24, 24)]);
onUpdate(() => {
score += dt();
scoreLabel.text = Math.floor(score).toString();
});
});
// ゲームオーバーのシーン
scene("gameover", (score) => {
add([
text(`Game Over\nScore: ${Math.floor(score)}\n[Space] Retry`),
pos(center()),
anchor("center"),
]);
onKeyPress("space", () => go("game"));
});
go("game");
わずか60行ほどですが、ポイントがいくつも詰まっています。
scene()とgo()- タイトル画面、本編、ゲームオーバーといった画面遷移を宣言的に管理できます- タグと
onCollide()- オブジェクトに"obstacle"のような文字列タグを付けておくと、タグ単位で衝突イベントを処理できます loop()とoffscreen()- 敵の定期生成や画面外オブジェクトの自動破棄など、ゲームで頻出する処理がワンライナーで書けます
このコードをベースにスプライトを差し替え、効果音(loadSound() と play())を足すだけで、オリジナルゲームとして十分成立します。筆者はこの構成から始めて、週末のうちに友人に遊んでもらえるレベルのミニゲームまで持っていけました。
ゲームジャムへの参加作品、プログラミング教育の教材、自社サイトに埋め込む販促ミニゲームなど、「短期間でWeb上に動くゲームを出したい」場面全般でKAPLAYは強力な選択肢になります。
KAPLAYで障害物を避けるミニゲームを動かす
上のコードは読むだけでなく、実際にブラウザ上で遊べます。スペースキーでジャンプし、loop()によって一定間隔で生成される障害物(ピンクの矩形)を避け続けてください。プレイヤーにbody()を付けているため重力が働き、ジャンプ後は自然に着地します。障害物にぶつかるとonCollide("obstacle", ...)が発火し、go("gameover", score)でゲームオーバー画面に切り替わる、という流れです。
スコアが伸びる速さを変えたい場合はscore += dt()の係数を、障害物の出現間隔を変えたい場合はloop(1.2, ...)の1.2という数値を書き換えてみてください。数値を1つ動かすだけでゲームの難易度が大きく変わることが体感できるはずです。
KAPLAYでクリックして的を狙い撃つミニゲーム
キー入力だけでなく、マウス操作でもゲームを作れるのがKAPLAYの強みです。onClick(tag, callback)を使うと、area()コンポーネントを持つ特定のタグのオブジェクトがクリックされたときだけ処理を実行できます。以下のサンプルでは、黄色い的("target"タグ)をクリックするたびにdestroy()で消し、新しい的をspawnTarget()で補充しています。
function spawnTarget() {
add([
circle(18),
pos(rand(40, width() - 40), rand(80, height() - 40)),
area(),
color(255, 215, 0),
"target",
]);
}
// "target"タグを持つオブジェクトがクリックされたら発火
onClick("target", (target) => {
destroy(target);
hits += 1;
spawnTarget();
});
実際に動かして、的を連続でクリックしてみてください。ヒット数がその場でカウントアップされます。
spawnTarget()内のcircle(18)の半径を小さくすると狙いにくくなって難易度が上がり、forループの初期個数を増やすと画面がにぎやかになります。onClick()はarea()コンポーネントを持つオブジェクトにしか反応しない点も、実装時に押さえておくと便利です。
まとめ
KAPLAYの魅力を振り返ります。
- Kaboom.jsの思想を受け継ぎ、コミュニティによって活発に開発が続く2Dゲームライブラリです
- コンポーネントを配列で組み合わせるAPIにより、数十行で物理挙動付きのゲームが動きます
- シーン管理・衝突判定・タグシステムなど、ゲーム開発の定番機能が最初から揃っています
まずはブラウザで動くKAPLAYGROUNDのサンプルをいくつか触ってみて、気に入ったら npx create-kaplay で手元に環境を作ってみてください。「ゲーム開発は大変」というイメージが、良い意味で裏切られるはずです。
