開発チームの自発的な課題解決のためにオープンスペースをやってみた

こんにちは。

株式会社 Synamon でエンジニアをしております、渡辺匡城(@mochi_neko_7)と申します。

今回は、社内の開発チームで自発的な課題の解決や改善ができないかという試みとしてオープンスペースをやってみた話を紹介します。

振り返りも兼ねて、実施の経緯からお話ししていきます。

オープンスペースとは

オープンスペース、あるいは OST(Open Space Technology)とは、参加者が自発的に対話するためのワークショップの1つです。

www.ogis-ri.co.jp

特徴としては以下が挙げられます。

  • 参加者がテーマを出す
  • 参加者はセッションを自由に移動してよい
  • 最後にまとめとその共有をする

アジャイル開発界隈では割とメジャーで、Scrum Masters Night! や Engineering Manager Meetup などのイベントでも行われています。

smn.connpass.com

engineering-manager-meetup.connpass.com

背景

少し前から開発チームにおいて、週一で自由に相談や課題解決をする場を作ってみていました。

しかし開発チーム全体では16人程度、有志で集まっても10人以上集まり、やや人数が多いです。

そうなるとどうしても話を聞いている時間が多く、せっかく集まってもらったのに有意義に時間を使ってもらえていない、という課題感がありました。

やり方やそもそもの定例の意義を考え直していたのですが、その時たまたま読んでいた LeSS(Large Scale Scrum)の書籍でオープンスペースが紹介されていました。

www.amazon.co.jp

そこでちょうど使えそうかなということで、試しにやってみることになりました。

もう1つ背景として、コロナの影響で弊社が完全リモートワークになっていた頃に、コミュニケーション活性化の目的で雑談オープンスペースを何度かやっていました。

ですのでやってみる分には抵抗が少ないかなという期待がありました。

仮説

実施するにあたって立てた仮説は以下になります。

  • 課題解決や改善が自発的に生まれるのでは
  • セッションが小規模で平行して走ることで、コミュニケーションの密度が上がるのでは
  • 定例開催することで、不安や悩みを早めに解消できるのでは

流れと準備

基本的な流れは一般的なものを踏襲しました。

時間は1時間で、以下のようなタイムスケジュールを想定していました。

  1. オープニング(10分)
  2. 参加者からテーマを募る(3分)
  3. セッションの時間と場所を決める(2分)
  4. セッションを行う(30分)
  5. まとめと共有(15分)

事前告知をして、テーマは事前に2つ挙げてもらい、もう2つはその場で出してもらいました。

セッション中の会話は Discord、メモや議事録は Miro を用いました。

discord.com

miro.com

Miro ではこんな感じのセットアップをして、後からセッションの内容がどうだったのか見返せるように工夫してみました。

f:id:mochinekos:20200821160817p:plain
MiroOSTTemplate

付箋の色で使い分けをしています。

  • オレンジ:テーマ
  • 緑:まとめとネクストアクション
  • 濃い黄色:Discord のルーム
  • 薄い黄色:メモ

キャンバス全体を直線で4等分にして中心にテーマなどを置くことで、それ以外のスペースを自由に使えるようにしています。

実際にやってみたらどうなったか

出たテーマ

ざっくり以下のような内容でセッションが盛り上がりました。

  • 読書会をどうやってやるか
  • プロダクトの開発体制の話
  • とある機能の実装方法の相談
  • 最近の注力開発の状況

内容は意外と広く挙がってきました。

まとめやネクストアクションを考えるのはやはりポイントですね。

セッション

テーマを挙げてもらったあとに、セッションの配置をしました。

しかしその際複数のテーマで、テーマを話したいメンバーとテーマに関して相談したいメンバーが被ってしまいました。

そこでセッションを同時に4つ行うのではなく、2つを2回に分けて行うことに急遽変更しました。

そうしてみるとタイムボックスの意識が強くなるので、より会話の密度が上がった印象を受けました。

これは想定していない良い効果でした。

タイムマネジメント

まず Discord に人が集まるまで少し時間がかかります。

それは想定していたのですが、テーマ集めと割り振りに時間がかかりました。

さらにセッションを2回に分けることとなり、時間設定を組みなおした結果、全体の時間が少し超過してしまいました。

タイムマネジメントが甘かったのは反省点でした。

仮説の検証

実施前の仮説の検証結果は以下になります。

  • 課題解決や改善が自発的に生まれるのでは
    • 〇:自発的にテーマが上がってきた
    • △:様々なメンバーからテーマがたくさん挙がってくるともっと良い
    • ✕:実際に解決や改善の効果が出るかトラッキングしたい
  • セッションが小規模で平行して走ることで、コミュニケーションの密度が上がるのでは
    • 〇:タイムボックスの意識が生まれた
    • 〇:全体で1セッションより会話が増え、集中力も上がった
  • 定例開催することで、不安や悩みを早めに解消できるのでは
    • ✕:まだ1回目、もう何度か実施してみて検証したい

おわりに

実際にやってみて、チームのコミュニケーションの1つとしては有効だと実感しました。

ですのでもう何度か実施してみて検証を続けていくことにしました。

結果と反省を踏まえて、進め方自体も改善していきます。

  • タイムテーブルを組みなおすか、パターンを作っておく
  • 開始時に前回実施分の振り返りを簡単に行う

オープンスペースはソフトウェア開発以外にも十分有用な手法ですし、実施するのにはそこまで手間はかかりませんので、チームの自発的な課題解決や改善のきっかけとして試しにやってみてはいかがでしょうか。

おまけ

弊社では「XRが当たり前の世界をつくる」というミッションを一緒に実現していきたいエンジニア、エンジニアリング・マネージャーの各職種の募集を強化しています。

XR 技術への強い関心のある方、スタートアップの環境で成長していきたい方、自己組織的な開発チームづくりに興味のある方などいらっしゃいましたら、ぜひエントリーしてください。

www.wantedly.com

www.wantedly.com

www.wantedly.com

Unityで対象オブジェクトに(ほぼ)手を入れずに使えるアウトラインエフェクトを作った

f:id:Sokuhatiku:20200720225722p:plain
空中ペンで書いた文字に表示されるアウトライン

はじめに

NEUTRANS BIZのベース機能に、Grabというものがあります。挙動は名前の通りで、レーザーポインターを当てた、もしくは直接触っているアイテムを掴んで、移動させることが出来ます。

ある時、アイテムを掴める状態を分かりやすくしてほしいというオーダーがあった為、それを実現するために、掴めるアイテムに対してアウトラインを表示する仕組みを作成しました。

この機能はすでに最新版のNEUTRANS BIZに搭載されています。

手法の検討

アウトラインの実現方法としては、メッシュを法線方向に膨らませて反転させるものが一般的です。これはお手軽ですが、いくつかの欠点があります。

  • ハードエッジの表現が苦手
  • シェーダーに手を入れる、もしくはモデルにマテリアルを追加する必要がある。

f:id:Sokuhatiku:20200720210109p:plain
メッシュ押し出し反転によるアウトライン

上画像をよくみるとアウトラインが途切れてしまっています。丸みを帯びた物体であれば問題にはなりにくいのですが、このような金属質の物体はエッジを利かせているものが多く、その場合単純に頂点を押し出しただけのアウトラインは破綻してしまいます。

以上の欠点を解消する為に、ComputeShaderとImageEffectを利用して、対象オブジェクトのレイヤー変更のみでアウトラインのON/OFFを切替できる仕組みを開発しました。

f:id:Sokuhatiku:20200720211303g:plain
レーザーポインターを当てるとレイヤーが切り替わる

この方式の利点は以下の通りです

  • オブジェクトのメッシュ特性やマテリアルに表示が左右されない
  • 遠くのオブジェクトであっても太さが変わらない為視認性が高い
  • ハードエッジに強い

逆に欠点は以下の通りです

  • レンダリング用にレイヤーを使うため、物理コンポーネントとは別オブジェクトに分ける必要がある
  • イメージエフェクトと追加カメラを利用している為、それなりに重い

仕組み

動作のイメージは以下のようになります。

  1. アウトラインを表示させたいオブジェクトをアウトラインレイヤーに移動する。
  2. アウトラインレイヤーのみ映すカメラ(シルエットカメラ)でリファレンス画像をレンダリングする。
  3. ComputeShaderでリファレンス画像からエッジ検出してアウトラインを生成する。
  4. 通常のレンダリング結果とアウトラインを合成する。

f:id:Sokuhatiku:20200720223840p:plain

工夫してみた点

Depthの考慮

前述の仕組みによりアウトラインの表示は可能になりました。ただしこの状態では、アウトラインを出すオブジェクトが他のオブジェクトの背後にあってもアウトラインが出てしまいます。

f:id:Sokuhatiku:20200720191931p:plain
キューブを貫通してアウトラインが見えてしまう

この違和感はVR中の酔いの原因になりかねない為、対策を行います。

SetReplacementShaderを利用してシルエットカメラのレンダリングに利用するシェーダーを変更し、深度情報をカラーで出力してもらうようにしました。*1

// シルエットカメラにDepth出力用シェーダーをセットする
silhouetteCamera.SetReplacementShader(settings.DepthShader, "RenderType");
// 通常カメラの深度情報は以下のコードで取得可能
var eyeDepth = Shader.GetGlobalTexture("_CameraDepthTexture");

そしてComputeShader内で、通常カメラのレンダリング結果の深度情報と比較を行い、アウトラインがオブジェクトに隠れているかどうかの判断を行うようにしました。

    float sumDepth = 0;
    float avaiableCount = 0;

    for (int i = -outlineSize; i <= outlineSize; i++)
    {
        for (int j = -outlineSize; j <= outlineSize; j++)
        {
            int pos = selfpos + i + (j * threadGroupSize_x);
            float depth = silhouetteDepth[pos];
            float avariable = depth > 0;

            sumDepth += depth * avariable;
            avaiableCount += avariable;
        }
    }

    float ztest = ((sumDepth / avaiableCount) - SourceDepth[did]) > 0;

f:id:Sokuhatiku:20200720191822p:plain

これで上手く遮蔽出来ます。 ※デバッグ用テクスチャの色は強調しています。

負荷削減

ピクセル情報の参照はGPUの中で(比較的)重い処理です。 単純に周囲のピクセルを参照すると、アウトラインの厚みによってピクセル当たりの参照ピクセル数が(2n+1)^ 2で増加します。単純計算すると3ピクセルの厚みのアウトラインを作る為には\{(2 * 3) + 1\}^ 2=49ピクセル参照する必要があります。*2

f:id:Sokuhatiku:20200721125835p:plain
3pxのアウトラインを出すためには各ピクセルが7x7の範囲を認識する必要がある

コンピュートシェーダーには、同じスレッドグループ内のスレッド同士で使える共有メモリが存在します。 これを利用する事で、隣のスレッドが取得したピクセル情報を使いまわせるため、結果としてピクセル当たりの参照回数を抑えることが出来ます。

ただし、シェアードメモリのサイズ及びスレッドグループの大きさには制限があり、一般的なFullHDの画像すべてのピクセルをシェアードメモリに載せることは出来ない為、多少工夫して何とかします。

// 例えばこのようなシェアードメモリを定義する
groupshared float silhouettePixelBuffer[ThreadGroupSize_X * ThreadGroupSize_Y* 4];
void DoOutline(uint2 gtid : SV_GroupThreadID, uint2 gid : SV_GroupID)
{
    // 担当アドレスを計算
    int2 sharedID = gtid * 2;
    int2 bufferID = int2(gtid.x * ThreadGroupSize_X - ThreadGroupSize_X * 0.5 + sharedID.x,
                        gid.y * ThreadGroupSize_Y - ThreadGroupSize_Y * 0.5 + sharedID.y);

    // 担当データを書き込む
    silhouettePixelBuffer[ThreadGroupSize_X * 2 * sharedID.y + sharedID.x] = Silhouette[bufferID];
    silhouettePixelBuffer[ThreadGroupSize_X * 2 * (sharedID.y + 1) + sharedID.x] = Silhouette[bufferID + int2(0, 1)];
    silhouettePixelBuffer[ThreadGroupSize_X * 2 * sharedID.y + (sharedID.x + 1)] = Silhouette[bufferID + int2(1, 0)];
    silhouettePixelBuffer[ThreadGroupSize_X * 2 * (sharedID.y + 1) + (sharedID.x + 1)] = Silhouette[bufferID + int2(1, 1)];

    // グループ内全てのスレッドで上の処理が終わるのを待つ
    GroupMemoryBarrierWithGroupSync();

    // この後はsilhouettePixelBufferを参照する処理を組む

結果はこちらです。 f:id:Sokuhatiku:20200720203503p:plain

思いっきり負荷をかけて改善3msという程度だったので、やらなくても良かったかもしれません……。

最後に

f:id:Sokuhatiku:20200721140442g:plain
VRかつ複雑な形状でも綺麗にアウトラインが出るところがお気に入り

以上の仕組みは、実は2017年頃に作成したものです。この度テックブログの記事としてちょうどいい題材ではないかと持ち掛けられたため、引っ張り出してきて記事にしました。

当時はほぼ新入社員だったのですが、自由にコードを書かせてもらって今に至ります。

Synamonでは現在仲間を絶賛採用中です。ご興味のある方は是非一度お話ししましょう!

herp.careers

*1:このシェーダー差し替え処理のトレードオフとして、GeometryShader等シェーダー内で頂点を弄る処理があった場合、ケアしなければ破綻するようになってしまいますが……。

*2:実際は円形に描画する為、角部分の参照は減らせます。

開発チームの生産性・健全性を可視化できるgilotを触ってみた

こんにちは。

株式会社 Synamon でエンジニアをしております、渡辺匡城(@mochi_neko_7)と申します。

今回はソフトウェアの開発チームの生産性・健全性を可視化できる gilot というツールを触ってみたのでレポートします。

ツールの作者の広木大地さん(@hiroki_daichi)は エンジニアリング組織論への招待 の著者であり、EM.FM などでも開発組織の話を発信されています。

そんな広木さんがツールを作成したと目にしたので、実際に触ってみて、弊社のプロダクトに適用してみました。

日本語での使い方やグラフ、指標の解説は Qiita にもまとめられていますので、こちらも参照ください。

qiita.com

上記の内容の補足として、環境のセットアップや Windows 環境ではまったところ、弊社のプロダクトの簡単な解析結果の紹介をします。

gilot

gilot(ジロー)は Git のログをもとに開発チームの生産性や健全性を可視化できるツールです。

GitHub のリポジトリはこちらになります。

github.com

環境セットアップ

簡単にですが、gilot の利用に必要な環境のセットアップを補足します。

なお、今回の検証に使用した環境は以下になります。

  • OS:Windows10
  • gilot:0.2.3

Python

gilot は Python のプログラムのため、実行には Python の環境が必要です。 環境自体はいくつかあり何でも構いませんが、公式はこちらです。

www.Python.org

環境変数のパスを通すのを忘れないでください。

Git

Git のログ解析をするので、Git Client の環境も必要になります。

Git を使っているリポジトリが解析対象になるので、基本的には既にセットアップされているはずです。

GUI 系の Git ツールで内部に Git Client をインストールしている場合にはその環境変数のパスを通すか、新しく公式からインストールしてしまっても構いません。

Git-scm.com

gilot

gilot のインストールは、コンソールで以下のコマンドを入力して行います。

$ pip install gilot

解析方法

GitHubQiita にも紹介がありますが、ここでも簡単に紹介します。

log

まず log コマンドを使って Git のログを解析します。

$ gilot log [repository] -o [log].csv
  • [repository] には解析対象のリポジトリのディレクトリを指定してください。

  • [log] には解析結果の出力先を指定してください。

直接グラフなどを出力するコマンドもありますが、解析にはやや時間がかかりますので、一度ファイルに書き出しておくことをお勧めします。

デフォルトでは master ブランチを対象に解析します。 これを変更したい場合には、--branch [branch_name] のオプションを追加してください。

後で紹介する hotspothotgraph の解析をしたい場合には、--full のオプションを指定して解析する必要があります。

$ gilot log [repository] --full -o [log-full].csv

こちらも少々時間がかかりますので、エラーが出ていない場合にはしばらく待ちましょう。

plot

plot コマンドを使うことで、4つの指標のグラフを作成できます。

$ gilot plot -i [log].csv -o [plot].png
  • [log] には log コマンドで作成した解析結果を指定してください。

  • [plot] にはグラフの画像の出力先を指定してください。

グラフの見方は Qiita の記事を参照してください。

hotspot

hotspot コマンドを使うことで、変更されやすいファイルを解析できます。

$ gilot hotspot -i [log-full].csv
  • [log-full] には --full オプションを追加して解析したログファイルを指定してください。

変更されやすいファイルのランキングがコンソールに出力されます。

変更されやすいということは、バグの温床になりやすいコードであり、リファクタの良い対象になりやすいと考えられます。

hotgraph

hotgraph コマンドを使うことで、同時に変更されやすいファイルのネットワークグラフを作成できます。

$ gilot hotgraph -i [log-full].csv -o [hotgraph].png
  • [log-full] には、-full オプションを追加して解析したログファイルを指定してください。

  • [hotgraph] には、グラフの画像の出力先を指定してください。

--allow-files--disallow-files のオプションで解析対象のファイルのフィルタができますので、プロジェクトによって適宜使用してください。

Windows を使っている方は注意が必要です。

内部で使用している signal.py のライブラリが Windows では使用できずエラーを吐いてしまいます。 (参考)

これは --stop-retry のオプションを使うことで回避ができます。

$ gilot hotgraph -i [log-full].csv -o [hotgraph].png --stop-retry

同時に変更されやすいファイルには何かしらの関連があると考えられます。

もし一見関係の薄いファイルが関連付けられている場合には、それらの責務が適切になっているか確認やリファクタをしたほうがよいと考えられます。

author

最近追加された author というコマンドを使うことで、コミットしている人のコミット量や全体での割合を時系列に解析できます。

$ gilot author -i [log].csv -o [author].png
  • [log] には log コマンドで作成した解析結果を指定してください。

  • [author] にはグラフの画像の出力先を指定してください。

結果

弊社のプロダクトである NEUTRANS BIZ のリポジトリの plot の結果だけ少しお見せします。

f:id:mochinekos:20200711162725p:plain

簡単な考察

上記の結果の考察を簡単にですが行ってみました。

グラフの詳細な説明は Qiita を参照してください。

Gini Coefficient

50%を下回っているので、それほど格差が大きいわけではなさそうです。

これも時系列で追って変化を見てみたいですね。

Hisgram of Code Output

ややピークが大きいでしょうか。

このグラフの使い方はまだピンと来ていないです。

Code Output and Productivity

insertions と deletions が交互に出ていて、定期的にメンテナンスしているのが分かりやすい印象です。

リリースサイクルとの連動がありそうですね。

最近追加された Productivity がまだどのような指標なのか分かっていないです。

Numer of Actual Authors

数値と実体はおおよそ一致している印象です。

数値が落ち込んでいる部分は、おそらくプロダクトの方向性を決めていた時期で手が止まっていたのかなと推測できます。

開発の安定性の参考になりそうです。

おわりに

今回は手でコンソールにコマンドを打って検証しましたが、CI に組み込んで自動で定期的にグラフを出力するのもできそうですね。

ソフトウェアの生産性や健全性は目に見えづらいものですが、ソフトウェアのコードそのものではなく、活動(Git のログ)を用いると数値で解析することできます。

と作者の方が EM.FM でおっしゃっていました。

このような指標を自分で見出したり解析するツールを作るのはなかなか大変ですよね。

その点 gilot はお手軽に可視化までできてとても便利です。

開発チームの生産性や健全性を可視化するツールの1つとして、開発チームのデリバリーパフォーマンスを測る指標 などと併用しながらうまく利用していきたいです。

UnityでのオープンワールドにはZ-Fightingという壁が立ちはだかっていた

はじめに

エンジニアの小池(DBK)です。

VRでオープンワールドに入りたいと思った人はたくさんいると思います。最近はSwitchなどでオープンワールドのゲームが出ているので特に多いのではないでしょうか。
弊社にもそんな人たちがたくさんいて、でっかいシーンを作りVRで入って色々なことがしたい!となりまして、いわゆるオープンワールドのような非常に広大なシーンの作成に取り掛かりました。

成果物

結局、弊社提供中のサービスであるNEUTRANS BIZ上では3km四方のLargeFieldという名前のシーンになりました。

建物や橋を実物大で見ることができるので、なかなか好評です。

訪れた悲しみ

シーン上のオブジェクトが原点から遠ざかっていくほど、Z-Fightingが激しくなっていきます。弊社サービスではuGUIを利用して様々なUIを構成しているので、この現象が頻発してしまい、シーンの大きさを小さくせざるを得ませんでした。

ちなみにZ-Fightingとは、メッシュがジラジラするアレです。ちゃんとWikipediaにも項目があります。
簡単に言うと、同じ位置に面が2つ以上ある場合、描画したいピクセルが複数存在するため、このような現象が発生します。特に、UnityではTransformがfloatなので、浮動小数点の計算精度がZ-Fightingに大きく影響しています。

Z-fighting - Wikipedia

開発環境

一応検証環境を記載しておきますが、Unityのバージョンは関係ないかと思います。

  • CPU:i7 8700
  • GPU:GTX1080
  • メモリ:16GB
  • OS:Windows 10 pro
  • Unity:2018.4.6f

検証

  • 準備

Z-Fightingを故意に発生させるために、uGUIのImageを利用してメッシュの重なりを作成しました。0.0001のオフセットがされていて、緑のImageが手前に配置されています。

右上に表示されているのは原点からのx方向の距離です。

また、メッシュの法線方向のオフセットを0.0001単位で広げることができるボタンも設置しました。

f:id:hdkkikdbk:20200627235817j:plain
Test UI

検証に利用したUnityのシーンはNEUTRANS BIZのLargeFieldで行いました。簡単な部屋のモデルと、グラウンドとしてのPlaneがオブジェクトとして配置されています。ちなみにこのシーンの容量は以下です。

  • LargeField:44KB
  • 空のシーン:16KB

部屋の写真
Room

  • やり方

作成したUIをx方向に原点から移動していき、どの位置でZ-Fightingが発生するか検証しました。

  • 結果

f:id:hdkkikdbk:20200630162655g:plain

原点から離れるほどにZ-Fightingが激しくなりました。こちらのシーンでは約9,000mからZ-Fightingが確認されました。オフセットを+0.1000すると約10,000mで再度Z-Fightingが発生しました。
また、Editorで実行した方が発生しやすいこともわかりました。Editorの処理によるオーバーヘッドが入ってくるためだと思われます。
そのほか、シーン内に配置されているオブジェクトが多いほど、原点からの距離が短くても発生しやすくなりました。

結論と対策

シーンに配置されているオブジェクト数、原点からの距離、表示するメッシュサイズなど、さまざまなパラメータが関係していることが容易に想像できます。定量的に検証するためにはこのようなパラメータで比較する必要がありますが、すくなくともZ-Fightingが発生しないように、メッシュの法線方向の重なりに注意する必要があることがわかりました。

今回の検証では、3Dオブジェクトの検証は行っていませんが、メッシュが重なっている部分では同じ現象が確認されました。

対策としては以下があげられます。

  1. Transformをいじって、Z-Fightingが発生しているメッシュの法線方向に差をつける
  2. シェーダーでオフセットを指定してずらす
  3. 原点からの距離ができるだけ短くなるように、原点を中心として円状にオブジェクトを配置する
  4. Playerが原点から離れないように背景オブジェクトを回転させて移動する

今回の対策としてはTransformで様々なUIにオフセットを持たせることで解決しました。もともと、uGUIのImageが重なっていた部分もあり、すでに多少のオフセットがあったのそれを広げた形になります。

また、初めはシーンに存在する部屋のモデルを原点に置いてシーンを作成していたのですが、端に行くほど原点からの距離が長くなってしまいます。そこで、中央を原点として端に部屋のモデルを配置することで、原点からの距離がシーンサイズの1辺の長さの半分になりました。

Transformを変更する方法だと、Staticなオブジェクトは問題ないですが、オブジェクトが動く場合は原点からの距離に合わせてメッシュの差を制御する必要がありそうです。

また、面のメッシュにだけ対応するだけであれば問題ないですが、立体的なオブジェクトはシェーダーで対策を行う必要があります。シェーダーについての詳しい方法はこちらを参考にしてください。

Unity でのZファイティング(Z-Fighting)の対処法 - 強火で進め

一番確実な方法としては、4つ目にあげたようにPlayerを中心として世界を回すように移動させるのがよいのでしょうが、オブジェクトを動かすときの負荷やVRなので3次元移動での方法を考える必要があるなど、なかなか考えることが多いです。本当にオープンワールドが必要になった時には再度検証してみようと思います。

最後に

Synamonでは、XRで市場を切り開いていきたい、スタートアップで挑戦していきたいエンジニアを募集しています。

気になった方は下記のWantedlyや、自分の(Twitter)でも何でもいいので、気軽にご連絡ください!

ポモドーロ・テクニックで複数人で開発してみた話

はじめに

こんにちは。

株式会社Synamonでエンジニアをしております、渡辺匡城(@mochi_neko_7)と申します。

最後の記事投稿から少し時間が空いてしまいましたが、これから再開していきたいと思っていますので、よろしくお願いいたします。

今回はモブプログラミングにポモドーロ・テクニック(ポモドーロ)を導入した開発を社内で実施してみたので、そこで実際にやってみた結果を簡単に紹介します。

状況設定

まずは簡単にですが開発の状況を紹介します。

  • 4人の固定メンバーの新しいチーム
  • 複数のテーマの開発を中長期間かけて行う
  • リアルで集まることが多い
  • 初めてのモブプログラミング
  • 1日に2~4時間固定で時間を確保
  • メンバーのスキル、経験はバラバラ
  • 設計作業の割合が多め

モブプログラミング(モブプロ)は、ペアプログラミングの複数人バージョンのような形のチーム開発の手法になります。 qiita.com モブプロの紹介はまた別の機会で記事にしますので、ここでは割愛させていただきます。

ポモドーロ自体は個人でも使えるのですが、今回はチームでの開発で適用してみました。

課題

開発を始めて数か月経って、いくつか課題が見えてきました。

  • 議論が白熱すると休憩なしに何時間も話し込んでしまう
  • かなり疲れる
  • 時間がかかる割に話がまとまらない

ポモドーロの導入

そこで、その頃どこかで耳にしたポモドーロ・テクニックを導入してみました。 next.rikunabi.com

ルールは以下になります。

  • 作業25分+休憩5分=1ポモドーロ(1ポモ)
  • 4ポモ毎に30分の長めの休憩を入れる
  • 作業の途中で割り込みが入った場合、そのポモは完了とする

もともとはクリエイティブな仕事での生産性向上のための手法として開発されたようです。

ポモドーロはトマトのイタリア語で、トマト型のキッチンタイマーが由来のようですね。

タイマー1つあれば実施できる手軽なものですが、専用アプリもいくつかあるようです。

個人的にいい感じに使いやすいアプリが見つからず、Unityを使って自分でえいやって作ったものをチームで使っていました。 github.com (最低限の機能重視でUIとかかなり適当ですが...)

というわけで、開発作業を「4ポモ=2時間」のセットで定期的に実施するスタイルをとってみました。

結果

実際にこれを半年近くやってみて実感したことは以下になります。

  • 集中力が上がった
  • 疲れにくくなった
  • 開発のリズム感が出るようになった
  • ポモ単位で作業時間が見積もれるようになった

実際、ポモドーロ導入のタイミングで作業時間は半分になりましたが、アウトプットの差は体感としてはあまり感じませんでした。

その日の作業を「3ポモ作業+1ポモ週次振り返り」のように切る使い方もでき、タイムマネジメントの手法としても優秀です。

個人でもポモドーロを使って仕事をする場合にも有用でした。

ただし、打ち合わせが頻繁に入るような日にはリズム感が崩れてしまい、あまり機能しなかった印象があります。

まとめ

  • 集中して作業したい場合に有用
  • 一人でも複数人でも使える
  • 手軽にできる
  • チーム内での評判はとてもよかった
  • 頻繁に割り込みが入るような場合には合わないかも

一見すると休憩が入ることで作業時間が減り、成果が下がるのではと思われます。 しかし実際には、クリエイティブな作業を集中的にする際には適度な休憩を入れることで、集中力が上がってよいというのを実感できました。

これは実際に体感してもらわないとなかなか伝わりづらいところでしょうか。

30分を単位とした短時間スプリントに応用したり、モブプロのドライバーの交代のタイミングにしてしまうなど、応用もできそうです。

タイマーだけあれば簡単に導入できますので、みなさんも試しに使ってみてはいかがでしょうか。

最後に

Synamonではエンジニア採用をさまざまなポジションで強化中です。

ビジネスXRで市場を切り開いていきたい、スタートアップで挑戦していきたいエンジニアを募集しています。

ご興味ある方はぜひ気軽にお話ししてみませんか。

www.wantedly.com

www.wantedly.com

www.wantedly.com

www.wantedly.com

photo credit: gerlos Pomodoro [day 61] via photopin (license)

xR (VR / AR / MR, etc.) の標準仕様OpenXRについて調べてみた

はじめに

株式会社Synamonでエンジニアをしております,久能 (@do_i_know_it) と申します.

 

VRコンテンツを開発していて一番大変なのは,アプリケーションをOculusやSteamVRなど複数のプラットフォームに対応する,新しいデバイスに対応するなどの作業だと思います.

新しいデバイスは独自のプラットフォームに対応したSDKを使わないと動作できないといった状況が多いのが現状です.

Unityによる開発では,独自プラットフォームのSDKがUnity標準のAPIに十分に対応しておらず苦しめられることも多々あったりします (心当たりがある方も多いのでは?).

 

そんな中,VRにおける仕様を標準化することでアプリケーションの開発コストを削減するためにOpenXRなるプロジェクトが立ち上がりました.

本記事では,「OpenXRとは何ぞや?」という方に向けてOpenXRとその周辺の概要を簡単に紹介したいと思います.

www.khronos.org

OpenXRとは

OpenXRとは,VR (人工現実感) / AR (拡張現実感) / MR (複合現実感) などのxRランタイムプラットフォームにおけるアプリケーションとデバイスとの間の仕様を標準化する取り組みです.

glTF,OpenGL,Vulkanなどを策定したKhronos Groupによって2016年から提唱,推進されています. 

OpenXRは次のような特徴を持つAPIとして策定されます.

  • Open
  • Royalty Free
  • Cross Platform

OpenXR 0.90が2019年3月に公開され,一部の仕様が仮策定されました.

www.khronos.org

OpenXR 1.0は2019年秋に公開予定で,残りの仕様が仮策定されます.

(2019/08/14 追記・修正)

2019年7月にSIGGRAPH 2019にてOpenXR 1.0が公開されました.

www.khronos.org

OpenXR 0.90で仮策定されていた一部の仕様 (後述のApplication Interface) がOpenXR 1.0で整備されました.

残りの仕様 (後述のDevice Plugin Interface) は1.0以降で策定・整備されていくようです.

OpenXRによる恩恵

プラットフォームのアプリケーションとデバイスとの間の仕様が標準化されることでデバイス開発者,プラットフォーム開発者,アプリケーション開発者のそれぞれにメリットがあります.

  • デバイス開発者
    • プラットフォームごとのデバイスドライバの対応が容易になる
  • プラットフォーム開発者
    • デバイスドライバごとのランタイムシステムの対応が容易になる
  • アプリケーション開発者
    • 各プラットフォームや各デバイスへの移植が容易になる

f:id:do_i_know_it:20190618125145j:plain

(OpenXR Overview - The Khronos Group Incより引用)

 

現状では,アプリケーション開発者はデバイスやプラットフォームごとにそれぞれ対応が必要であり,デバイス開発者はプラットフォームのランタイムシステムごとにデバイスドライバを提供する必要があります.

そのため,以下のコストが高くなります.

  • デバイスの各プラットフォームへの対応
  • アプリケーションの各プラットフォームや各デバイスへの対応

これにより,アプリケーションの移植性が課題となっています.

 

例えば,UnityでSteamVR対応のPCVRコンテンツを開発するとしましょう.その場合,以下のような事態が考えられます.

  • SteamVR PluginによりOculus RiftやHTC VIVE,Windows MRに対応したコンテンツを開発
  • Oculus Storeへの移植,Oculus GoやOculus Questへ対応するためにはSteamVR PluginをOculus Integrationに置き換える必要

最近はスタンドアロンなHMDもいろいろ出てきましたよね.VIVE Wave SDKやDaydream用のGoogle VR SDKなど,スタンドアロンHMDはPCVRとは別のSDKを必要とする場合が多い印象です.これらに対応しようとするとまたまたSDKを使用した処理の置き換えが発生します.

今後さらに多様なプラットフォームが台頭してくると,コンテンツを各プラットフォームに対応する度にそれぞれのプラットフォーム用のSDKに処理を置き換えていくことになり,マルチプラットフォームに対応したコンテンツを気軽に開発しにくくなっていきます.

 

OpenXRによって仕様が標準化されることで,アプリケーションの移植性が向上し,多様なプラットフォーム,多様なデバイスに対応したコンテンツを提供できるようになります.

APIのアーキテクチャ

これらの恩恵を実現するためのアーキテクチャとして,OpenXRでは2層のAPIを提供することでデバイス,プラットフォーム,アプリケーションを分離します.

  • Application Interface
    • プラットフォームのランタイムが提供するAPI
    • アプリケーションはこのAPIを通じてランタイムへアクセス
  • Device Plugin Interface
    • デバイスドライバが提供するAPI
    • ランタイムシステムはこのAPIを通じてデバイスドライバへアクセス

f:id:do_i_know_it:20190618125632p:plain

 

Unity, Oculus,SteamVR,Oculus Rift,HTC VIVEがそれぞれOpenXRに対応した未来を考えてみましょう.その場合,以下のような恩恵が考えられます.

  • Oculus RiftやHTC VIVEがDevice Plugin Interfaceを公開するデバイスドライバに対応することで,デバイスの動作環境がOculusでもStreamVRでもよい
  • OculusやStreamVRのランタイムがApplication Interfaceを公開し,Device Plugin Interfaceに対応した実装になることで,ランタイムは制御しているデバイスがOculus RiftでもHTC VIVEでもよい
  • Unityの標準APIがApplication Interfaceに対応した実装になった場合,アプリケーションは実行環境がOculusでもSteamVRでもよい

 

また,OpenXRは公式APIレイヤの他に独自のレイヤを設けられるため拡張性の高い設計になっています.追加したレイヤによって独自の機能を追加してAPIを拡張したり,既存APIの挙動を変更することができます. 

f:id:do_i_know_it:20190618125550p:plain

対応するデバイス

OpenXR 0.90は下記の形態のデバイスをサポートします.

  • Hand
    • ハンドコントローラ
      • ex) Oculus Touch
    • トラッキングした手の姿勢
      • ex) Leap Motion
  • Head
    • ヘッドマウンテッドディスプレイ (HMD)
      • ex) HTC VIVE
    • トラッキングした頭の姿勢
      • ex) RealSense
  • Gamepad
    • 従来の両手持ちゲームパッド
  • Treadmill
    • 歩行による移動を計測する装置

提供する機能

OpenXR 0.90は下記の機能を提供します.

  • Spaces
    • アプリケーション内の空間の管理
  • View Configuration
    • アプリケーション画面構成の管理
  • Session
    • アプリケーションの実行ループの管理
  • Rendering
    • アプリケーションの描画処理の管理
  • Input and Haptics
    • ユーザのアクションとフィードバックの管理

Renderingはあくまで描画処理の実行タイミングなどの管理だけを行い,実際の描画命令がどのような実装かは問われません.そのため,描画の手段としてOpenGLを利用するかVulkanを利用するかなどはプラットフォームのランタイムの実装次第となります.

詳しくは公式の仕様を眺めてみてください.

www.khronos.org

メンバーシップ

Khronos Groupのメンバーシップに参加することで,OpenXRの仕様の普及や策定などに関わることができます.

www.khronos.org

メンバーシップは大まかに分けて以下の2種類に大別されます.

  • 仕様の策定に参加可能,普及活動に参加可能

f:id:do_i_know_it:20190618130518p:plain

  • 仕様の策定は参加不可,普及活動は参加可能

f:id:do_i_know_it:20190618130514p:plain

(https://www.khronos.org/members/より引用)

2019年7月現在,GoogleやMicrosoftの他,Unity,Epic Games,Sonyなどが参画しています.

OpenXRへの対応状況

APIへの対応状況は2019年7月現在下記の通りです.

  • 対応済み
  • 年内対応予定 
    • Oculus (Facebook)
    • Unreal Engine (Epic Games)

 

Unityの対応状況はというと,現時点では公表されていません.しかしメンバーシップには参加しているので,近く対応することを期待しています.

 

(2019/08/14 追記)

Oculus Rift,Oculus  QuestのOpenXR対応が発表されました.

 

www.khronos.org

 

その他の標準化プロジェクト

今回紹介フォーカスしているOpenXRの他にも,xRにおける仕様を策定しようとする活動がいくつかありました.

OpenVR

Valve Softwareが2015年から提供しているVRデバイス向けのAPIであり,特定のハードウェアベンダのSDKなどに依存せずにアプリケーションを開発できることを目的としています.

github.com

BSD 3-Clause Licenseで公開されています.

OpenXR同様,アプリケーション側とドライバ側の2層にAPIが分かれています.

www.youtube.com

2019年7月現在,主にSteamVR Pluginの公開APIのような立ち位置になっています.

またSteamVR PluginはInput System 2.0でOpenXRへの対応を見据えた機構に変わりました.

Open Source Virtual Reality (OSVR)

Razerなどが2015年1月から推進していたオープンソースなVRデバイスの仕様標準化プロジェクトです.

ハードウェア要求が低くOSに依存しないため,GNU/LinuxのPCでVRを体験できるのが特徴です.

osvr.github.io

Apache 2.0 Licenseで公開されています.

2019年7月現在,残念ながらコミュニティでの活動が見られません.

また,RazerはSensicsと提携して同名のPC向けHMDを開発・販売していましたが,現在は生産が終了しているようです.

General Specifications for Virtual Reality Head-Mounted Displays

中国電子標準化研究所が2017年4月から提唱,推進している仕様書です.

北京工科大学やHTCなど,中国国内の研究機関や企業が標準化に参加しています.

2017年7月から仕様書の英文版(原題:虚拟现实头戴式显示设备通用规范)が公開されています.

skarredghost.com

 

おまけ

公式HPにてTシャツが販売されています.OpenXRを広めたい,OpenXRに貢献している気分になりたい方におすすめです.

Powered by teespring

teespring.com

 

これまでに紹介した通り,OpenXRはデバイスドライバ,ランタイム,アプリケーションの間におけるAPIを標準化する取り組みです.

これに対して,デバイスとPCとの物理的な接続方法に関する標準規格がVirtualLinkです.USB Type-CのDisplayPort Alternate Modeを用いて,HMDの接続規格を標準化します.

sites.google.com

まとめ

本記事では,OpenXRとその周辺の概要を紹介しました.

  • OpenXRとはxR (VR/AR/MR) の仕様を標準化する取り組み
  • アプリケーション,プラットフォームのランタイム,デバイスドライバの間に標準APIを策定
    → プラットフォーム,デバイス別の対応が簡易化
    → アプリケーションの移植性が向上
  • OpenXRの他にも標準仕様を策定する取り組みが存在する
  • メンバーシップに参加するとOpenXRの普及や策定に関われる

今回紹介したOpenXRなどの標準仕様の策定が推進されている現状を見ると,弊社の目指すVRが当たり前の世界へ近づいている実感がありますね.

仕様が標準化されることでVRの普及が進むことを期待しているので,今後も動向を追っていきたいと思っています.

ReorderableListのすすめ

 

はじめに

こんにちは。

株式会社Synamonでエンジニアをしております、渡辺(@mochi_neko_7)と申します。

 

本記事のテーマは、UnityのEditor拡張のひとつである、「Reorderable List」になります。 

 

通常の配列やリストのUnityEditor上でのGUIは、以下のように要素の順番が固定されています。

f:id:mochinekos:20190527161509p:plain

一方でReorderableListでは、GUIでリストの要素の順番を自由に入れ替えられるのが大きな特徴です。

f:id:mochinekos:20190620123924g:plain

 

Unityには以前からある機能で、とても便利なものなのですが、あまり知られていないのではないでしょうか?

 

本記事では、

  • ReorderableList
  • Editor拡張による開発環境の向上

を知ってもらうことを目的としています。

 

概要は以下のとおりです。

  1. ReorderableListとは
  2. Simple Reorderable List
  3. Editor拡張の知見
  4. やり残したこと

初心者向けの説明から、具体的な使い方の説明まで行います。

ソースコードおよびUnityPackageは以下のGitHubで公開しています。

github.com

 

かいつまんだ説明はこちらのイベントのLTでも発表させていただきました。

roppongiunity.connpass.com

 

LTのスライド資料も併せて参考にしていただければと思います。

docs.google.com

 

本記事ではこの内容に加えて、

  • もう少し細かな説明
  • 実際の使い方
  • カスタマイズ例
  • やり残したこと

などを補足したいと思います。

 

 

 

 

 

 

1、ReorderableListとは

ReorderableListは、UnityのEditor拡張の一つです。

あまりご存じない方のために、Editor拡張とはなにか、ということから、ReorderableListとはなにか、ということまで簡単に紹介したいと思います。

 

Editor拡張とは

Unityのプログラムは、大きく分けると次の2つに分類することができます。

  1. Unity Engine  = Unityで作成したアプリケーションおよびEditor上で動作するもの
  2. Unity Editor    = UnityのEditor上のみで動作するもの

今回お話するのは、後者のUnityEditorの話になります。

 

Unityでアプリケーションを作る際には、GUIによるEditor上での操作が基本になります。

このGUIは利用者がカスタマイズすることができ、Editor拡張と呼ばれています。

たとえば、

  • コンポーネントのInspectorでの表示を調整
  • 専用ウィンドウを自作
  • Projectの表示を改造

などといったこともできます。

 

 

配列やリストのEditor表示

配列やリストをInspectorに表示して、Editor上で編集したい場合、表示したいフィールドに[UnityEngine.SerializeField]のAttributeを付けることで可能です。

f:id:mochinekos:20190619204633p:plain

f:id:mochinekos:20190527161509p:plain

特徴は以下の3つです。

  • 要素数をSizeで指定する
  • 要素間の挿入・削除はできる(右クリック)
  • 順序の入れ替えはできない

この最後が厄介で、順番が大事になるリストの使い方をした時には、パラメータをそれぞれセットしなおさなければなりません。

パラメータの中身を保持したまま要素の順番を入れ替えたいような時に、もどかしい思いをしたことはありませんか?

そこで役に立つのがReorderable Listです。

 

 

Reorderable List

実はUntiyEditorInternalのNameSpaceの中にReorderable Listなるものがあります。

「Reorderable」の意味は、

  • re : 繰り返し
  • order : 順番を変える
  • able : 可能

で、つまり「入れ替え可能な」ということです。

リストの要素の操作が直感的にできる、結構便利な機能です。

全部のList表示が最初からこのReorderableListでもいいのでは、と思うほどです。

 

ただし、InternalのNameSpace内ですので、正式にリリースされているものではないことに注意する必要はあります。*1

 

このAPIは便利な反面、少し扱いづらいものとなっています。

UnityEditor.EditorGUILayoutなどの他のEditor便利クラスたちとは違って、各要素の描画方法や高さを自分で指定する必要があります。*2

毎回個別に描画方法を指定する方式では、使いまわしが利きません。

それに描画方法を書かせるのは、GUI初心者にはややハードルが高いですよね。

それではせっかく便利な機能も使われなくなってしまいます。

 

そこで、こんなReorderableListが欲しいと思うわけです。

  • できるだけ扱いやすいものがいい
  • 汎用的に使えるものがいい
  • 機能はシンプルなものでいい 

 

シンプルで使いやすいものが欲しかったので、自分で作成することにしました。

それが「Simple Reorderable List」です。

github.com

 

本記事の目的は、あくまでReorderableListの布教です。

なので、もし他にいいものがあれば「Simple Reorderable List」を使わなくても構いません。

AssetStoreやGitHubにいつくか見つかると思います。

シンプルな機能があれば十分、むしろ余計なものはいらない、というのであればぜひこちらを使ってもらえればと思います。 

 

 

 

2、Simple Reorderable List

自分の作成したReorderableListの使い方を紹介します。 

 

以下の順番で説明していきたいと思います。

  • Editor拡張の準備
  • SimpleReorderableListの使い方
  • 特徴
  • オプションの説明
  • カスタマイズ例
  • 思想

 

 

Editor拡張の準備

Editor拡張の準備をしましょう。

 

ReorderableListを使用したいコンポーネントをSinglePropertySampleとします。

このコンポーネントのInspectorでの表示を自分で調整したい場合には、Editor拡張用のクラスを作成する必要があります。

ここではSinglePropertySampleEditorとし、これをEditorという名前のフォルダに置きます。*3

f:id:mochinekos:20190619212556p:plain

SinglePropertySampleには、ここではとりあえず文字列のリストtextsを持たせておきましょう。

このtextsをEditor上で編集できるようにするために、[UnityEngine.SerializeField]を付けるのを忘れないでください。

f:id:mochinekos:20190619212809p:plain

 次にEditorのスクリプトの準備をしましょう。

SinglePropertySampleEditorを作る上でのお約束は、

  1. UnityEditor.Editorクラスを継承する
  2. UnityEditor.CustomEditorAttributeをつける
  3. AttributeのConstructorに、調整したいコンポーネント(SinglePropertySample)のTypeを入れる
  4. UnityEditor.Editor.OnInspectorGUI()をオーバーライドして、描画を上書きする

になります。

f:id:mochinekos:20190619213231p:plain

 

ひとまずこれでEditor拡張の基本的な準備は完了です。

Editor拡張自体に関する入門的な話を知りたい方は、以下のサイトなどをご覧いただくのがおすすめです。

anchan828.github.io

caitsithware.com

 

 

 

SimpleReorderableListの使い方

Simple Reorderable List」を導入しましょう。

github.com

のReleaseにある最新版の.unitypackageをダウンロードし、UnityEditorにDrag&Dropしてインポートします。

 

textsをReorderableList化する手順は以下になります。

  1. Mochineko.ReorderableList.ReorderableListLayouterのフィールドを用意する
  2. OnEnable()で、textsSerializedPropertyを取得し、1. のフィールドを初期化する
  3. OnInspectorGUI()で、1. のフィールドのLayout()を呼び出す
  4. OnInspectorGUI()の最後に、UnityEditor.Editor.serializedObject.ApplyModifiedProperties()を呼び出す

f:id:mochinekos:20190619214048p:plain

これにより、textsのEditor上での表示が次のような感じになります。

f:id:mochinekos:20190619214407p:plain

 

 

 

特徴

SimpleReorderableListの機能の特徴は、

  1. 要素の入れ替え、追加・削除をGUIで直感的に操作できる
  2. 複数プロパティを持つ要素や、自作したクラスにもそのまま使える
  3. 要素の背景に交互にコントラストを付けて見やすく
  4. カスタマイズでDropDownで要素を追加することもできる

になります。

それぞれGIF画像で簡単に紹介していきます。

 

SimpleReorderableListには、以降で挙げる例をはじめとして、簡単なサンプルを用意しています。

よろしければ実装のコードも併せてご参照ください。

 

要素をドラッグして、順番を入れ替えることができます。

f:id:mochinekos:20190620123924g:plain

 

右下の「+・-」ボタンで要素の追加・削除をすることができます。

f:id:mochinekos:20190620124140g:plain

 

複数プロパティを持つ場合でも、フォールドアウト付きで表示できます。

f:id:mochinekos:20190620123951g:plain

  

上の例が既にそうですが、自作したクラスでも表示できます。

内部にリストなどを含んでいても問題ありません。

f:id:mochinekos:20190620124432g:plain

 

あらかじめ用意した文字列を使って、ドロップダウンで要素を追加することもできます。

f:id:mochinekos:20190620124745g:plain

 

 

オプション

SimpleReorderableListには大きく分けて2つのオプションを用意しています。*4

  • NativeFunctionOptions
  • ReadyMadeDrawerOptions

デフォルトのままで問題ない場合には、何も指定せずに使用できます。

f:id:mochinekos:20190620152530p:plain

少しカスタマイズしたい場合などには変更することができます。

ここではこれらのオプションの説明をしたいと思います。

 

NativeFunctionOptions

本来のReorderableListにあるオプションです。

  • Draggable = 要素をドラッグして順番を入れ替えられるか
  • DisplayHeader = ヘッダー部分に文字を表示するか
  • DisplayAddButton = 要素を追加するボタン(+)を表示するか
  • DisplayRemoveButton = 要素を削除するボタン(-)を表示するか

f:id:mochinekos:20190624153256p:plain

デフォルトではすべてtrueにしています。

必要のない機能がある場合には、Constructorでオプションを放り込んで指定してください。

f:id:mochinekos:20190620150801p:plain

 

 

ReadyMadeDrawerOptions

自分が作成した描画方法を使用するかのオプションです。

  • UseReadyMadeHeader = リストのプロパティ名をヘッダーに表示します
  • UseReadyMadeElement = 自動的に要素の描画を行います
  • UseReadyMadeBackground = 見やすいように要素の背景色を交互に変えます

これもデフォルトではすべてtrueにしています。

これも必要のない機能がある場合には、Constructorでオプションを放り込んで指定してください。

f:id:mochinekos:20190620151720p:plain

 

もちろん、2種類のオプションをどちらも変更することも可能です。

f:id:mochinekos:20190620151955p:plain

 

 

カスタマイズ例

これまでにお見せしたのは、標準的な使い方をした場合のものです。

ここでは、オプションによって少し応用を利かせたユースケースを紹介します。

 

要素数の固定

通常のリストなどでは、Editor上のSizeのパラメータで要素数を変えることができました。

逆に言えば、いくらスクリプトで要素数を指定しても、Editorで数を変えることができてしまいます。

ところが、ReorderableListでは要素数は右下のボタン(+、-)でのみ行い、これらは非表示にすることができます。

そのため、以下のようにして要素数を変更できないようにすることも可能です。

 

Editor側で要素数を指定して初期化します。

f:id:mochinekos:20190613124020p:plain

ReorderableListの初期化時に、要素の追加と削除のボタンを非表示にするようオプションを指定します。

f:id:mochinekos:20190624151450p:plain

すると、このように要素数を変更できないリストが出来上がります。

f:id:mochinekos:20190613124400p:plain

 

もし古いシリアライズデータが残っていて数が変な場合には、コンポーネント右上の歯車アイコンをクリックし、Resetを実行してください。*5

 

 

ドロップダウン

決められた要素しか追加したくない場合、追加する要素をあらかじめ用意した一覧から選ばせる方法があります。

 

ReorderableListの初期化時に、AddDrawDropDownCallback(...)を使用します。

第一引数には、選ばせたい候補strin[]を文字列で指定します。

第二引数には、選ばれた文字列に対するコールバックSystem.Action<string>を指定します。

f:id:mochinekos:20190621191902p:plain

すると、このようにドロップダウンで選択して要素を追加することができます。

f:id:mochinekos:20190613125712g:plain

 

このように、Editor拡張を少し工夫することで、Editorの使いやすさとある程度の制約を両立することもできます。

 

 

思想

まとめとして、簡単に設計思想的なものをお話しします。

  • シンプルさ
  • 汎用性
  • 見やすさ

 

自作した主な動機は、Unity本来のReorderableListが扱いにくいことでした。

ですので、できるだけシンプルに使える、自分が使いたいと思えるものを作るよう心掛けました。

 

せっかく作ったものでも、汎用性がなければいろんなところで使うことができません。

配列やリストは様々な型の要素を扱いますので、ジェネリックな対応は必須です。

今回作ったものでは、UnityのSerializedPropertyの仕組みをそのまま流用する形で、これを実現しています。

 

機能的な部分だけではなく、GUI上での見やすさもこだわっています。

Projectウィンドウなど、要素の数が増えるととても見づらく、神経質になる必要が出てきます。

複数の要素を扱う場合を想定しているので、要素の区別がしやすいよう、かつ邪魔にならないよう調整しています。

 

 

3、Editor拡張の知見

 

Serialized Property

UnityEditor.SerializedPropertyには、

  • CountInProperty(...)
  • CountRemaingin()

という一見便利そうなメソッドが用意されていますが、少し注意が必要です。

これらのメソッドを叩くと、SerializedPropertyIteratorが1つ進みます

つまり、メソッド実行後のSerializedPropertyは1つ先のPropertyを指すものになります。

Debug.Log()SerializedPropertyの内部の状態を見ながら動作確認...なんてやっていると変な挙動をするので注意してください。

公式のスクリプトリファレンスにも(英語で)書かれています。 

docs.unity3d.com

 

これを回避するためには、一度SerializedPropertyコピーSerializedProperty.Copy()で取ればよいです。

コピーのほうを操作してもコピー元には影響しなくなります。

 

 

ユーザースキンの考慮

 

UnityのPro以上のライセンスでは、EditorSkin(カラーテーマ)をPreferencesで変更することができます。*6

f:id:mochinekos:20190613130837p:plain

それぞれの違いは以下です。

  • Personal:無料版でも利用できる、白っぽいテーマ
  • Professional:Pro以上で利用できる、黒っぽいテーマ

 Personalではこんな感じ。

f:id:mochinekos:20190613130916p:plain

Professionalではこんな感じ。

f:id:mochinekos:20190612124229p:plain

 

どちらを利用するのかは好みの問題です。

しかし、Editor拡張で描画する際に自分で色を指定する際には、スキンで見かけが変わることに注意しなければなりません。

Professionalで見やすく調整しても、Personalでは見にくい、なんてこともあります。

 

EditorGUIUtility.isProSkinでユーザーの使用しているスキンがどちらか判定できますので、必要に応じて色を使いわけるなどしましょう。*7

あまり多くはないかもしれませんが、スキンの違いで微妙にレイアウトが変わる場合もあります。*8

描画を自分で行う際には、念のためスキンを変えても問題ないか確認するのがいいと思います。

 

 

 

4、やり残したこと

今回、理由があって対応できなかったことを最後に述べておきます。

 

PropertyDrawer対応

今回作った「SimpleReorderableList」は、面倒な設定をすることがなく汎用的に使えるものにはなっています。

ですが、これを使用する際には、どうしてもEditor拡張を書く必要があります。*9

フィールドに特定のAttributeを付けるだけで使うことができ、Editor拡張を書かなくてもいいのが理想です。

 

これを実現できそうなEditor拡張の一つとして、PropertyDrawerがあります。

これらの詳細は先ほども挙げたこちら

anchan828.github.io

を参照してください。

 

実際にこれを試してみたのですが、配列やリストに対してのPropertyDrawerは各要素にしか適用されず、リストそのものの描画を上書きすることはできないようです。

そのため、PropertyDrawerによる対応は泣く泣く諦めました...*10

 

 

IList対応

ReorderableListの初期化の方法には、実は大きく分けて2つあります。

  • SerializedProperty
  • IList

各要素の描画の指定と高さ計算の汎用性から、前者のSerializedPropertyによるもののみの実装をしました。 

IListに対応する際には、これらの汎用的なものを自作するか、使用する部分で都度作成するかになります。

これはかなり重労働になるため、今回は対応を見送りました。

 

 

 

まとめ

今回もやや長くなってしまいましたが、要約すると、

  • ReorderableList便利ですよ
  • 「Simple Reorderable List」よかったら使ってください
  • いくつかEditor拡張の知見を共有します

という話でした。

 

初心者向けの説明から、具体的な使い方の手順まで紹介しました。

ソースコードもGitHubで公開していますので、独自でReorderableListを実装されるかたなどに参考になれば幸いです。

 

 

おわりに

Editor拡張は、基本的には実際に動作するアプリケーションに何かするわけではないので、割と後回しにされがちなのではないでしょうか?

ですが実際に触ってみると、いろいろなことができて結構楽しいですし、開発がはかどる便利機能を作ることができたりします。

ReorderableListはそんな便利な機能の一つに過ぎません。

どんなものを作るにせよ、開発環境って結構大切ですよね。

本記事をきっかけに、Editor拡張を触ってみようと思う人が少しでも増えてくれると嬉しいです。

 

 

*1:とはいえUnity自体で各所で使われていますので、すぐに使えなくなるというようなこともないと思われます

*2:実際には、特定のdelegateに描画メソッドなどを += で差しにいきます

*3:Editorという名前のフォルダの中にあればいいので、場所はどこでもいいです。個人的には近くに置いたほうが分かりやすくて好きです

*4:パラメータが多くなったので、カテゴライズしてstructを用意しました

*5:ただし、ほかの要素のシリアライズデータもリセットされてしまうので注意してください

*6:商用で利用している方は当然利用できますよね?

*7:とはいえPro以上の人は実際に切り替えて色を確認できますが、無料版ではできないのでなかなか大変です...

*8:実際、ReorderableListの背景の描画では、要素の左側のマージンが微妙に違いました...

*9:Editor拡張のコードを自動生成する機能も一度作ったのですが...

*10:もし方法を知っている方がいらっしゃいましたら教えてほしいです