Skip to content

ノード管理

エンジンでは、画面に表示されるすべてのゲームオブジェクトをノードと呼びます。矩形、円、テキスト、スプライト、線、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
ninesliceUI パネル(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, ynumber0位置
alphanumber1透明度(0 で完全透明、1 で不透明)
scaleX, scaleYnumber1拡大率
rotationnumber0回転(ラジアン)
flipX, flipYbooleanfalse水平・垂直反転
tintstringカラーティント(CSS カラー値)
tintAmountnumber0.5ティントの強度(0〜1)
visiblebooleantrue表示・非表示
tagstringタグ(グループ化に使用)
parentstring親ノード 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,
});
プロパティデフォルト説明
fillstring背景色
borderColorstring外枠の色
borderWidthnumber2枠線の太さ
borderStylestring'solid'枠線スタイル(solid / double / groove
innerColorstringborderColor内枠の色(double / groove 用)
innerPaddingnumber4外枠と内枠の間隔
cornerRadiusnumber0角丸の半径
imagestring画像キー(指定時は画像モード)
sliceSizenumberimg.width/39 分割時のスライスサイズ

親子関係

子ノードは親の座標系を引き継ぎます。親を移動すると子も一緒に移動し、親の回転・拡縮・透明度も子に反映されます。

親子の設定

ノード追加時に 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 の負荷も抑えられます。