テーマ
ノード管理
エンジンでは、画面に表示されるすべてのゲームオブジェクトをノードと呼びます。矩形、円、テキスト、スプライト、線、NineSlice の 6 種類があり、それぞれ用途に応じて使い分けます。
ノードの種類
| type | 用途 | 主なプロパティ |
|---|---|---|
rect | 矩形(背景、ボタン、当たり判定など) | width, height, fill |
circle | 円(キャラクター、弾など) | radius, fill |
text | テキスト表示 | text, font, fill, align |
sprite | 画像スプライト | image, width, height, anchor |
line | 線(壁、区切り線など) | x2, y2, stroke, lineWidth |
nineslice | UI パネル(RPG 風のウィンドウ枠) | width, height, fill, borderColor |
ノードの追加
単体追加: engine.add(id, config)
typescript
// 矩形
engine.add('player', {
type: 'rect',
x: 100,
y: 200,
width: 30,
height: 30,
fill: '#3b82f6',
});
// 円
engine.add('enemy', {
type: 'circle',
x: 300,
y: 100,
radius: 20,
fill: '#ef4444',
});
// テキスト
engine.add('label', {
type: 'text',
x: 300,
y: 50,
text: 'Score: 0',
font: 'bold 16px sans-serif',
fill: '#fff',
align: 'center',
});
// スプライト画像
engine.add('ship', {
type: 'sprite',
x: 100,
y: 100,
image: 'player',
width: 32,
height: 32,
anchor: { x: 0.5, y: 0.5 },
});
// 線
engine.add('wall', {
type: 'line',
x: 0,
y: 300,
x2: 600,
y2: 300,
stroke: '#fff',
lineWidth: 2,
});一括追加: engine.addMany(nodes)
複数のノードを配列で一括追加できます。シーンの初期配置に便利です。
typescript
engine.addMany([
{ id: 'bg', type: 'rect', x: 0, y: 0, width: 600, height: 600, fill: '#000' },
{ id: 'title', type: 'text', x: 300, y: 100, text: 'Hello', fill: '#fff', align: 'center' },
]);ノードの更新と取得
engine.update(id, props)
ノードの任意のプロパティをいつでも変更できます。
typescript
engine.update('player', { x: 150, y: 250 });
engine.update('label', { text: 'Score: 100' });engine.get(id)
ノードの現在の状態を取得します。存在しなければ null を返します。
typescript
const player = engine.get('player');
if (player) {
console.log(player.x, player.y);
}ノードの削除
engine.remove(id)
指定したノードを削除します。子ノードも再帰的に削除されます。
engine.clear()
全ノード・コールバック・タイマーをクリアします。シーン遷移時には自動的に呼ばれます。
共通プロパティ
すべてのノードに共通で使えるプロパティです。
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
x, y | number | 0 | 位置 |
alpha | number | 1 | 透明度(0 で完全透明、1 で不透明) |
scaleX, scaleY | number | 1 | 拡大率 |
rotation | number | 0 | 回転(ラジアン) |
flipX, flipY | boolean | false | 水平・垂直反転 |
tint | string | — | カラーティント(CSS カラー値) |
tintAmount | number | 0.5 | ティントの強度(0〜1) |
visible | boolean | true | 表示・非表示 |
tag | string | — | タグ(グループ化に使用) |
parent | string | — | 親ノード ID |
clipRect | {x,y,width,height} | — | クリッピング領域 |
onClick | () => void | — | クリック・タップ時のハンドラ |
onDown | () => void | — | ポインタ押下時のハンドラ |
onUp | () => void | — | ポインタ解放時のハンドラ |
リッチテキスト
テキストノードで richText: true を指定すると、一部のテキストだけ色を変えるインラインカラーが使えます。{c:#色コード}テキスト{/c} の書式です。
typescript
engine.add('dialog', {
type: 'text',
x: 50,
y: 400,
text: '{c:#7c3aed}長老{/c}「{c:#3b82f6}クリスタル{/c}を集めよ」',
font: '16px sans-serif',
fill: '#fff',
richText: true,
align: 'center',
});TIP
ネストはできません。{c:色A}...{c:色B}...{/c}...{/c} のような書き方は不可です。
反転とティント
flipX / flipY
キャラクターの向きを変えるときに使います。親ノードに設定すると子ノードにも反映されます。
typescript
// 左向きにする
engine.update('hero', { flipX: true });tint(色変え)
同じスプライトで色違いを作ったり、ダメージ時の赤点滅に使います。
typescript
// ダメージ時に赤く点滅させて元に戻す
engine.update('hero', { tint: '#ff0000', tintAmount: 0.6 });
await engine.animate('hero', { tintAmount: 0 }, { duration: 400 });
// 同じ画像で色違いの敵を作る
engine.add('enemy-fire', {
type: 'sprite',
image: 'slime',
x: 100,
y: 100,
width: 32,
height: 32,
tint: '#ff4400',
tintAmount: 0.4,
});
engine.add('enemy-ice', {
type: 'sprite',
image: 'slime',
x: 200,
y: 100,
width: 32,
height: 32,
tint: '#0088ff',
tintAmount: 0.4,
});NineSlice(UI パネル)
RPG のウィンドウ枠のような装飾パネルを描画するノードです。画像を使わない Canvas 描画モードと、スプライトシートを使う画像モードがあります。
Canvas 描画モード(画像不要)
typescript
engine.add('panel', {
type: 'nineslice',
x: 20,
y: 50,
width: 300,
height: 200,
fill: '#0f1729',
borderColor: '#4a90d9',
borderWidth: 2,
borderStyle: 'double', // 'solid' | 'double' | 'groove'
innerColor: '#2a5aa0',
innerPadding: 4,
cornerRadius: 8,
});画像ベースモード
typescript
engine.add('frame', {
type: 'nineslice',
x: 10,
y: 10,
width: 400,
height: 300,
image: 'ui-frame',
sliceSize: 16,
});| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
fill | string | — | 背景色 |
borderColor | string | — | 外枠の色 |
borderWidth | number | 2 | 枠線の太さ |
borderStyle | string | 'solid' | 枠線スタイル(solid / double / groove) |
innerColor | string | borderColor | 内枠の色(double / groove 用) |
innerPadding | number | 4 | 外枠と内枠の間隔 |
cornerRadius | number | 0 | 角丸の半径 |
image | string | — | 画像キー(指定時は画像モード) |
sliceSize | number | img.width/3 | 9 分割時のスライスサイズ |
親子関係
子ノードは親の座標系を引き継ぎます。親を移動すると子も一緒に移動し、親の回転・拡縮・透明度も子に反映されます。
親子の設定
ノード追加時に parent プロパティで指定するか、後から setParent() で設定できます。
typescript
// 追加時に指定
engine.add('body', { type: 'circle', x: 100, y: 100, radius: 30, fill: '#22c55e' });
engine.add('eye', { type: 'circle', x: 10, y: -5, radius: 5, fill: '#fff', parent: 'body' });
// 後から設定
engine.setParent('eye', 'body');
// 親を解除
engine.setParent('eye', null);親子関係の取得
typescript
engine.getChildren('body'); // 子ノード ID の配列
engine.getParent('eye'); // 親ノード ID(なければ null)
engine.getWorldPos('eye'); // ワールド座標(親の座標を加算した位置)タグとノード検索
タグを使うとノードをグループ化して、まとめて操作できます。
typescript
// タグ付きで追加
engine.add('e1', { type: 'circle', x: 100, y: 100, radius: 10, fill: '#f00', tag: 'enemy' });
engine.add('e2', { type: 'circle', x: 200, y: 100, radius: 10, fill: '#f00', tag: 'enemy' });
// タグで検索
engine.findByTag('enemy'); // ['e1', 'e2']
// タグで一括更新
engine.updateByTag('enemy', { fill: '#ff0' });
// タグで一括削除
engine.removeByTag('enemy');条件関数でノードを検索・削除することもできます。
typescript
// x < 0 のノードをすべて取得
engine.findAll((node) => node.x < 0);
// x < 0 のノードをすべて削除
engine.removeAll((node) => node.x < 0);Z 順序(描画順)
ノードは追加順に描画されます。後から追加したノードが手前に表示されます。描画順を変えたい場合は以下を使います。
typescript
engine.sendToFront('player'); // 最前面へ
engine.sendToBack('bg'); // 最背面へクリッピング
clipRect を指定すると、ノードとその子ノードが矩形領域内にのみ描画されます。スクロール可能な領域を作るときに便利です。
typescript
engine.add('viewport', {
type: 'rect',
x: 50,
y: 50,
width: 0,
height: 0,
clipRect: { x: 0, y: 0, width: 200, height: 300 }, // ローカル座標で指定
});
engine.add('content', {
type: 'text',
x: 10,
y: 10,
text: 'Clipped!',
parent: 'viewport',
});ノードプール
弾幕ゲームのように大量の同種ノードを生成・破棄する場合、プールを使うとパフォーマンスが向上します。
typescript
const pool = engine.createPool({
tag: 'bullet',
create: () => ({ type: 'rect', x: 0, y: 0, width: 4, height: 10, fill: '#ff0' }),
initialSize: 20,
});
// ノードを取得(visible: true になる)
const id = pool.acquire();
engine.update(id, { x: playerX, y: playerY });
// 不要になったら返却(visible: false になる)
pool.release(id);
// 全ノードを返却
pool.releaseAll();TIP
プールはノードの生成コストを削減します。acquire() は新規作成ではなく非表示のノードを再利用するため、GC の負荷も抑えられます。