PlayCanvasでUIを作成するには以下の2点の方法があります。
- Element Componentで作成
- HTML要素を追加して作成
前者はPlayCanvasに備わっている機能で、画像やテキストなどの2Dコンポーネントで構成されるユーザインターフェイスを構築するために使用されます。
また、後者はHTMLやCSS、ブラウザDOMを追加し作成していく、Web標準の機能を使用します。
前者については、他ナレッジ記事にて紹介しております。
※Element ComponentによるUI作成のサンプルのナレッジはこちら
サンプルプロジェクトを用意していますので、ご参照ください。
また、このサンプルを使ってゲームや他コンテンツなど自由に役立ててください。
Project: https://playcanvas.com/project/1024612/
Publish: https://playcanv.as/p/4oiO5Sat/
ここでは、後者の「PCUI」を使ったUIの作成方法を紹介します。
PCUIの設定方法(pcui-use-case)
ここで紹介する「PCUI」はHTML要素を追加することで作成する方法になります。
「PCUI」はWeb用のユーザーインターフェイスコンポーネントライブラリであり、メニューやボタンなどを部品ごと使用することができます。
サンプルプロジェクトのシーン「pcui-use-case」から確認ができます。
ここではRender ComponentのMaterialとRender Type、Transformの数値も変更できるようにUIを作っています。
Root Entity に設定したScriptの「ui-pc.js」のスクリプト属性である targetEntityにはRender Componentを設定したEntity、targetMaterialsにはtargetEntityに設定するMaterialを配列で設定します。
「PCUI」を使用するには、ASSETSにBuildしたPCUIをアップロードしPreloadさせる必要があります。
Preloadさせることで、ui-pc.js でPCUIを使用することができます。
このBuildした PCUI である「pcui-bundle.min.js」を作成するには、GitHubに載っているBuild方法に倣って作成します。
https://github.com/playcanvas/pcui/blob/main/BUILDGUIDE.md
また、サンプルプロジェクトから当Scriptをコピーして別プロジェクトで使用することもできます。
ui-pc.jsのコード内容は以下になります。
let UiPc = pc.createScript('uiPc');
UiPc.attributes.add('html', { type: 'asset', assetType: 'html' });
UiPc.attributes.add('targetEntity', { type: 'entity' , description: 'Primitive 3D Model Entity' });
UiPc.attributes.add('targetMaterials', { type: 'asset' , assetType: 'material', array: true });
UiPc.prototype.initialize = function() {
this.addHtmlWrapper = document.createElement("div"); // シーン変更で削除しやすいdiv要素を作成
this.addHtmlWrapper.id = "pc-htmlWrapper";
this.addHtmlWrapper.style.width = "100%";
this.addHtmlWrapper.style.height = "100%";
document.body.appendChild(this.addHtmlWrapper);
this.setupMainContainer(); // Settingsの大枠のContainer
this.setupMainPane(); // Settingsのパネル設定
this.addRenderSettings(); // select-inputのパネル // Select Render's Type
this.addDivider(); // 罫線を追加
this.addMaterialSettings(); // select-inputのパネル // Select Materials
this.addDivider(); // 罫線を追加
this.addTransformSettings(); // VectorInput - Position, Rotate, Scale
this.addDivider(); // 罫線を追加
this.addMediaInfo(); // 任意のHTMLを挿入するパネル
};
UiPc.prototype.setupMainContainer = function() { // Settingsの大枠のContainer
const { Container } = pcui;
const container = new Container({
grid: true
});
container.style.position = 'relative';
container.style.height = '100%';
container.style.width = '100%';
this.addHtmlWrapper.appendChild(container.dom);
this.ui = container.dom;
};
UiPc.prototype.setupMainPane = function() { // Settingsのパネル設定
const { Container, Panel, Label } = pcui;
const panel = new Panel({
flex: true,
collapsible: true,
collapsed: true,
collapseHorizontally: true,
removable: false,
headerText: 'Settings'
});
const content = panel.content;
panel.style.width = '250px';
this.ui.appendChild(panel.dom);
this.pane = content.dom;
};
UiPc.prototype.addRenderSettings = function() { // select-inputのパネル // Select Render's Type
const { Panel, SelectInput } = pcui;
const panel = new Panel({
flex: true,
collapsible: false,
headerText: 'Primitive Render Type'
});
const content = panel.content;
const options = [ // Select-inputで選択するRender Typeを設定
{ v: 'box', t: 'Box' },
{ v: 'capsule', t: 'Capsule' },
{ v: 'sphere', t: 'Sphere' },
{ v: 'cylinder', t: 'Cylinder' },
{ v: 'cone', t: 'Cone' },
];
const input = new SelectInput({
options,
value: 'box'
});
input.on('change', mode => { // Selectから選択し変更されたらイベントを処理します
this.targetEntity.render.type = mode; // 設定したEntityのRender Typeを指定のものに変更されます
});
content.dom.appendChild(input.dom);
this.pane.appendChild(panel.dom);
};
UiPc.prototype.addMaterialSettings = function() { // select-inputのパネル // Select Materials
const { Panel, SelectInput } = pcui;
const panel = new Panel({
flex: true,
collapsible: false,
headerText: 'Setting Material'
});
const content = panel.content;
const options = [];
for(let i=0; i < this.targetMaterials.length; i++) { // 配列で設定したMaterialをfor文で処理します
options.push({
v: i+1, // 0だとエラーが出る。 // valueに数値を設定
t: this.targetMaterials[i].name // Materialの名前を設定
});
}
const input = new SelectInput({
options,
value: 1
});
this.targetEntity.render.meshInstances[0].material = this.targetMaterials[0].resources[0]; // 初回読み込み時に配列の一つ目のMaterialが設定されるように設定
input.on('change', num => { // Selectから選択し変更されたらイベントを処理します
this.targetEntity.render.meshInstances[0].material = this.targetMaterials[num-1].resources[0]; // 選択した数値を元にMaterialをEntityに変更します
});
content.dom.appendChild(input.dom);
this.pane.appendChild(panel.dom);
};
UiPc.prototype.addTransformSettings = function() { // VectorInput - Position, Rotate, Scale
const { Panel, VectorInput, LabelGroup } = pcui;
const panel = new Panel({
flex: true,
collapsible: false,
headerText: 'Transform'
});
const content = panel.content;
let transforms = ["Position", "Rotate", "Scale"];
for(let i=0; i<transforms.length; i++) { // 上で配列にあるプロパティのPosition, Rotate, Scaleをfor文で一つずつ処理
const labelGroup = new LabelGroup({ // プロパティごとにラベルで囲う
text: transforms[i],
});
content.dom.appendChild(labelGroup.dom);
const input = new VectorInput({ // プロパティごとに入力する数値のinputを作成
min: -180,
max: 180,
step: 0.1,
precision: 2, // 矢印キーの小数点の位の数値を指定
stepPrecision: 1, // Shift押しながら矢印キーの小数点の位の数値を指定
});
input.on('change', vecNum => { // inputの値が変更されたら以下を処理
if(transforms[i] === "Position") { // 変更された値がPositionなら以下を処理
this.targetEntity.setPosition(...vecNum); // 設定したEntityを変更されたPositionに変更
}else if(transforms[i] === "Rotate") { // 変更された値がRotateなら以下を処理
this.targetEntity.setLocalEulerAngles(...vecNum); // 設定したEntityを変更されたRotateに変更
}else if(transforms[i] === "Scale") { // 変更された値がScaleなら以下を処理
this.targetEntity.setLocalScale(...vecNum); // 設定したEntityを変更されたScaleに変更
}
});
labelGroup.dom.appendChild(input.dom);
}
this.pane.appendChild(panel.dom);
};
UiPc.prototype.addDivider = function() { // 罫線を追加
const { Divider } = pcui;
const divider = new Divider();
this.pane.appendChild(divider.dom);
};
UiPc.prototype.addMediaInfo = function() { // 任意のHTMLを挿入するパネル
const { Container } = pcui;
const container = new Container({
flex: true,
});
const media = document.createElement('div');
media.innerHTML = this.html.resource || '';
media.style.userSelect = 'none';
container.style.marginTop = 'auto';
container.style.marginBottom = 'auto';
container.style.marginLeft = 'auto';
container.style.marginRight = 'auto';
container.dom.appendChild(media);
this.pane.appendChild(container.dom);
};
各パーツごと生成して、 addChild() などを使ってHTMLのブラウザDOMに落としこんています。
上記のコードでは簡易的ではあるが、処理の内容をコメントアウトしています。
PCUI について詳しく知りたい場合はこちらをご参照ください。
https://playcanvas.github.io/pcui/
コメント
0件のコメント
サインインしてコメントを残してください。