UI
はじめに
8th Wall Studioは、インタラクティブでユーザーフレンドリーなインターフェースを作成するためのUIシステムを内蔵しています。UIレイアウトとコンポーネント
Studioには、テキストや画像からボタンやフレームまで、さまざまなUIビルディングブロックが用意されています。 階層パネルの直感的な(+)オプションにより、UI要素の追加やカスタマイズが簡単に行えます。 UI Element Componentには、CSSとFlexboxにインスパイアされた詳細な設定項目があり、ボーダーから背景色まですべてを調整できます。 フレックスボックスのスタイリングについては、こちらを参照してください。
UI要素の追加
UI要素を導入するには、いくつかの方法がある:
- **ビジュアルエディター:**プリセットを追加するには、階層の(+)オプションを使用します。
- コンポーネントメソッド: UI 要素をコンポーネントとしてエンティティにアタッチします。
- スクリプティング: APIを使用してプログラムで要素を追加します。
3D UI
3D UIエレメントは3Dシーンにシームレスに統合され、空間的にインタラクティブな表示が可能になります。 インスペクタやトランスフォーム・ギズモで調整できます。
交流
イベントリスナーを持つカスタムコンポーネントを使用して、3D UI要素にインタラクションを追加できます。
例
import * as ecs from '@8thwall/ecs'
ecs.registerComponent({
name: '3D Button',
schema: {
},
schemaDefaults: {
},
data: {
},
stateMachine: ({world, eid}) => {
ecs.defineState('default')
.initial()
.listen(eid, ecs.input.SCREEN_TOUCH_START, (e) => {
console.log('Interacted!')
})
},
})
オーバーレイUI
スクリーンに固定されたUIでは、オーバーレイ要素は絶対位置決めを提供します。 シミュレータ内でこれらの要素をプレビューし、レスポンシブデザインのためにパーセンテージベースのサイジングを使用します。
交流
イベントリスナーを持つカスタムコンポーネントを使用して、Overlay UI 要素にインタラクションを追加できます。
例
import * as ecs from '@8thwall/ecs'
ecs.registerComponent({
name: 'Overlay Button',
schema: {
},
schemaDefaults: {
},
data: {
},
stateMachine: ({world, eid}) => {
ecs.defineState('default')
.initial()
.listen(eid, 'click', (e) => {
console.log('Interacted!')
})
},
})
ステートマシンとの統合
このページの前の例で見たように、UIはステートマシンと統合して、下の写真のような基本的なメニューナビゲーションなどの機能を実装することができる。
UIコンポーネントで作られたこれらのボタンは、操作されたときにイベントをディスパッチするように設定できる。
ecs.registerComponent({
name: 'start-button',
stateMachine: ({world, eid}) => {
ecs.defineState('default')
.initial()
.listen(eid, ecs.input.UI_CLICK, () => {
world.events.dispatch(eid, 'onStartButtonClick')
})
},
})
Studioで作成されたUIメニューは、状態別に追跡および整理することができます。
enum GAME_STATES {
GAME_START = 'gameStateStart',
GAME_ACTIVE = 'gameStateActive',
GAME_OVER = 'gameStateOver',
}
enum GAME_MENUS {
START_MENU = 'startMenu',
GAME_OVER_MENU = 'gameOverMenu',
}.
他のすべてのメニューを非表示にし、アクティブにしたい1つのメニューを表示することで、メニュー間の切り替えを容易にするために、プログラムで非アクティブなすべてのメニューを非表示にする関数を使用することができます。
const updateUI = (world, schema, activeMenu = null) => {
Object.values(GAME_MENUS).forEach((menu) => {
if (schema[menu]) {
if (menu === activeMenu) {
ecs.Hidden.remove(world, schema[menu])
} else {
ecs.Hidden.set(world, schema[menu])
}.
} else {
console.warn(`Menu ${menu} is not defined in the schema.`)
}.
})
}
上記はすべて、ボタンのクリックやゲームの状態によって変化するメニューナビゲーションのステートマシンを管理するために使用できる。 次の例では、スタートボタンをクリックするとゲームが始まり、設定した時間が経過するとゲームオーバーメニューが表示されます。 ゲームオーバーメニューからは、さらにボタンでゲームを再開したり、スタートメニューに戻ったりすることができる。
ecs.registerComponent({
name: 'game-controller',
schema:{
startMenu: ecs.eid,
gameOverMenu: ecs.eid,
gameActiveMenu: ecs.eid,
},
data: {
isGameActive: ecs.boolean,
},
stateMachine: ({world, eid, dataAttribute, schemaAttribute}) => {
const gameOver = ecs.defineTrigger()
ecs.defineState(GAME_STATES.GAME_START)
.initial()
.onEnter(() => {
console.log('ゲームスタートに入った')
updateUI(world, schemaAttribute.cursor(eid), GAME_MENUS.START_MENU)
})
.onEvent('onStartButtonClick', GAME_STATES.GAME_ACTIVE, {target: world.events.globalId})
ecs.defineState(GAME_STATES.GAME_ACTIVE)
.onEnter(() => {
console.log('状態変化: Entered Game Active')
updateUI(world, schemaAttribute.cursor(eid), 'gameActive')
setTimeout(() => {
console.log('Waiting done. Triggering game over.')
gameOver.trigger()
}, 1000)
})
.onTrigger(gameOver, GAME_STATES.GAME_OVER)
ecs.defineState(GAME_STATES.GAME_OVER)
.onEnter(() => {
dataAttribute.cursor(eid).isGameActive = false
updateUI(world, schemaAttribute.cursor(eid), GAME_MENUS.GAME_OVER_MENU)
})
.onEvent('onRestartButtonClick', GAME_STATES.GAME_ACTIVE, {target: world.events.globalId})
.onEvent('onReturnStartClick', GAME_STATES.GAME_START, {target: world.events.globalId})
},
})
フォント
デフォルトフォント
デフォルトのフォントは、UIシステム内で使用できます。
Nunito
Akidenz Grotesk
Baskerville
Futura
Gotham
Helvetica
Nanum Pen Script
Press Start 2P
Times
Inconsolata
カスタムフォント
また、TTFファイルを介してカスタムフォントをアップロードし、UIエレメントで使用することもできます。 カスタムフォントファイルをアセットに追加して、利用できるようにしましょう。