メインコンテンツまでスキップ

UI - リーダーボード

Elementコンポーネントを使用しているリーダーボード。フルシーンを参照してください。

このチュートリアルでは、ビルトインの[Elements] 2を使用して、シンプルなリーダーボードを作成する方法を説明します。リーダーボードは、JSONアセットから取得したデータでプログラムによって動的に埋められます。

ヒエラルキー (Hierarchy)

ヒエラルキー上でUIはこのように見えます:

Hierarchy

私たちは2DのScreenを持っており、タイトルとサブタイトルを表示するための2つの要素、およびリーダーボードデータの背景とパネルとして使用される2つのイメージ要素があります。 Your Score の下には、プレイヤーのリーダーボード内での位置を表示し、Leaderboard の下にはその他の情報を表示します。

また、 Entry Template という無効化されたエンティティもあります。これは、テンプレートの各行に使用するものです。JSONアセット内に存在する各リーダーボードエントリに対して、そのテンプレートをクローンし、各クローンを対応するパネルの下に追加します。

スクリーンの設定

スクリーンは次のように設定されています。

Screen

2Dスクリーンであるため、 Screen Space を選択しました。 Reference Resolution は、ターゲットとしている解像度です。この場合、1080 x 1920です。スケールモードとしてBlendを選択しているため、スクリーンは解像度の変更に適応します。また、スケールブレンドを1に設定しているため、スクリーンは高さの変更にのみ適応されます。

The screen entityには、leaderboardスクリプトを含むScriptコンポーネントもあります。以下で詳細を見ていきます。

Panelの設定

各パネルには、背景を表示するイメージエレメント (Image Element) があります。パネルの下には、Entry Templateのクローンをプログラムで追加します。パネルは画面の中央にアンカーされています。

Entry Templateの設定

リーダーボードの1行ごとのテンプレートは、ヒエラルキー構造上で次のようになっています。

Entry Template

プレーヤーのスコアと 'PTS'という名前のラベルを表示するための、リーダーボードの位置、プレイヤー名、プレイヤーのスコアを表示するための4つの子要素があります。

Entry Template自体はGroup Elementです。

Entry Template Attributes

Group Elementには分割された水平アンカーがあることに注意してください:

Split Anchors

水平アンカーは等しくない(0と1です)ので、スクリーンがリサイズされると、エレメントは自動的に全体の水平領域を埋めるように拡大します。また、エッジから少し離れた小さなギャップを許容するために、水平マージンは50ピクセルに設定されています - マージンはアンカーが分割されたときにのみ設定することができます。

次は、Groupの子要素の残りの部分を見てみましょう。

ポジション (Position)

位置は左にアンカーされています:

Position

Name

名前は左にヒモ付けされ、やや右に移動されます。

Name

スコア (Score)

スコアは右にアンカーされています。

Score

ポイント (Points)

ポイントは右にアンカーされています。

Pts

スクリプト (Script)

JSONアセットを読み取り、リーダーボードにデータを埋め込むleaderboardスクリプトは次のようになります。

var Leaderboard = pc.createScript('leaderboard');

// the text entry template to clone
Leaderboard.attributes.add("template", {type: "entity"});
// the parent leaderboard for the personal score
Leaderboard.attributes.add("personal", {type: "entity"});
// the parent leaderboard for the top ten
Leaderboard.attributes.add("leaderboard", {type: "entity"});

Leaderboard.prototype.initialize = function() {
var self = this;

this.entries = [];

this.load(function (data) {
self.clear();

// add the personal entry
var y = -75;
self.addEntry(self.personal, y, data.personal.position, data.personal.name, data.personal.score);

// add the top ten
y = -60;
for (var i = 0; i < Math.min(data.leaderboard.length, 10); i++) {
self.addEntry(self.leaderboard, y, i+1, data.leaderboard[i].name, data.leaderboard[i].score);
y -= 99; // offset each entry
}
});
};

// clear all leaderboard entries
Leaderboard.prototype.clear = function () {
for (var i = 0; i < this.entries.length; i++) {
this.entries[i].destroy();
}

this.entries = [];
};

// add a new entry into the leaderboard
Leaderboard.prototype.addEntry = function (parent, y, position, name, score) {
var entry = this.template.clone();
entry.enabled = true;

entry.findByName("Position").element.text = position.toString();
entry.findByName("Name").element.text = name.toUpperCase();
entry.findByName("Score").element.text = score.toString();

this.entries.push(entry);

parent.addChild(entry);
entry.translateLocal(0, y, 0);
};

// Mock loading leaderboard data, for this demo we just get the data from a JSON file in the project
// For your project you could download this from a server backend
Leaderboard.prototype.load = function (callback) {
var asset = this.app.assets.find("leaderboard-data.json");
asset.ready(function () {
callback(asset.resource);
});
this.app.assets.load(asset);
};