Amazon SumerianでRoll a Ballを作ってみた

Amazon Sumerianがどんな感じか知るために[Unity - はじめてのUnity](https://unity3d.com/jp/learn/tutorials/projects/hajiuni-jp)のような玉転がしゲームを作ってみた。
矢印キーで上下左右移動、アイテムを全て取るとゲームクリア。炎に触れるとゲームオーバーになる。
2018/5/16あたりまでで作成した。

![ezgif-1-84cf1570f3.gif](https://qiita-image-store.s3.amazonaws.com/0/16768/98728d8d-c87e-c876-d512-7978471f9ac1.gif)

他の人がSumerianをさわる時のために作成手順を記録しておく。
作成手順を実行する前提として基本的なSumerianのチュートリアルを行っておくことが必要になると思う。
また、Sumerianはプレビュー版なのでここから仕様が変わる可能性がある。

# 作成手順

## シーンの作成

Default Lighting templateベースでシーンを作成する。

### 参考にしたAmazon Sumerianのチュートリアル

* [Amazon Sumerian Interface | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/getting-started/sumerian-interface/)

## ステージを作成

### やること

Entityを配置してプレイヤーを覆う床と壁があるステージを作る。

### 手順

Box Entityを5つ追加してステージの壁と床を作成しそれぞれ名前をFloor、Wall1、Wall2、Wall3、Wall4にしておく。
それぞれのTransform Componentの値を以下のようにする。

* Floor

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | 0 | 0 | 0 |
| Rotation | 0 | 0 | 0 |
| Scale | 20 | 0.1 | 20 |

* Wall1

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | -10 | 1 | 0 |
| Rotation | 0 | 0 | 0 |
| Scale | 1 | 2 | 20 |

* Wall2

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | 10 | 1 | 0 |
| Rotation | 0 | 0 | 0 |
| Scale | 1 | 2 | 20 |

* Wall3

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | 0 | 1 | 10 |
| Rotation | 0 | 90 | 0 |
| Scale | 1 | 2 | 20 |

* Wall4

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | 0 | 1 | -10 |
| Rotation | 0 | 90 | 0 |
| Scale | 1 | 2 | 20 |

### 参考にしたAmazon Sumerianのチュートリアル

* [Amazon Sumerian Basics: Creating a TV Room | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/getting-started/sumerian-basics-tv-room/)

## プレイヤーの移動

### やること

ボールをプレイヤーとして設定する。
プレイヤーは物理法則に従って動くようにし、矢印キーで前後左右に動けるようにする。

### 手順

* Sphere Entityを追加して名前をPlayerにしておく。
* PlayerのTransform Componentを以下のような値にする。

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | 0 | 4 | 0 |
| Rotation | 0 | 0 | 0 |
| Scale | 1 | 1 | 1 |

* PlayerにCollider Componentを追加しShapeをSphereに変更する。
* PlayerにRigid Body Componentを追加する。
* PlayerにState Machine Componentを追加し、以下のBehaviorを設定する。
![Screenshot-2018-5-14 Sumerian Console.png](https://qiita-image-store.s3.amazonaws.com/0/16768/6b908935-e317-1f36-b96c-07fccbc9527a.png)
* Floor、Wall1～4にCollider Componentを追加する。

### 参考にしたAmazon Sumerianのチュートリアル

* [Flying a Drone | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/getting-started/flying-a-drone/)

## カメラを動かす

### やること

カメラがプレイヤーを斜め下に見下ろしながら追随するように設定する。

### 手順

* Default CameraのCamera ComponentのGeneral>Follow Editor Cameraのチェックを外す。
* Default CameraのTransform Componentを以下のような値にする。

|  | x | y | z |
|:--|:--:|:--:|:--:|
| Translation | -6 | 13 | 0 |
| Rotation | -55 | -90 | 0 |
| Scale | 1 | 1 | 1 |

* Default Cameraに以下のようなScriptを設定しTarget ParameterにPlayerを設定しておく。

```javascript
'use strict';
	
var offset;

function setup(args, ctx) {
	offset = ctx.entity.getTranslation().sub(args.target.getTranslation()).clone();
}

function update(args, ctx) {
	ctx.entity.setTranslation(args.target.getTranslation().add(offset));
}

var parameters = [
	{
		name: "Target",
		key: "target",
		type: "entity"
	}
];
```

### 参考にしたAmazon Sumerianのチュートリアル

* [Scripting Basics | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/beginner/scripting-basics/)

## アイテム回収の追加

### やること

触れると消えるアイテムを配置する。

### 手順

* Box Entityを追加して名前をItemにしておく。
* ItemにCollider Componentを追加してTriggerにチェックを入れる。
* Itemに State machine Componentを追加して以下のBehaviorを設定する。

![9b00b5db-018c-47d6-b7a3-43e273c775b0.png](https://qiita-image-store.s3.amazonaws.com/0/16768/650c4bb3-de87-fe33-e86c-0b43d89ec484.png)

### PlayerがItemに触れてもItemが消えない場合

一旦Sceneの編集を終了して再び開きなおすと正常に動作する場合がある。

### 参考にしたAmazon Sumerianのチュートリアル

* [State Machine Editor Interface | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/beginner/state-graph-editor-interface/)
* [State Machine Basics | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/beginner/state-machine-basics/)

## ゲームのUIを追加する

### やること

アイテムの残りカウントを表示する。

### 手順

* HTML Entityを追加して名前をCounterにしておく。
* CounterのHTML ComponentのMove with Transformのチェックを外しておく。
* CounterのHTML Componentを編集して以下のようにする。

```html
<style>
#counter {
  margin: 10px;
  font-size: 40px;
}

</style>

<div id="counter">test</div>
```

* Item全てにItemタグを追加する。

![キャプチャItemTag.PNG](https://qiita-image-store.s3.amazonaws.com/0/16768/b1278e94-ff71-6041-4f84-1f4fa91366fa.png)

* CounterにScript Componentを追加して以下のようなスクリプトを設定する。

```javascript
'use strict';

var count = 0;

function setup(args, ctx) {
	var entities = ctx.world.getEntities();
	entities.forEach(function(entity) {
		if (entity.hasTag("Item")) {
			count += 1;
		}
	});
	
	counter = document.getElementById("counter");
	counter.textContent = String(count);
	
	sumerian.SystemBus.addListener("counterChange", countChange);
}

function cleanup(args, ctx) {
	sumerian.SystemBus.removeListener("counterChange", countChange);
}

function countChange() {
	count -= 1;
	counter = document.getElementById("counter");
	counter.textContent = String(count);
}
```

* ItemのState machine Componentの設定したBehaviorのHide StateにEmitMessage Actionを追加してChannelをcounterChangeに設定する。

### 参考にしたAmazon Sumerianのチュートリアル

* [Events Basics | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/beginner/events/)
* [Positioning Static HTML | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/intermediate/positioning-static-html/)
* [HTML Component Interaction | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/intermediate/html-component-interaction/)
* [SumerianRunner Events | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/expert/sumerianrunner-events/)

## ゲームのクリアを追加する

### やること

全てのアイテムを回収するとゲームクリア画面を表示するようにする。
ゲームクリア画面で再スタートボタンを押すとページを再読み込みしてゲームを再スタートするようにする(PublishされたSceneでは有効だがScene編集中の実行では押せない）

### 手順

* HTML Entityを追加して名前をGameOverにしておく。
* GameOverのHTML ComponentのMove with Transformのチェックを外しておく。
* GameOverのHTML Componentを編集して以下のようにする。

```html
<style>
	.gameover-background {
		background: #fefefe;
		width: 100vw;
		height: 100vh;
		display: flex;
		align-items: center;
		justify-content: center;
	}
	
	.gameover-center {
	    
	}
	
	#gameover-message {
		text-align: center;
	}
</style>

<div class="gameover-background">
<div class="gameover-center">
    <div id="gameover-message">Game Over</div>
	<input id="reloadgame" type="submit" value="再スタート">
</div>
<div>
```

* GameOverにScript Componentを追加して以下のようなスクリプトを設定する。

```javascript
'use strict';

function setup(args, ctx) {
	document.getElementById("reloadgame").onclick = function() {
		location.reload();
	}
	
	sumerian.SystemBus.addListener("gameOver", gameover);
}

function cleanup(args, ctx) {
	sumerian.SystemBus.removeListener("gameOver", gameover);
}

function gameover(text) {
	if (text != null) {
		console.log(text);
		var msg = document.getElementById("gameover-message");
		console.log(msg);
		msg.textContent = String(text);
	}
}
```

* GameOverにState machine Componentを追加して以下のBehaviorを設定する。

![f9541826-90ce-4f04-8c01-c60bfd547134.png](https://qiita-image-store.s3.amazonaws.com/0/16768/4a5654bd-aa5a-2b13-c4d2-85083423d229.png)

* Counterに設定しているScript中のcountChange(）を以下のように変更する。

```javascript
function countChange() {
	count -= 1;
	counter = document.getElementById("counter");
	counter.textContent = String(count);
	
// === 以下を追加 === //
	if (count == 0) {
		sumerian.SystemBus.emit("gameOver", "Game Clear");
	}
// === ここまで === //
}
```

## 障害物とリスタート

### やること

触れるとゲームオーバーになるアイテムを配置する。

### 手順

* Box Entityを追加して名前をDangerItemにしておく。
* DangerItemにCollider Componentを追加してTriggerにチェックを入れる。
* DangerItemに State machine Componentを追加して以下のBehaviorを設定する。

![キャプチャdangerItemStateMachine.PNG](https://qiita-image-store.s3.amazonaws.com/0/16768/7fcced04-708f-6ac8-b754-6d64626ec260.png)


## SceneをPublish

SceneをPublishする。

### 参考にしたAmazon Sumerianのチュートリアル

* [Publishing a Scene | Learn Amazon Sumerian](https://docs.sumerian.amazonaws.com/tutorials/create/getting-started/publishing-scene/)

# 作ってみた感想など

* HTMLでUIが作成できるのは良い。UnityのuGUIは癖があって学習コストがかかる。
* HTMLの要素をスクリプトでgetElementByIdで取得して操作できたりするのが良い。UnityのNativePluginでそれをやるのは面倒。
* StateMachineである程度のことを視覚的にできるのが良い。UEのブループリントみたいに全てのことをできるような方向に行くのだろうか？現状はスクリプトでしかできないことがある。
* まだプレビュー版のためか不安定。衝突判定が効かなくなったり（ComponentやScriptがあってるはずなので動かなくてかなりはまった）たびたびアクセスできなかったりMaterialで色付けしても反映されない（のでDangerなことを識別するために炎のeffectをつけた）などあった。
* Scene間の遷移やSceneの再開始はどうする？APIを見つけられなかった。ビルドしたURL間で移動することになる？
* UnityのPrefab機能がある？同じ種類のEntityを一つ変更するたびに他に適用するのが面倒。