5月社内ゲームジャムの成果物「DrawBungeeRope」/ LineRendererで線描画する話
社内ゲームジャムにて
- ゲームジャム部の5月の活動で「紐」をテーマにゲームを作りました。
- 「DrawBangeeRope」
- PCブラウザでのプレイはこちらからどうぞ
- バンジージャンプする人の紐を書いてあげるゲームです。
- 今回は紐の描画にLineRendererを使ったので使い方を書きます。
LineRenderer
- LineRendererはUnity上に線を描画するコンポーネント
使い方
LineRendererは特定の座標間に直線を描画する。
動的に描画しない / 描画してから動かない のであればインスペクタで座標を指定する
- Positions->size に指定する座標の個数を入力する
- Positions->ElementX に座標を指定する
- 動的に生成したい / 線を動かしたいのであれば、スクリプトで座標を指定する
以下はドラッグ時に線を描画するサンプルコード
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Linq; public class Rope : MonoBehaviour { public List<Vector2> drawRopePositionList = new List<Vector2>(); private LineRenderer lineRenderer; void Start () { lineRenderer = GetComponent<LineRenderer>(); // 線の描画を有効にする lineRenderer.enabled = true; } void Update () { if (Input.GetMouseButton(0)) { Draw(); } } void Draw () { Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); // drawRopePositionListは後にロープの長さの計算を行うため作成している // 線を描画したいだけであれば直接、LineRendererに座標を格納するので良い // ただし、余計な描画は避ける為に、最後と同じ位置であれば座標を格納しないようにしている if (drawRopePositionList.Count == 0 || (mousePosition != drawRopePositionList.Last())) { drawRopePositionList.Add(mousePosition); } if (drawRopePositionList.Count > 0) { // 座標の格納可能数を更新する lineRenderer.pSetVertexCount(drawRopePositionList.Count); Vector3 lineRendererPosiotion = new Vector3(mousePosition.x, mousePosition.y, -1.0f); // 座標を格納する // SetPosition(index, Vector3) // 既にindexに座標が格納されている場合、更新される // これを利用して毎フレーム毎に伸び縮みする線の描画等も可能 lineRenderer.SetPosition(drawRopePositionList.Count - 1, lineRendererPosiotion); } } }
描画する線の色や質感を変えたい
- まず適当なMaterialを作ります
- Projectビューより create -> Material
作成した Material を LineRenderer -> Materials にて指定する
- Size を変更することによって複数の質感を同時に適応することも可能
(1) Material 自体の色を変更するやり方
- Material にて “Shader” を “Standard” に変更
- MainMaps の “Albedo” の項目にて好みの色に変更する
- 他のパラメータもよしなに変更する
(2) LineRendererのParamatersのStartColor/EndColorを変更するやり方
- Material にて “Shader” を “Particle -> Additive(Soft)” に変更
- LineRenderer にて Paramaters -> StartColor/EndColor をよしなに変更する
- このやり方であれば、α値を変更することで線を透過させることも可能
スクリプトからも変更出来るので線をフェードアウトさせることも出来る
public IEnumerator FadeOut () { float a = 1.0f; while (a > 0) { Vector4 color = new Vector4(1.0f, 1.0f, 1.0f, a); // SetColors(StartColot, EndColor) // 線の先頭と末尾で同じ色を使用しているので同じ値を指定している // 先端から徐々にフェードアウトしたい、みたいなケースは個別に指定が必要 lineRenderer.SetColors(color, color); yield return new WaitForSeconds(0.1f); a -= 0.1f; } // α値が0になったら線の描画自体をやめる lineRenderer.enabled = false; yield break; }
線がSpriteよりも後ろに描画される
- Material に Particle を指定している場合のみ。
- LineRenderer に限らず Particle は同一の SortingLayer にて Sprite の背面に描画されてしまう。
- Particle 専用の SortingLayer を用意して、その SortingLayer を前面に出すやり方が簡単。
- SortingLayer は描画に関するレイヤー
- Layer は物理挙動に関するレイヤー (異なるレイヤーであれば衝突しない、みたいな設定が出来る)
- 以下のテラシュールブログさんの記事がすごいためになる。
Unityのスプライトの描画順は「SortingLayer、Order In Layer、Z値」の順番で設定します。
レイヤーの追加
- 上部メニューより Edit -> ProjectSettings -> Tags and Layers を開く
- SortingLayersに適当な名前のレイヤーを追加する
レイヤーの指定(インスペクタ)
- SpriteRenderer に SortingLayer を指定する箇所があるのでそこで指定する
レイヤーの指定(スクリプト)
LineRenderer のように SortingLayer の指定箇所が無い場合はスクリプトにて指定する
private LineRenderer lineRenderer; void Start () { lineRenderer = GetComponent<LineRenderer>(); lineRenderer.enabled = true; lineRenderer.sortingLayerName = "Particle"; }
Unite2015Tokyo Day2メモ
- ざっくり自分用メモ
- uGUIパフォーマンスの話が特に参考になった
- 英語や上級者向けの公演全然付いて行けなかった…
- Urban Coaster死ぬかと思った…
Unityパフォーマンスチューニング
ゲーム作成時のオプティマイズ
Unityプロファイラ
- プロファイラで見れるもの
- CPU/GPU/Audio/Physics/Memory usage
- Unity5はパーソナル版で誰でも使える様になってるよ
CPUプロファイラ
- 時間がかかっている順に表示
- ゲームが実際に動いている最中に表示出来る
CPUプロファイラ: タイムライン
- 何が起きたか視覚的に把握出来る
- 同期/何かが起きたときに中断が起きているなど
メモリプロファイラ
- ヒープ用にかなりメモリを割り当てている
- 詳細を見ることが出来るが負荷的にスナップショット的な活用が望ましい
LOADING DATA
- データ種別
- シーン
- シーンが依存するアセット
- リソース/ストリーミングアセット/WWW
自分の好きなローディングパイプラインを作ることを可能
非同期ローディング
- Application.LoadLevel *Async
- AssetBundle.Load* Async
- 5.0: Resources.LoadAsync
- Batch size still matters
- 5.0: texture continue to load in background
シーンローディング: メモリの消費
- 現在のシーンは新しいシーンがreadyになるまで取り込まれない
- アセットに関しても同様
- メモリスパイクが発生するときの対処
- 空のシーン(loading)を用意し、古いシーンをpargeしてから新しいシーンを読み込む等
ローディング: シリアライゼイション
ローディング: アセットバンドル
- プレイヤーの再是の最適化
- build timeの最適化
- ローカル/Webサーバから高速データ取得
- WWW.LoadFromCacheOrDownLoad();
- 全てのデータをバンドルすることが出来る (WWW特有問題の解決)
UNLOADING
- オブジェクトの削除作業のスレッド上での実施
- Resources.unloadUnusedAssets / GC.Collect
- 安全な仕組みが無い
- 今使用しているアセットか否かを判断出来ない
GC パフォーマンス
- GC.Collect によりスパイクが発生する
REDUCE GC WORK
- レファレンスするようなデータをパックする
- メモリの移動量を減らす / メモリを消去する
RESULTS
- GC for array length of 1,000,000 charactoets on MBP
- Class with randomized memory locations: 35ms
- Class with linear memory: 20ms
- Struncts: 10ms
- Strunct and no String: 0.18ms
MINIMIZING MANAGED ALLOCATIONS
- Reuse temporary buffers
- Allocate pools of reusable
- Use structs instead of classed
- OnGUIは使用しないで new UI System を使ってね
プール
GC chrun
- Instantiate/Destroy overhead
プール方法
- プールの中ではdictionaryは使わない、Listを使うのが良い
- 事前に暖めておく
- プールの中のオブジェクト
- 使用するときにSetActive(true)
- 画面外へ置いておく
- 5.0 においては Instantiarion / actibvation のパフォーマンスが50%程度改善している
一般的なパフォーマンス関連のコツ
将来的に
- メインスレッドから処理をどんどん剥がして行く
- ストリーミングの改善/最適化
- GCを静的に
- transformの階層化に対する負荷を下げる
- 更ならプロファイリングツールを!
まとめ
- 非同期ローディングしよう
- メモリの利用パターンを意識しよう
- データをレイアウトする際にゲームパフォーマンスを意識する
- オブジェクトをキャッシュして再利用しよう
- パフォーマンスの最適化のためにプロファイラを見よう
Unityのシーンを紐解き把握するには
- 今回話す内容
- プロジェクトをサクっと読む方法
- 何故こんなことが必要になったのか
- バグレポートの構造解析
- サンプルシーンの解析
- コード記載するの面倒
- 昔作ったプロジェクトが読めない
- シーンの構造やメタデータをごにょごにょする話し
シーン構築のルールを確認
- プロジェクト>シーン>オブジェクト>コンポーネント
- プロジェクト
- コンポーネントはコールバックで動作する
- 始点はコールバックから
- Start/Update/FixedUpdate/OnCollisionEnter…
- コンポーネント動かない条件
- 非アクティブなオブジェクトは動かない
- 参照もコールバックも無いと動かない
- コンポーネントを持たないと動かない
- オブジェクトへのメッセージ
- コンポーネントへのメッセージ
- event/UnityEvent/StartCoroutine
- 参照手法例
- GetComponent
- GetComponentInChild/Parent
- FindWithType/FindWithTag
- オブジェクトを作る方法
- オブジェクトの元を得る方法
ルールを基に情報を集める
- コンポーネントの呼び出しの把握
- どのコンポーネントがいつ動くのかが大事
- コールバック (OnCollider/OnTrigger/OnMouse/SendMessage…) を持つか?
- ランタイムで増減する
- どのコンポーネントがいつ動くのかが大事
コンポーネントの列挙
- コンポーネント一覧からからコールバック一覧を取得するエディタ拡張作るハック
IEventSystemHandler
- IEventSystemHandlerを継承している場合はインスペクタで確認出来る
- e.g) uGUI>button>InterceptedEvent
文字列のメソッドコール
- 任意のメソッド名で呼ばれる (AnimationEvent/SendMessage/EventSystem)
- コールバックとして計上しておく
-
- 無理
- オブジェクトを消したときのリスクが不明
- 参照情報を元に被参照リストを作る
三章先の座標の確認
- handlerを使って矢印を貼ると紐付けを確認しやすい
量が多すぎると混乱するのでストリップする仕組み
以下を参照リストから削除する
- オブジェクトの親子関係で構築した参照
- オブジェクト内で自己完結している参照
- 選択中のオブジェクト内での参照
どこからも参照されないオブジェクト
- 自己完結しているコンポーネントを非表示にする工夫
コンポーネントの依存関係
- Monodevelopで検索 > シーンで使用されているかを特定出来ない
エディタ拡張書く
- MonoScriptでMonobehaviourのコードを取得する
参照関係をグラフ化
Model
どういうオブジェクトか
マネージャー系オブジェクト
- オブジェクト総数が1つでコンポーネント的な参照が多い場合
- 大抵シングルトン
- 外部からのメッセージを受けて動作する方が多い
ギミック系オブジェクト
- コライダー等で自己完結するオブジェクト
- Playerへの参照があるかないかくらい
- トリガーやアクションをマネージャーに通知するタイプも居る
- ステージ系のゲームにありがち
Updateで頑張るドン
- メインオブジェクト
- 多くの参照を集めている対応でおおい
- Updateやコルーチンで自発的に動く
- コードを見れば処理が判る
そのオブジェクトがどうやって参照されるか
- 参照先の状態 (パラメータ) を注目する
- 自分で動くか管理されるかの似たく
- 被参照が一つの場合管理されている可能性が多い
- 被参照が多い場合、自分で動く可能性が多い
タグを保つ場合、FindWithTagが使われてる
- 親子関係で検索される
- 名前で検索される場合もある
対マネージャー (シングルトン)
何故参照を持つのか
- 検索のキャッシュ? …
- 判るような命名規則付けるのが一番ですね!
そのオブジェクトはどこから持って来たのか?
生成コードの検索
- シーン無いに最初から配置されているか?
- シーン内でオブジェクトを生成するコードは検索する必要がある
- Instantiate
該当のプレハブを持つシーンを探す
- LoadLevelAditiの場合、ロードするシーンを探す
- 生成物がプレハブの場合、事前にシーン内の参照情報を保持しておく
- ReferenceViewer (エディタ拡張マニアクス)
-
- UnityYAMLMergeが入って (smart merge) シーンやプレハブのマージが可能に
このシーンはどんな構造なのか
- 実行時にシーンが持つコンポーネントを知る
- オブジェクトの役割と参照関係を知る
- オブジェクトが作られる条件を知る
- コンポーネントの動くタイミングを知る
- オブジェクトの動きを把握すると大体シーンの構造が判る
UnityGUI開発至難 (FAST UI BEST PRACTICE)
- パフォーマンスの高いIF
- Unity5のフレームデバッガ
- バッチング処理
バッチ処理の基礎
- 決まった順番でメッシュがレンダリングされる
- 決まった筆が無いと描画されない (プロパティ毎に)
- ステート変更に時間がかかる
- 同じステートのメッシュは1つのバッチと捉えて、1回のdrawcallで描画される
- オブジェクトをバッチにグルーピングする処理をバッチングという
- テクスチャの変更は速い / マテリアルの変更は遅い
- マテリアルの変更
- シェーダの変更が入るのが遅い原因 (リビルドが挟まる)
- SetPassCallはこの遅い変更のことを指す
- Statuisticsを見るとバッチ数とSetPassCallが表示される
バッチング
- バッチング vs バッチングしないケース
- どう見た目が異なるかデモ
- バッチをどのように計算されているか
- 内部ルールで決まってくる
- マテリアル変更/マテリアルプロパティが共有された/要素がオーバーラップされた場合
FrameDebuger
- 何がバッチとしてまとめられるか見られる
- Window>FrameDebuger
- どのシェーダ/マテリアルプロパティ/頂点数
- Canvas単位でBatch処理を行う
- CanvasInCanvas は独自のバッチを生成
バッチ生成のルール
- 同じマテリアルである必要がある
- バッチが切れるのはテクスチャ/マテリアルが異なる/変更する場合
- エレメントが重複配置している場合はバッチが切れる場合はある
- バッチングソーティングの話
- UISystem
- (Unity5.2) Canvasからの同一平面性が壊れる場合、ソーティングを切る
- 例えばzが異なる場合バッチンググループによって表示が崩れてしまうので
マテリアルの変更は最小限に抑える
- 同じマテリアルを使う必要がある
5.2: テキストとノーマルUI要素は同一のマテリアルとして扱う
テクスチャー
- UIの中での変更を抑えよう
- spriteAtlasなど一つのテクスチャーにパッキング居ておく必要がある
- Textは動的変更なのでテクスチャは異なる = バッチングが異なる
サンプル
- 25のDrawCallが発生するシーン
- Canvasから離れている > 同じz座標へ
- Textureが異なる > SpriteAtlas > パッキングタグを付けてSpriteEditorにてパックする!!
CanvasRenderer
- スクリーン上に現れる全てのUI要素が所持する
- texture / mesh / color を保持する
- Text / Image を使うときには必ず付与される
- 変更するとバッチングのし直しが発生する
- バッチの計算し直し
- マテリアル/テクスチャーの変更
- 遅くも速くもないので出来れば避けたい
- 階層の順番が変更されたとき
- 親に対して子が追加された/子の順番が変更された
- 遅いのでなるべく起きない様にしたいよね
- 親に対して子が追加された/子の順番が変更された
- バッチの計算し直し
PixelPerfect
- スナップ処理
- 矩形と大きさを合わせる処理
- 遅いので出来るだけ使わない方にするのが良い
- オブジェクトを動かすときだけON、動かし終わったらOFFにするなど工夫出来る
- ScreenSpaceCanvasのみ機能する
Custom UI Elements
- 独自のグラフィックを作成する
独自のカスタムレイアウトを作成する
ICanvasElementという概念
- いくつかのメソッドを付与する必要なある > Rebuild
- rebuild callbacks
- Prelayout
- Layout
- PostLayout
- PreRender
- LatePreRender
- イベントのトリガー
- CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild();
- CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild();
- イベント処理のタイミング
- [FIXME] スライド公開されたら見る
- リビルドがトリガーされる例
- OnRectTransformDimensionsChange
- OnTransformParentChanged
- OnTransformChildrenChanged (for layout group)
- OnCanvasGroupChanged
- ショートカットも用意されてるよ
- 以下を継承する
- Graphic
- Selectavle
- LayoutGroup
- 以下を継承する
More Information
- セッション: ロードマップ
- 検索: フレームデバッガー
- 検索: スプライトパッカー
- コード: Unity UI bitbucket
白猫プロジェクトの裏側
開発フロー
- プロトタイプ 2-3名 1ヶ月
- アルファ版 10-13名 4ヶ月 (アクションの基礎が楽しめる完成度)
- ベータ版 15-18名 4ヶ月 (ゲームサイクルが回せる程度)
リリース
開発特徴
- 全社員にβ版の配布
- 小学生高学年レビュー
- チュートリアルが出来ているか
メモリ/パフォーマンス
基本はキャッシュ
- e.g) Instantiate
- ダメージ表記: 処理落ち
- Before: if (action.hit) { Instantiate(DamageNumber); }
- CachedObjectManeger.Instance.OreCache(obj, num); // 生成個数
- CachedObjectManager.Instance.Borrow(obj);
- AudioClipキャッシュ
- ボトルネックはLoad
- 必要になったときにキャッシュする手法
- エフェクトのキャッシュ
- 今回は断念
- ParticleSystemをActiveにしたときに別の座標に表示されることがあった
- ParticleSystem以外の制御も必要だった
- キャッシュを前提にしたルール大事
-
- マップ画面で処理落ち
- 海をキラキラさせるシェーダ
- フラグメントシェーダーで波のアニメーション計算していた (sin使用)
- バーテックスシェーダへ波の計算を移行した
- 使っていない変数に計算値をセットしてフラグメントシェーダに渡す
- シェーダーの一括変換
- 必要の無いカラー計算をしているシェーダーを一括置換
- PC用のシェーダー使用も一括置換
起動時間の拘束か
自前で用意したキャッシュシステム
- 起動時にAssetBersionListをダウンロード (path_versionNumber の形式)
- PlayerPrefに保存されているversionを比較
- 更新されていたらダウンロード
- ストレージへの書き込み
- PLayerPrefabsに新しいバージョンを入れる
- 1分から8秒に
ファイル読み込む数の問題
メモリとプラグラムサイズの最適化
不必要なdll, コードの削除
- AssetsStoreで購入した者のサンプル等は削除するかEditorフォルダに入れる
- 同様の機能を行う者が既に入っているのにdllをリンクしてしまっているケースがあった
- .jsがあると Boo.lang.dll がリンクされるので必要なければ消しておく (アセット内注意)
Stripinglevelの変更
AssetsBundleのメモリリークの繻子エイ
- 明示的にReleaseする必要がある管理方式
- 特定のOwnerがDestroyされてAssetBundleが開放されない
- Xcodeを使って調査した
- FrameDebuggerでVRAMの中身をチェックして破棄されてなければならないテクスチャを調査
今後の改題
- CharactorController使ってる
- 重い / Unity5で挙動変わってる
- UIの構築用ではない軽量な2Dアセットを探す / 作る
- キャッシュで来て大量に表示出来るエフェクトシステム
- ダメージパケットなど大量に送信する際のバッチング
リアルタイムサーバー
サーバシステム構成
- [FIXME] そのうち画像上がるだろう
リアルタイム通信
- host: 共闘で必要になるどー来データのマスターデータを持つ
- ボスデータ
- 自キャラ
- ステージギミック
- guest
- 自キャラ
- hostユーザからデータを貰う
(雑魚キャラは動きは同期していなくて生死のみ管理)
通信保証データ
クライアントサーバ注意点
- クライアントのサーバのデータ不一致
- サーバのデータをコピーしてクライアントが持つ場合不一致が生じる
- リクエスト成功、レスポンスが無い場合
- モバイルは通信環境によって接続される
- データが不一致だとサーバ側でエラーが発生する
- トークンを付与したリクエストを送る
- DBの最大値を入れてテストする
- MySQLではBigintで管理していた値をクライアントでは int (System.Int32) で管理して事故発生
- DB側をintに合わせて対応した…
Unityで音を制す
- ミドルウェアの使用事例
CRIミドルウェア
- CRI ADX2
- CRI Sofdec2
- ファイルマジックPRO
ゲームサウンドに求められるもの
- データサイズを小さく
- 圧縮と音質はトレードオフ
- 再生のCPU負荷 (同時に何本再生?)
- メモリ使用量を小さく
- 気持ちのいいサウンド
- 切り替えの滑らかさ
- ゲーム情報としてのサウンド
- ユーザ通知を判りやすく
- キャラや世界の表現
- ボイスや環境音/賑やかさ
ADX2が変えるワークフロー
圧縮コーデック
- ADX/HCA/HCA-MX(これが一番ゲーム向け/多数再生向け)
- 極端に圧縮率が劇的に変わる訳ではないので注意
イントロつきループ再生
- ループポイント付き波形の圧縮/再生に対応
事例紹介
乖離性ミリオンアーサー
- SocialGameInfo 採用事例のインタビュー
- 台詞再生時のBGM音量調整
- BGMは微妙な増減程度 (BGM聞きたいユーザ向け)
- 企画の方が音の調整していた
- オプションの音量設定
- データにカテゴリー情報を入れて、カテゴリへの音量指定
- サウンドパックファイル: 1音1パックファイルに近い > ファイルマジックによるパック
- ストーリーの音量は章毎に別途ダウンロード
- チュートリアルプレイ中に追加データのダウンロード
七つの大罪 ポケットの中の騎士団
- 5人のボイスが一斉に
- ストリームで再生しているので普通は合わせるの大変
- プログラム側で再生紙時
- BGM26曲/SE25種/ボイス1800種
ファントムオブキル
- フィールド曲とバトル曲のつなぎ込みに工夫
- 同期再生して音量をインタラクティブに変化させてる
- ボイスの圧縮 5800種 1500MB > 150MB
- キャラボイスはキャラ毎 1キャラ100ボイスぐらい
- 追加のBGMのみダウンロードしてくる
サウンド制作から組み込みまで
- 通常のワークフロー
- プログラマが頑張る
- ADX2入れた場合
- 演出設定とプラグラムの分離
- サウンド担当者が演出設定まで担当する
開発支援
- リアルタイムサウンド変化
- 実行中のアプリで直接サウンド調整
- 音ゲーの楽曲と踏めん表示のタイミング合わせを支援
- プログラムによる楽曲再生とスピーカーからの発音の遅延時間の通知
Unityを利用したスマートフォン向けゲームアプリ開発へのアプローチ方法
会社紹介
- SummerTimeStudio
- 沖縄の会社だよ / 沖縄出身のエンジニアが多いよ
- ココイチ戦争
- 開発合宿
開発スタイルと特徴
-
- コンシューマー向けの3D技術活用
- 全世界のユーザへスピーディにクオリティの高い3Dゲームの提供可
コミュニケーションン工藤開発
- 会議フォーマットの撤廃
- 問題点/疑問点をその場で解決する
- 話した内容に付いてはすぐにメモして共有
- 全員がフラットな立場で話し合う
- 一人一人が主体性を持ったものづくり
- 各プロジェクトに3名のメンバーをアサイン
小数精鋭のスポード重視
- プログラマ1名
- 3Dアーティスト1名
- 2Dアーティスト1名
- プロジェクトの規模や開発フェーズに応じて柔軟に対応
最小限のルールで柔軟に変化
- 時代の流れや環境の変化に合わせた最良を追求
開発環境の構築プロセス
サマータイムスタジオに入る前のこと
今までは自分が作ることが多かった
- 動く者を作るのは楽しんでやれる
- 自分で作れば自由に最適化出来る
- 過去のノウハウで何とか乗り切れてしまう
Unityをそのまま使ってみる
- 実感したUnityの弱み (3.x当時)
ただしプラグイン/アセットで補完
- ユーザが多く問題が解決されている
-
- Unityの中で起きている問題は対応難しい
- その機能を避ける
- 実際はUnityのバージョンアップに伴い解決が進んで行った感じ
- マルチプラットフォーム対応の効率化
- Android/iOSでの差異を九州
- アプリ内課金の実装
- アチーブメント、リーダーボードの実装
- モバイル向け広告の実装 … etc
- Unityの中で起きている問題は対応難しい
タイトル固有部分以外の効率化と安定化
STFramework紹介
- STFramework.Initialize()を呼び出す
- InputManager
- input.GetTouch() はエディタ上で動かない
- UnityRemoteで動作進化あった
- エディタ上でも気が売るに動作確認したかった
- マウス入力をタップと同じフォーマットにして返すだけ
- マルチタップはUnityRemote必須
- SceneManager
- Scene切り替えをスムーズにしたい
- Sceneの遷移や管理を自動化
- 初期化、破棄処理をコルーチンで実装
- シーン遷移におけるコールバック処理
- Scene毎にクラス定義が必要
- UIManager & UI Components
- PurchaseManager
- XMLImporter
- その他
今後の課題
- Unity5への対応・最適化
- エディタ拡張の整備
Unite2015Tokyo Day1メモ
Unite2015とは
- 年に1度のUnityのお祭りです
- 以下、自分の取ったメモ
- スライドが全公演に対して公開されるので一時的なものである認識
基調講演
http://pc.watch.impress.co.jp/docs/news/event/20150413_697587.html
UnityProfessionalEdition
- チームラインセンス
- パフォーマンスの速報 (PreView)
- UnityAssetsStore Level11 Deals
- AssetsStoreをとても得に使える仕組み
- ロイヤリティ無しで使える
UnityPersonalEdition
- Unity5エンジンの全ての機能を使えるようになったよ
- 従来のPro版で制限されてた機能含む
- ロイヤリティ無しで使えるよ
- 100万の利用者
IncredisbleGraphics
- 物理ベースレンダリング
- グローバルイルミネーション
- サンプル動画(3人/短期間)
REPUBLIQUE
- Unity5で物理ベースシェーダーによりリアルな質感を表現
- これから作るゲームをもっと美しくなる
- 感情を与えていい体験をしてもらう
無料でプロダクト公開!
- https://www.assetstore.unity3d.com/jp/#!/content/34352
- 大前さん「人の人生をダウンロードしている気がする」
Lighting
- Mechanim
- Entry -> Exit が見える様になって判りやすいよね
- AudioMixer
Unity5 feature
- 64bit版のエディタ対応
- PhysX 3.3 upgrade
- animationシステムの刷新
- AudioTools
マルチプラットフォーム対応
- 6つのプラットフォーム対応大変だったよ、更にやってみよう
- 21のプラットフォームを対応
- 1からの作業だった
- WebGLサポート
- IL2CPP
- 全てのプラットフォームに対応させたい!!
Massive R&D
- 300人あまりの開発者が関わってる
- core / cloud / longer / R&D team
- new ニンテンドー3DS 今年夏β : ブースでも触れるよ!!
VR (Oculus/パルマーさん)
- GearVR で課金プラットフォームのリリース
- VRはどんどん広がって行くよ!!
- Unity 5.1 のインテグレーションデモ
- 大前さん「こんなところに偶然DK2があったので」
- VertualReality対応チェック入れるだけで視線追従
- エディタとOculus側との表示が分かれる
クラウドサービス
- パフォーマンスレポーティング
- アナリティクス
- CloudBuild
- Buildに数分〜数10分掛かる
- CloudBuild大絶賛 280,000builded 15万時間の節約
- 無償版もある!! UnityProに内包されている Pro $25〜
- UnityAds
- 1500Game / TOPGames (iOS) 4/10
- Work with CyberAgent && Gee
ここが変わる! Unity5のスマホ開発 〜アセットバンドル、ブルド、プラグイン〜
AssetBundle
今までの問題点
- 複雑
- ビルド時間が長い -どれをビルドすればいいのか不明でフルビルド
- 面倒な依存関係
- バージョン毎の互換性が無い
解決方針
- シンプル (ビルド/ランタイム)
- 追加ビルド (ビルドを最小限にとどめる)
- 依存性はUnityが解決する (ビルドして使うだけ)
- 互換性を保持する
- [注意] 混ぜるな危険 (4と5)
新しいAssetBundleビルド
AssetとAssetBundle間を結びつける
- インスペクタから各Assetsに対してnameを記載する
- ビルドするスクリプトを呼ぶ
-
- 小文字のみ/同盟禁止/パス構成持てる(/)
Buildスクリプト
- BuildAssetBundles(出力パス, BuildAssetBundleOption, 出力ターゲット)
Options
- IgnoreTypeTreeChanges (NEW!!)
- タイプツリーが変わっても虫 = ソースコード変更しても変化したと見なされない
- DisableWriteTypeTree
- タイプツリー遺体をサイズ削減用とで消す
- IgnoreTypeTreeChanges (NEW!!)
互換性
- 5.1以降の互換性は保持される (5.0はバグで互換性持たない)
Manifestファイル
- (Single) Manifestファイル -> 親玉/依存関係を解決出来る/ランタイムに読んで依存関係を解消しようとする
- .manifestファイル -> インクリメンタルビルドにだけ関係する
- CRC / アセット名 / 依存関係 / Hash / ClassTypes
Variant
- ランタイム時に読み込むアセットバンドルを変更出来る
- フォルダ/シーンなどに適応出来る
- AssetBundle名の隣に指定する
- LoadVariantsでsd/hdのどちらを呼び出すか指定するような感じ
サンプル
サンプルプロジェクトを使おう
-
- AssetBundleManager.cs (マネージャークラス)
- 基本ロードの仕組み : AB名を受け取ってLoadAssetBundleが走りWWW発行してキューがリクエストを返す -> GetAsset
- 依存性の干渉: LoadAssetBundle内部でAB名を貰ってinitでAssetBundleManifestを読み、依存ABをロード
- エディタシミュレーション: GetAssetPasssFromAssetBundleAndAssetName
- Variants を使った切り替え: Variantに関する名前を呼び出して、一致する名前を呼び、最後の名前を付け替える (sd->hd)
- BaseLoader.cs (基本ローダー)
- デモ
- https://github.com/makoto-unity/NewAssetBundleSample
- ジュエルセイバーの画像素材を動的に呼び出す
- cacheしているので読み込めば早い
- AssetBundleManager.cs (マネージャークラス)
ビルド
マルチプロセスビルドHack
- 複数のプロジェクトを用意してビルドすると早いのでは!?
- シンボリックリンクを使うよ Library/ProjectSettingsをリンクする
- Unity側はバッチを作れば良いよ
- [注意] 未来永劫使えるとも限らない
- [注意] UnityのAssetBundleビルドがマルチスレッド化すればいいのでは…
IL2CPP
-
- Xcodeプロジェクトを直接編集できる
- http://bit.ly/1CSDBYo
Plugin
Pluginの設定の変更
NativeCodePlugin
- Unityからネイティブの関数を呼び、CからObjCを呼び出し…
- NativeCodePlugin: 直接ObjCを直接呼び出す
- [注意] 引数が使えない…
Unityではじめる徹底企画講座!を考える
- 大野功二さん
- 3Dゲームを面白くする技術
- unityではじめる3Dゲーム作り
こんな経験はありますか?
- 凄い企画思いついた
- Unityあるよ!作ろう
- あれ作れない、何か違う、思った様に操作出来ない
- ゲームが完成しない、諦める 「こんなはずじゃなかった!!」
企画を完成させられない問題
プランニングの問題
- 「企画を完成させられるかどうか」「企画は完成させられているか」
- 企画 ≠ アイデア
- 企画 ≠ 思いつき
- 企画はゲームを作る為の「出発点」と「ゴール地点」および開発の方向性を指し示すもの
- 「企画を完成させられるかどうか」「企画は完成させられているか」
企画の出発点 = ハイコンセプト/コアアイデア
- いつ/どこで/誰が
- どんな遊び方で/どんな体験をさせて
- どんな感情を抱かせて
- どうおもしろがらせるのか
企画のゴール地点
- ルック & フィール (第一印象) が大事
- そのゲームをプレイすることでプレイヤーの心や生活や人生にどのような影響を与えるか
企画の方向性
- おおまかなゲームデザイン (ルール/システム/操作性)
- 1回のプレイ時間 / ボリューム
時代とともに変わる企画手法 (答えはない…)
- 新しいシステムを作れば売れる時代とか
- ゲームを出せば売れるからとにかくはよな時代とか
- ターゲットユーザがこまくて状況にあわせて企画の手法そのものがちがう
- お笑いと同じ!!!!!!
ゲームの企画を料理に置き換えてみる
- [ミッション] 彼女/彼氏を家に招待することが出来たので、料理でもてなそう!
- 勝利条件(目的)を考える
- 方法は条件による
- 相手の好きな者を作る (自分が嫌いな場合は自分が楽しくなれないので好きになる努力が必要)
- 自分の好きな物を相手にも好きなってもらう (相手がそれを好きになれる要素があることが必要)
- 自分も相手も、見たことの無い者を作る
- 自分が好きなものは彼女も好きに違いない!!という発想だけじゃ弱い
- おもてなし
- 相手をイメージすることが大事
- すなわちリサーチ… 「どんな食べ物が好きですか? いつ? 時間は? どんな時に心の距離を縮めてくれるか?
調理とゲーム要素は似ている
料理の失敗例
- ゲーム機で実現出来ないほどの量の仕様を一度に並べようとしていませんか?
- ちょうど良い量を出していますか?
- ゲームが提供するアクションの順番は適切ですか?
- ゲームで扱うネタは新s年ですか?
- ゲームで表現したいことに対して、そのインターフェイスは適切ですか?
プレイヤーのどんな顔が見たいですか?
- 人の顔を想像するには現実の経験値が必要
- ゲーム以外の情報や引き出しを作ることが大事
仕様の問題点
- 仕様: ゲームをXXXを実現する為にアイデアを設計やメカニクスレベルまで分解したもの
ゲームのおもしろさを引き出す要素は以下の組み合わせとバランス
- アクション: 反射神経
- パズル: 正しい順番や意味を見つける
- リソース: 制限/時間
- 官能性: 操作するだけで気持ちがいい
- 運:プレイヤーが介入出来ない要素
仕様作成
- 新しい仕様を作る (センス/挑戦した回数)
- まねる (知識の数/まねた数)
仕様の基本
- ゲームを数多く見てどう読み解くかを研究する
- ゲームデザイナは実現したいゲームに対して、必要なパーツ(基礎仕様)をプログラマに渡して、一緒に最終仕様を作る
実装の問題
挫折原因
ゲームエンジンには特性がある
- Unityの特性を作ろう
- 頑張ればどんなゲームでも作れます!!
- けど作りやすいゲームや作るのに時間がかかるゲームは当然あるよ
短時間で作りやすいゲーム
- 複雑な辺り判定や物理演算が必要なゲーム
- 単純なアニメーションのゲーム
初めて作ると時間がかかるゲーム
- 複雑な当たりや物理演算の結果が勝敗を決めるゲーム
- 複雑なアニメーションのゲーム
- 理由
- Physicsを使いこなせていない
- 高校レベルの数学と物理の知識が必要
- 3D:PhysX / 2D:Box2Dと異なる
- e.g) 四角いcoliderだと段差に引っかかるが、足下に丸いcolider入れておくと上れるよ
- Mecanimを使いこなせていない
- アニメーションの基礎知識
- Unity5ではStateMachineBehaviors / AutoMachineAuthoring など
- 企画をUnity (の特性) に寄せる / Unityを知り尽くして頑張って実装する
- Physicsを使いこなせていない
作りやすいゲームの共通点
- PhysicsやMecanimのこんポーメントやプロパティ編集だけで実装可能
- ゲームのノウハウの公開の有無
まずはアセットストアのコンプリートプロジェクトのテンプレートを参考に仕様
- CompletePhysicsPlatformKit
- こういうことが出来るよ!出来ないよ!の説明
- アドベンチャー: 宴
- 2Dゲーム:ninja slasherX
- CompletePhysicsPlatformKit
調整の問題
- ゲームの面白さは調整で決まる
- 調整は一人では出来ないのでテストプレイヤーこそが重要な鍵
- ちゃぶ台返し -> 何回できるかが鍵
- 開発中は未来のプレイヤーの顔を想像しよう!
Unity5 グラフィクス使いこないガイド
- 基礎以外はWorkshopで
- Workshopの内容も後日配信するよ!
Lightingの新機能
AmbientLightの強化
- 3つの方式から選択出来る様になったよ
- Window -> Lighting
- Skybox
- Skyboxに該当している空が映り込む
- Gradient
- グラデーション/色を指定する
SkyBox
- ProceduralSkyBox
- パラメータから空を作れる!
- SunSize: 太陽の大きさ変更
- AtompsheteThicknes: 層の厚さ
- 太陽の光源を設定すると連動する (光源の角度に合わせて太陽が現れる)
- パラメータから空を作れる!
- CubemapSkyBox
- パノラマ画像から作れる!(hdri とかで検索するといっぱい出てくる)
- .exr / .hdr という形式のファイルを読み込める様になる
- cubemapに指定してapplyする
- skybox -> cubemap に指定する
- 物体の表面に影響
- 光源が柔らかいのでDirectionalLight1個追加して太陽を追加すると良い
- ProceduralSkyBox
影
- CAST SHADOWS OPTION
- MwshRender -> CastShadows
- 両面の影 (TwoSided)
- Shadows Only (影のみが落ちて見た目は消える)
- MwshRender -> CastShadows
- PCF SOFT SHADOW
- 綺麗になっただけでなくパフォーマンスは上がっている
- モバイルでは使えないので注意
- BAKED SOFT SHADOW
- 半影の開き具合を調整出来る様になった
- SHADOW BIAS
- NORMAL BIAS方式を光源で指定する
- 縮めるようなバイアスを掛けてアーティファクト(ノイズ)を削除出来る
- 複雑なモデルでは影に隙間が出来るのでBIASとの使い分けが大事
- CAST SHADOWS OPTION
RealtimeGIの基礎 (グローバルイルミネーション)
- 間接光の表現を使うことが可能なもの (IndirectLight)
Lighting -> GeneralGI
- 物体を動かしたり / 光源が動いたりしても反映される
- (Unity開けない) 「死ぬかと思った…」
- (Defuse反射する) 固形物のものにstaticフラグを建てて当てる必要がある
- staticオブジェクトに関しては自動で間接光が伝搬される
- 間接照明の効果が現れる
- 動き回るオブジェクトには勝手にGIは有効にならない
- LightProbeGroupを指定してあげる必要がある
- エリア内の動作を計算してくれる
- Supecularの入ったオブジェクトに対しては ReflectionProbeを指定する必要がある
- 意図せず発行していたらSkybox映り込んでいるな….
DirectionalMode
- NonDirectional: 追加情報無し
- Directional: どの方向から代表的な光が入り込んでくるかを近似で定める
- DirectionalSpecular: 直接光/間接光の持つ情報を持たせる
- [注意] 計算量やデータ量が増える / 代表的な光源一つだけを考慮しているので複数の光は危うい表現になりがち
- RefrectionProbeを指定してあげると解決する
RefrecrionProbe
- Probe同士のつなぎ
- MeshRendererのblendOption
- 反射の更に反射
- 映しているものは黒く表示されてしまう
- RefrectionBounces: 反射回数を指定出来る
- Bakeするときの処理が重くなるのでまあ2くらいまでは…
- リアルタイム反射
- 動いている者に関してはRefrecrionProbeには映り込まない
- EveryFrameにするとリアルタイムで映り込む
- InvisibleFaces: フレームレートを落とす(1/10?)により処理を軽くする
- リアルタイムだと画質も落ちるので注意
- BoxProjection
- ある決められた範囲に映り込ませるよ
- 処理負荷も重くてモバイルでは使えないよx
- Probe同士のつなぎ
Render Massive Amount of Objects in Unity
(ちょっとシェーダのこと全然知らない自分だったので以下用語に不備あるかも / スライド待ち)
@i_saint
本公園の目指すところ
- Unityでいろんなトリックを用いて1万以上のオブジェクトを効率的に描画 & 更新する
- 検証はPC上 PS4/XBoxOne程度
レンダリング
前提
- 1つ1つGameObject化する: 現実的ではない
- GameObjectなしにMeshを描く手段が必要
Graphics.DrawMesh
疑似インスタンシング
- 1つのMeshに多数のモデルを格納する手法
- 元の頂点データを繰り返す
- 何番目のモデル化という情報を付与
- 65,000 / モデルの超点数を1回のdrawcallで描ける限界
- Cubeは24両点なので 65,000 / 24 = 2708個
- 各インスタンスの情報をGPUに送り、頂点シェーダモデル変更
- TRS行列等
- 必要なbatchの数だけMaterialを用意する
- 各MaterialにインスタンスIDの開始番号を付与する
- e.g) Cubeを10,000個か来たい場合、 10000 / 2708 = 4つ
- 必要個数を超えたモデルは頂点シェーダで画面に出ない様に工夫
- Materialに今Activeなのはいくつというものを保持する
- 1個でも描きたい場合は格納されているモデルの数分の処理する
- GPUにインスタンス情報を送る
ハードウェアインスタンシング
- 1回のdrawcallで1つのモデルを複数各機能
- 頂点シェーダの入力にインスタンス別のデータが加わる (TRS行列等を輪sつ)
Unity: Graphics.DrawProducedural()
Unity5.1でCommandBuffer/DrawProcedure() が追加
- render queueに載せることが出来る
- G-Bufferの精製/ ライティングしないオブジェクトには必要十分
Graphics.DrawProcedureIndirect()
- 描画するインスタンス数を指定出来る
update
- オブジェクトをUnity上でどう扱い/どう更新するか
- オブジェクト群を管理するマネージャをGameObjectとしてもつ
- Objectのデータはstructの配列として持つ
- 原始的だけど高速
UnityのColliderとのインタラクション等は独自に実装
ネイティブコード (=プラグイン化)
GPGOU / ComputeShader
C#でがんばる
- struct配列で持つしかない
- class参照しない書き方にする
- class参照は結構な負担
- 大きなデータのコプーは避ける
- ThreadGroup.QuueueUserWorkItem() による並列化
- いわゆるタスク並列
- [注意] Unityの機能の大部分はメインスレッドから触れない
- IL2CPPにより数値計算の高速が見込める (将来的には…)
- 最新の.NETでもある程度の改善が行われている
結論
- 現状大量描画は疑似インスタンシングが有力
- ハードウェアインスタンシングはUnity5.1以降にご期待ください
- アップデート処理は可能な限りC#は避けて自力で頑張る
Unity For Newニンテンドー3DS
- Newニンテンドー3DSをUnity5ベースでサポート
- Newニンテンドー3DSの登録Developerであれば利用可能
- サポートを求める声は貰っていた
- 8ヶ月くらい調査した
- 市場のiOS/Androidのアプリをいくつか選んで移植可能性を検討
- 8割以上のゲームはそのまま移植して動作するのでは!
旧3DSは?
- 議寿的サポートは可能
- メモリ/CPUの両面から制限がある
- 選んだタイトルのうち3割くらいが可能性あった
リリースは?
- 2015年夏: 認定堂に提出可能なβ版をリリース
調査研究と考え方
- 市場で現在出ているUnity利用のゲームを調査
- 主にアプリのメモリ/CPU使用率
- ハードのパフォーマンスを比較検討
- ユニティ・ゲームス・じゃお案で扱っているゲーム等は実際に移植してみてデータ取る
- 画面にキューブ出す/テクスチャ出す/スクリプト/物理エンジン…
- サンプルプロジェクトで検証する
- 3タイトルくらいの移植のチャレンジ
Wind-upKnight2 ねじ巻きナイト2
- RobotInvaderの傑作アクションゲーム
- WiiU版をユニティ・ゲームス・ジャパンで担当
ゲーム移植開発した話
3Dへのゲーム移植時の課題
- メモリ容量が他のプラットフォームより少ない
- シェーダ制限
- 画面が2つ / 立体視対応で3回の描写
最初にやったこと
- オリジナルのゲームはUnity4.3 -> 5.1にアップグレード
- 問題なく動作した
テクスチャ最適化と調整
スマホとのメモリの使用量比較
- 大体50-60%くらいのメモリ使用量に、4割以下になるものも
Unityのスクリプト実行速度
エンジンの最適化/描画
エンジンの指摘か/Z-Buffer更新On/Offee
- Z-Bufferの必要ないゲームでは更新をオフにする設定を追加
- メモリ/GPUバンドに作用
ねじまきナイト2
- 2画面対応
- 3画面(上両目/下)を描画して60fps維持
シェーダーの実装
ピクセルシェーダー対応
- ShaderLabを使った一般的な解決方法をチャレンジ中
- 結構大変なので最初は別なやり方で対応するかも
スクリプト対応
オーディオサポート
実機デモ
- カメラ: 上画面と下画面選択出来るような感じ
- UpperLCD / LowerLCD
- 任天堂のソフト開発Kitの一部の機能を使用出来る
- buildの時間は長い
- ジャイロもちゃんと動作しているよ
今後の改題
エンジンの最適化
2Dモードの改善
まとめ
- Newニンテンドー3DSをサポートするUnityをリリースするよ
- ミドルレンジのスマートフォンをターゲットにするようなゲームならサポートは一考の価値あり
- 2015夏にβ版出すよ
- UGJが選考してたいとリリースすることでエンジンの完成度を高めるよ
質疑応答
- NativePluginのサポート予定ある?
- ネットワークは繋がる?
- New3DSの開発ライセンス以外の枠で開発できる?
- New3DS自体の開発が必要なので基本的にライセンスは必須
- ねじまきナイト2でのbuild時間
- ビルドから転送まで5分程度
Unity 5オーディオ新機能の真髄
AudioClip
データと分離したよ
- AudioClip側にはメタデータを持つことでサウンドのスケジュールを組むことが出来る
- メモリの削減
Loadの仕方も使用出来る
- PreloadAudioDataのチェックを外すとオンデマンドで動的にロード出来る
- AudioClip.LoadAuioData(); / AudioClip.UnLoadAudioData
- Load in backgroundにチェックすることで非同期ロードも行ける
Audioのメモリの使用量の改善
Platform毎のoverrideな設定
- コーデック/サンプルレート等の設定
圧縮形式
- 複数選択/編集に対応
AudioSource
3Dセッティングの設定を外した
- SpatialBlend で2D/3Dのハイブリッドが可能
StereoPanの設定を良いにアクセス出来る様にした
ReverbZoneのパラメータを追加
- 2Dのサウンドでも動作する
- ナレーションボイスにリバーブを付けるなど
距離に応じてパラメータの設定が出来る
pauseの機能
- AudioSource.Pause() / UnPause()
Audioプロファイラ
- どのAudioClipが再生されているか判る
AudioMixier
デモファイル
階層的なmixierになっている
- Player/Weapon/Amibience/Weather…etc などのAudipGroup
インスペクタでステータスを変更出来る
リアルタイムでプレイ中に変更出来る
- Edit in Play Mode をクリックするとゲーム中にステータス変更が出来る
- snapshotの変更の仕方
- AudipMixierSnapshot snapshot; snapshot.TrandformTo(1.0f); // sec
- スクリプトからステータスの操作が可能
- [DEMO] Unityでマスタリングしてる
- [DEMO] sliderによるsnapshotの遷移 / pauseボタンによるlowpassの適応
Horizontal rescheduling
- AudioSource.PlayScheduled();
- 再生タイミングのスケジューリング
- ピアノロールみたいなデモ
NativePlugin
- かなりの種類のPluginを紹介された
- デモファイル