エンティティ・コンポーネント・システム
PlayCanvasのシーンにあるものは、すべてエンティティです。シーンを映すカメラも、照らすライトも、あらゆるモデル、サウンド、UIの部品、そしてゲームのオブジェクトもそうです。エンティティそのものは、位置、回転、スケールを持ち、ほかのエンティティとの階層の中に居場所を持つ、名前の付いた空間上の一点にすぎません。エンティティに能力を与えるのがコンポーネントです。cameraコンポーネントはエンティティをカメラにし、renderコンポーネントはその位置にメッシュを描画し、rigidbodyコンポーネントはエンティティを物理エンジンに委ね、scriptコンポーネントはその上で独自のコードを実行します。アプリケーションには、コンポーネントのタイプごとに1つのシステムがあり、そのタイプのすべてのコンポーネントを実行します。

このパターンは、エンティティ・コンポーネント・システム(ECS)と呼ばれます。どの方法で開発しても、このパターンを使います。エディター、React、Web Componentsはいずれも、エンジンに対して書いたコードと同じエンティティとコンポーネントを作成します。このセクションの各ページでは、概念を一度説明してから、それぞれの環境での使い方を示します。
エンティティ
エンティティは、Entityクラスのオブジェクトです。エンティティを見つけるのに使える名前とタグ、そしてその下にあるすべてのものと一緒にエンティティのオンとオフを切り替える有効状態を持ちます。位置、回転、スケールは親に対する相対値なので、エンティティを動かすと子も一緒に動きます。
シーンのエンティティは、app.rootをルートとするツリーを形作ります。エンティティは、このツリーに追加されたときにシーンに加わります。それまでは描画されず、スクリプトも実行されません。階層とトランスフォームを参照してください。
コンポーネント
コンポーネントは、エンティティに能力を1つ追加し、その能力の設定をentity.light.colorやentity.camera.fovのようなプロパティとして保持します。1つのエンティティが持てるコンポーネントは、各タイプにつき1つまでです。1つのオブジェクトに2つのライトを持たせるには、それぞれにライトを持つ2つの子エンティティを与えます。
エンジンには、カメラ、ライト、レンダリング、サウンド、物理、アニメーション、パーティクル、ユーザーインターフェースを扱う、およそ20種類のコンポーネントがあります。独自の振る舞いのために、新しい種類のコンポーネントを書くことはありません。代わりにスクリプトを書き、scriptコンポーネントがそのエンティティ上で任意の数のスクリプトを実行します。
システム
コンポーネントのタイプごとに、システムが1つあります。これは、そのタイプのすべてのコンポーネントを作成、更新、破棄し、それらが共有する設定を保持するComponentSystemです。システムを直接扱う必要はほとんどありません。例外の1つが共有の設定で、たとえばapp.systems.rigidbody.gravityは、すべてのRigidBodyを引っ張る重力です。
アプリケーションが実行するのは、登録されたシステムだけです。pc.AppBaseは1つも登録されていない状態で始まるので、使うシステムを列挙します。そうすれば、バンドラーは残りをビルドから除外できます。pc.Applicationは組み込みのシステムをすべて登録し、エディター、React、Web Componentsも同様です。コンポーネントシステムを参照してください。
Unityから移行する場合、エンティティはゲームオブジェクトに、コンポーネントはコンポーネントに当たります。Unityからの移行を参照してください。UnityのDOTSやBevyのようなデータ指向のECSから移行する場合は、PlayCanvasのエンティティが単なる識別子ではなくシーングラフ内のオブジェクトであること、そしてコンポーネントがデータと振る舞いの両方を持つことに注意してください。
1つのシーンを4つの方法で
カメラ、ライト、オレンジ色の箱という3つのエンティティからなるシーンです。カメラは高い位置から下に傾けて箱を見下ろし、箱は3つの面が見えるように回してあります。

- Engine
- Editor
- React
- Web Components
Engineをスタンドアロンで使用するのとおりにアプリケーションを設定し、render、camera、lightのコンポーネントシステムを登録した状態で、次のようにします。
const camera = new pc.Entity('camera');
camera.addComponent('camera', {
clearColor: new pc.Color(0.11, 0.12, 0.17)
});
camera.setPosition(0, 1.1, 3.2);
camera.setEulerAngles(-20, 0, 0);
app.root.addChild(camera);
const light = new pc.Entity('light');
light.addComponent('light');
light.setEulerAngles(45, -30, 0);
app.root.addChild(light);
const material = new pc.StandardMaterial();
material.diffuse = new pc.Color(1, 0.55, 0.2);
material.update();
const box = new pc.Entity('box');
box.addComponent('render', { type: 'box', material: material });
box.setEulerAngles(0, 35, 0);
app.root.addChild(box);
- ヒエラルキーでRootエンティティを選択し、 + をクリックしてCamera › Perspectiveを選択します。インスペクターで、Positionを(0, 1.1, 3.2)、Rotationを(-20, 0, 0)に設定し、cameraコンポーネントのClear Colorを暗い青にします。
- もう一度Rootを選択し、 + をクリックしてLight › Directional Lightを選択します。Rotationを(45, -30, 0)に設定します。
- もう一度Rootを選択し、 + をクリックして3D › Boxを選択します。Rotationを(0, 35, 0)に設定します。
- 箱に色を付けるには、オレンジ色のDiffuseを持つマテリアルを作成し、アセットパネルからビューポート内の箱へドラッグします。
これらのメニュー項目は、名前のとおりのコンポーネントを最初から持つエンティティを作成します。どのエンティティにも、インスペクターのAdd Componentボタンでコンポーネントを追加できます。
import { Application, Entity } from '@playcanvas/react';
import { Camera, Light, Render } from '@playcanvas/react/components';
import { useMaterial } from '@playcanvas/react/hooks';
function Scene() {
const orange = useMaterial({ diffuse: '#ff8c33' });
return (
<>
<Entity name="camera" position={[0, 1.1, 3.2]} rotation={[-20, 0, 0]}>
<Camera clearColor="#1c1f2b" />
</Entity>
<Entity name="light" rotation={[45, -30, 0]}>
<Light type="directional" />
</Entity>
<Entity name="box" rotation={[0, 35, 0]}>
<Render type="box" material={orange} />
</Entity>
</>
);
}
export default function App() {
return (
<Application>
<Scene />
</Application>
);
}
<pc-app>
<pc-material id="orange" diffuse="#ff8c33"></pc-material>
<pc-scene>
<pc-entity name="camera" position="0 1.1 3.2" rotation="-20 0 0">
<pc-camera clear-color="#1c1f2b"></pc-camera>
</pc-entity>
<pc-entity name="light" rotation="45 -30 0">
<pc-light></pc-light>
</pc-entity>
<pc-entity name="box" rotation="0 35 0">
<pc-render type="box" material="orange"></pc-render>
</pc-entity>
</pc-scene>
</pc-app>
どの方法で開発しても、結果はapp.rootの下にある同じエンティティのツリーで、それぞれが1つのコンポーネントを持ちます。エディター、React、Web Componentsはこれらのエンジンオブジェクトを代わりに作成し、必要なときにそれらへアクセスする方法をそれぞれ用意しています。
| Engine | Editor | React | Web Components | |
|---|---|---|---|---|
| エンティティ | new pc.Entity('box') | ヒエラルキーの項目 | <Entity name="box"> | <pc-entity name="box"> |
| ツリー内の位置 | parent.addChild(box) | ヒエラルキーで親の上にドラッグ | 親の<Entity>の中に入れ子にする | 親の<pc-entity>の中に入れ子にする |
| コンポーネント | box.addComponent('render', { type: 'box' }) | インスペクターのAdd Component | <Entity>の中の<Render type="box" /> | <pc-entity>の中の<pc-render type="box"> |
| プロパティ | box.render.castShadows = false | インスペクターのフィールド | castShadows={false} | cast-shadows="false" |
| 独自の振る舞い | box.addComponent('script').create(Spin) | Scriptコンポーネントのスクリプト | <Script script={Spin} /> | <pc-script>の中の<pc-script-instance name="spin"> |
| コードから見たエンジンのエンティティ | box | そのエンティティ上のスクリプトのthis.entity | <Entity>のref | <pc-entity>のentityプロパティ |
このセクションの内容
- エンティティ - エンティティの作成、命名、有効化、破棄、複製。
- コンポーネント - 組み込みのコンポーネントと、その追加、変更、無効化、削除。
- 階層とトランスフォーム - 座標系、ローカル空間とワールド空間、移動と回転、親子関係。
- エンティティの検索 - 名前、パス、タグ、コンポーネント、スクリプトによるエンティティの検索。
関連情報
- スクリプティング - エンティティに独自の振る舞いを与える
- Unityからの移行 - Unityのゲームオブジェクト、コンポーネント、プレハブとPlayCanvasとの対応
- ヒエラルキーパネルとインスペクターパネル - エディターでエンティティとコンポーネントを扱う
<Entity/>と<pc-entity>- ReactとWeb Componentsのエンティティのリファレンス- Entity、Component、ComponentSystem - エンジンのAPIリファレンス