Oculus Goを使ったVR勤怠打刻で気持ちを高める

freee Developers Advent Calendar 2018の3日目、会計 freee のUI設計とかプロダクトマネジメントとかを担当している @toofu__ です。業務と関係ない話を書きます。

気持ちを高める打刻

みなさん、打刻していますか?私は正直「面倒だな〜〜~」とか思いながら、いち従業員の責務として毎日打刻しています。

みんな同じような気持ちなのでしょう、怠惰な人類はいかに手間をかけずに勤怠打刻するかに知恵を絞り、スマホアプリを使ったり、音声入力で打刻したりします。しかし個人的には「よし、頑張るぞ!」と、やる気が出る打刻方法があってもいいのでは?と考えています。

人事労務freeeのスクリーンショット
ブラウザから退勤打刻をした様子 無機質

たとえば、打刻したらお気に入りのキャラクターが目の前で声をかけてくれるというのはどうでしょうか。気持ちが高ぶるのではないでしょうか。ちょうど手元にVR機器のOculus Goが転がっていたので、これを使ってやってみることにしました。

先に結果を載せておくとこんな感じです。

下準備

環境

  • Unity 2018.2.8f1
  • Oculus Go
  • 人事労務freee

人事労務freeeでは勤怠打刻APIが提供されています。今回はそれを使ってやっていきます。

freee Developer Communityのガイドを読んでアプリを作成し、appIDとsecret、それからAuthorization Codeを発行しておきます。(コールバックURIはurn:ietf:wg:oauth:2.0:oobで大丈夫です)

それからUnity側の下準備です。Unityの基本的な使い方の説明は省略しますが、まずはプロジェクトを新規作成し、アセットストアからOculus Integrationをインポートします。

アセットストアのスクリーンショット

インポートするとOculusという名前のフォルダがプロジェクト内にできるので、その中にあるOVRCameraRigという名前のプレハブをシーンに追加します(ついでに、はじめからあるMainCameraを削除します)。

OVRCameraRigを追加した様子のスクリーンショット

これで準備完了です。ここから実装を始めていきます。

実装

いくつかクラスを作っていきます。クラス間の関係はこんな感じです。主なスクリプトはgistにも書いておきます。

Unityのクラス間の関係図

Unityからfreee APIへの連携

簡単ですがこんなライブラリを作ったので、これでペイっと接続していきます。

github.com

コードをダウンロードして、Unityプロジェクト内にコピーしておきます。そこから、FreeeEventHandlerという名前のラッパークラスを作って、freee APIを叩いて行いたい操作を作っていきます。

using Freee;

public class FreeeEventHandler : MonoBehaviour {
  private Client client;
  [SerializeField] private string appID;
  [SerializeField] private string secret;
  [SerializeField] private string redirectURL;
  [SerializeField] private string authorization_code;
  [SerializeField] private string company_name;
  private int company_id;
  [SerializeField] private int employee_id;

  // 認証
  private void GenerateAccessToken() {
    string refresh_token = PlayerPrefs.GetString("refresh_token", "");
    client = new Freee.Client(appID, secret, redirectURL);
    if (string.IsNullOrEmpty(refresh_token)) {
      client.authorizationCode = authorization_code;
    } else {
      client.refreshToken = refresh_token;
    }
    StartCoroutine(client.GenerateAccessToken(GenerateAccessTokenCallback));
  }

  private void GenerateAccessTokenCallback(bool success, string response) {
    if (!success) return;
    GetCompanies(); // 認証が成功したら事業所IDを取りに行く
  }

  // 事業所ID取得
  private void GetCompanies() {
    StartCoroutine(client.Get("https://api.freee.co.jp/api/1/companies", new Dictionary<string, string>(), GetCompaniesCallback));
  }

  private void GetCompaniesCallback(bool success, string response) {
    if (!success) return;

    Company[] companies = JsonUtility.FromJson<Companies>(response).companies;
    var company = companies.First(c => c.display_name == company_name);
    company_id = company.id;

    // どの打刻が可能かを問い合わせて、結果をTimeClocksControllerに引き渡す処理
  }

  // 打刻
  public void PostTimeClocks(string type) {
    string endpoint = "https://api.freee.co.jp/hr/api/v1/employees/" + employee_id + "/time_clocks";
    // 打刻処理
  }

}

で、このクラスを適当なGameObjectにアタッチして、次のように値を入れていきます。

FreeeEventHandlerの値設定のスクリーンショット

App ID Secret Redirect URL Authorization_codeにはさきほどのアプリケーション登録で取得したそれぞれの情報を、Company_nameには人事労務freeeの事業所名、Employee_idには自分の従業員IDを記入します。これで打刻APIにリクエストを送るために必要な情報が揃います(従業員ID、gistでは取得用のスクリプトを書いていますが、めんどくさい人はこちらの記事を参考にして取得してください)。

打刻入力のUI

自分のお気に入りキャラクターはユニティちゃんです。本名は「大鳥こはく」さんで、ユニティ・テクノロジーズ・ジャパン公式のキャラクターです。ライセンスに準拠する形であれば、3Dモデルデータ等が無償で利用できます。さらに素晴らしいことに、表情や基本的なアニメーションなどがはじめから作られているので、簡単な利用であれば自分で動きを作ったりする必要がありません。 ダウンロードページ

SDユニティちゃんの画像
3頭身の「SDユニティちゃん」が好きです

このユニティちゃんをお迎えしてUIを作っていきます。

「打刻したらお気に入りのキャラクターに教えてもらいたい」という動機ではじめましたが、どうせなら「出勤ボタンを押して出勤」とかではなく、キャラクターとのインタラクションによって打刻を実行したいという気持ちが湧いてきました。そこで「ユニティちゃんと数秒間見つめ合って打刻」というUIにしてみます。

まず、ダウンロードしたSDユニティちゃんアセットパッケージをUnityプロジェクト内にインポートし、SD_unitychan_humanoidという名前のプレハブをシーン内に追加します。

プレハブ追加のスクリーンショット

ついでに、見つめ合っている時間を可視化するゲージを追加しました(見つめ合うとゲージがたまり、満タンになると打刻する)。これはuGUIの標準Sliderを調整して使っています。

スライダーを配置したスクリーンショット

肝心の「見つめ合う」判定ですが、まずSD_unitychan_humanoidに初めからアタッチされているIKLookAtコンポーネントを使って、自動でカメラの方を見続けてもらうことができます。下画像のように、LookAtObjに、ユニティちゃんに見つめてほしいオブジェクト(ここではOVRCameraRigのカメラなのでCenterEyeAnchor)をアタッチします。これでカメラが動き回ってもユニティちゃんは常にカメラの方を見つめてくれます。あとはカメラがユニティちゃんの方を向いているのを検知すればOKです。*1

IKLookAtの設定のスクリーンショット

カメラがユニティちゃんを向いていることを検知するために、SD_unitychan_humanoidに追加でSphereColliderコンポーネントをアタッチします。ちょうどユニティちゃんの頭にくるように位置と大きさを調整します。

コライダー配置のスクリーンショット
わかりづらいですが頭あたりに球体が2つあり、片方がいま追加したコライダーです

そして、カメラ側でものを見つめるGazePointerクラスと、見つめられる側であるGazableクラス、そしてGazableクラスを継承した、私と見つめ合ってくれるGazableUnitychanクラスを作成します(それぞれgist参照)。GazableUnitychanクラスをSD_unitychan_humanoidにアタッチします(gist)。

詳しくは長くなるので省略しますが、「カメラから飛ばしたRayがユニティちゃんの頭にあるSphereColliderに数秒間ヒットしつづけたらTimeClocksControllerPostSimpleTimeClocksメソッドを実行する」というアレです。

public class TimeClocksController {
  // (中略)

  public void PostSimpleTimeClocks() {
    _FreeeEventHandler.PostTimeClocks(simpleAvailableType(m_AvailableTypes)); // いまリクエストできる打刻の種類をm_AvailableTypesに格納しています
  }
  
  // 出勤が打刻できるなら出勤、退勤が打刻できるなら退勤のパラメータをつくる
  private string simpleAvailableType(string[] types) {
    if (Array.IndexOf(types, "clock_in") >= 0) {
      return "clock_in";
    }  else if (Array.IndexOf(types, "clock_out") >= 0) {
      return "clock_out";
    } else {
      return "";
    }
  }
}

これで見つめ合ったら打刻のUIができました。この時点でだいぶ幸せではあるんですが、当初の目的である「打刻したらお気に入りのキャラクターが声をかけてくれる」の部分をつくっていきます。

打刻完了時のユニティちゃん反応UI

特に理由はありませんが出勤よりも退勤を喜んでほしいので、

  • 出勤打刻時は微笑んでくれる
  • 退勤打刻時は喜びのあまりジャンプしてくれる

という感じにします。

SDユニティちゃんの横に吹き出しで「出勤しました 今日も一日頑張ろう!」のセリフが出ているスクリーンショット
こんな感じでフキダシでメッセージを伝えてくれる

そのあたりの反応の処理をまとめるSystemMessageControllerクラスを作ります。ユニティちゃんのリアクションやフキダシの動きなどはこのクラスに記載しています。詳細はgistを御覧ください。

public class SystemMessageController : MonoBehaviour {

  // 微笑みとともにフキダシが出る(引数によっては飛び跳ねてくれる)
  public void ShowMessageWithSmile(string message, bool Jumping = false, float remainTime = 5f) {
    if (Jumping) m_UnitychanAnimator.SetBool("Jump", true);
    ShowMessage(message, "smile@sd_hmd", 5f);
  }

  // 悲しそうな顔でフキダシが出る(エラーが出たときとか)
  public void ShowMessageWithSad(string message, float remainTime = 5f) {
    ShowMessage(message, "sad@sd_hmd", 5f);
  }

  // private関数諸々省略(gist参照)

}

で、FreeeEventHandlerに書いていた打刻完了時の処理をこのように追記します。打刻が完了するとSystemMessageControllerに処理を渡しつつ、また次の打刻可能種別を問い合わせしにいく、というやつです。

private void PostTimeClocksCallback(bool success, string response) {
        if (!success) return;

        TimeClock tc = JsonUtility.FromJson<PostTimeClocksResponse>(response).employee_time_clock;
        switch(tc.type) {
            case "clock_in": // 出勤打刻時
                _SystemMessageController.ShowMessageWithSmile("出勤しました\n今日も一日頑張ろう!");
                break;
            case "clock_out": // 退勤打刻時
                _SystemMessageController.ShowMessageWithSmile("退勤しました\nおつかれさま!", true); // 退勤時は2番目の引数を入れてジャンプしてもらう
                break;
        }

        GetTimeClocksAvailableTypes(); // 次の打刻可能種別を問い合わせる
    }

こんな感じで打刻結果をユニティちゃんが通知してくれるUIができました。欲を言えば音声で通知してくれたりするとグッときますが、今回はフキダシです。

ビルド

UnityからOculusGoへビルドするには、Android SDKのインストールなど色々準備が必要です。参考になるページが色々あるのでそちらを御覧ください。気をつけることとしては、今回は簡易的にfreee APIのAuthorization codeをプロジェクト内に書き込んでいますが、Authorization codeの有効期限は10分間なので、ビルド前に発行して、すぐ書き込んでビルドする必要がある、ということでしょうか(いちどRefresh tokenが発行されたら端末に保存し、次回からはそちらを使うので、毎回発行する必要はありません)。

で、実際にビルドしたのが冒頭の動画です。

再掲

念のため、ブラウザでも確認してみます。

人事労務freeeで打刻内容を確認しているスクリーンショット
ちゃんと出勤と退勤が打刻できているのが確認できました

この実装により、

  • Oculus Goを持って出社する
  • Oculus Goをかぶる
  • アプリを起動する
  • ユニティちゃんと見つめ合って出勤打刻
  • Oculus Goをはずす
  • 作業開始
  • 作業終了
  • Oculus Goをかぶる
  • アプリを起動する
  • ユニティちゃんと見つめ合うと退勤打刻してユニティちゃんがジャンプ
  • Oculus Goをはずす

という打刻フローが完成します。効率とは無縁の、やさしいやさしい世界が実現しました。

Oculus Riftの場合

さすがに上のフローだと自分以外にとって価値が無なので、もうちょっと利便性がないと厳しいかもしれません。そこで「普通にPCで作業をしていて、ふと、横を向いたらユニティちゃんがいて打刻できる」という感じでやっていこうと思います。その場合はOculusGoでは厳しいのですが、幸い手元にOculus RiftとWindowsPCが転がっていたので、これ用に調整を入れました。

デスクトップ画面を表示する

UnityにはuDesktopDuplicationというプラグインがあり、これを使うとWindows PCのデスクトップをサクッとVR上に表示することができます。一瞬で解決。すごい。

休憩とかもできるようにする

利便性を高めるという話なので、出退勤以外にも休憩も入れられるようにします。「見つめ合って打刻」というのをやめ、普通に出勤ボタンや退勤ボタン、休憩開始ボタン等を配置しました。

これにより、こんな感じになります。

これだと作業終了即退勤が実現でき、なおかつユニティちゃんからねぎらいの言葉をもらえる、ほどよいバランスなのではないでしょうか。

まとめ

こんな感じで、人事労務 freee の打刻APIを使って「お気に入りのキャラクターと触れ合いつつ、気がついたら打刻できていた」という状況を生み出すことができました。あまりの打刻したさにうっかり休日出勤してもいい。*2

途中から「これVRじゃなくてARのほうがいい感じになるのでは…?」という考えが頭をよぎったのですが、残念ながらHoloLensやMagicLeapは手元に転がっていなかったので、手元に来たときに試したいと思います。みなさんもぜひ freee APIを使って気持ちを高ぶらせてください。

明日の記事は機械学習のスペシャリスト、スモールビジネスAIラボのKenji Usuiさんです、お楽しみに。

ライセンス

ユニティちゃんライセンス

この記事はユニティちゃんライセンス条項の元に提供されています

*1:実際のところ、Oculus Goではポジショントラッキングはできないので、はじめにユニティちゃんがカメラの方を向くように配置してあげれば、わざわざIKLookAtを設定せずとも、ユニティちゃんはカメラの方を向いてくれます。ですがそういうことではないんですよね。

*2:よく考えたらVRなので出勤しなくても打刻できる