20191127のUnityに関する記事は5件です。

「MonKey - Productivity Commands」のコマンド操作でUnity開発を効率化する

PONOS Advent Calendar 2019の2日目の記事です。

昨日は@honeniqさんのfish shellのはじめかた 2019冬でした。

はじめに

Asset Storeで販売されているアセット「MonKey - Productivity Commands」を導入することにより、コマンドでUnityの各種操作を実行できるようになります。
Unityエディタ上での開発速度の向上が期待できると感じたので、紹介したいと思います。

なお、

  • Unity 2019.2.1.12f1
  • MacOS 10.14.6

の環境で動作確認しています。

「MonKey - Productivity Commands」とは

assetstore.png
MonKey - Productivity Commands - Asset Store

  • 1シート$40
  • 対応するUnityバージョンは2017.4.1以上
  • コマンド操作で様々な機能を実行して開発できる。
  • デザイナー、アーティスト、プログラマのための130個以上のコマンドを用意。
  • 属性を使うことでカスタムコマンドの追加も可能。
  • 公式ドキュメント(MonKey - User Guide)

導入

  • Unity Asset Storeで購入後、プロジェクトにインポートしてください。
    (デモが不要であれば、Plugins/Monkey Commander/Demo!は削除して構いません)
  • インポートが完了するとGetting Startedのダイアログが起動しますが、使い始めるために追加設定は必要ないので、
    そのまま閉じてしまいましょう。
    getting_started.png
  • 以上で導入は完了です。非常に簡単ですね。
  • 「`」キーを入力すると、Monkeyのコマンドパレットが表示され、コマンドの入力が可能になります。
    monkey.png

基本的な使い方

  • コマンドパレットに検索文字列を入力するとコマンドの候補が表示されます。

    • 省略形のコマンドも用意されているので、頻繁に使うコマンドについてはこれを覚えると入力を短縮できます。
    • 一部のコマンドにはホットキーも用意されています。これらのホットキーはMonkeyのコマンドパレットを表示していなくても利用できます。
      select_command.png
  • 「↑」「↓」キーで候補の中から実行するコマンドを選択、「Enter」キーでコマンドを実行します。

    • コマンドによっては実行時に追加のパラメータ入力が必要になるものもあります。
    • 操作感はMacアプリケーションの「Alfred」やUnityアセットの「Quick Search」に近いので、これらのアプリケーションを利用している方は馴染みやすいと思います。

使用例:Imageコンポーネントを持つGameObjectの名前の末尾に「_IMG」を追加する

ここからはMonKeyを活用する一例を紹介します。
以下のようなシーンをサンプルに、Imageコンポーネントを持つすべてのGameObjectについて、それが「イメージを表示しているオブジェクト」であると認識しやすいように、名前の末尾に「_IMG」を追加してみましょう。
Screen_1.png
※Man、Woman、Cat、DogのGameObjectがそれぞれImageコンポーネントを持っています。

この処理を通常の手順で実現しようとする場合、名前の変更を1GameObjectずつ手作業で行わなくてはならず、非常に手間がかかります。しかし、MonKeyを使用することで、その手順を大幅に短縮することが可能となります。
今回の使用例で使用するコマンドは以下の2つです。

Select Scene Objects of Type
指定した型を持つGameObjectをすべて選択します。
省略コマンドとして「ST」が用意されています。

Rename Add Name Suffixes
選択されているすべてのGameObjectの名前の末尾に指定した文字列を連結します。
省略コマンドとして「RNS」が用意されています。

では、MonKeyを使用した場合の手順を見てみましょう。

  1. 「`」でMonKeyのコマンドパレットを開く。
  2. 「ST」を入力し、「Select Scene Objects of Type」コマンドを選択する。
    Screen_2.png
  3. 「Select Scene Objects of Type」コマンドの追加パラメータ入力として、型名の入力フィールドが表示されるので、「image」を入力してコマンドを実行する。
    Screen_3.png
  4. ここまでで、Imageコンポーネントを持つGameObjectだけをすべて選択できた状態となる。
    Screen_4.png
  5. 「`」で再度MonKeyのコマンドパレットを開く。
  6. 「RNS」を入力し、「Rename Add Name Suffixes」コマンドを選択する。
    Screen_5.png
  7. 「Rename Add Name Suffixes」コマンドの追加パラメータ入力として、連結する文字列の入力フィールドが表示されるので、「_IMG」を入力してコマンドを実行する。
    Screen_6.png
  8. 選択中のすべてのGameObjectの名前が「〜_IMG」の形に変更される。 Screen_7.png

以上です。
1個1個のGameObjectを選択して名前を編集する必要がないため、非常に効率的です。

おわりに

本来、複数の操作を組み合わせなければ実現できない処理でも、MonKeyを活用することで1コマンドで実行することができるようになります。
日頃頻繁に実行している処理ほど操作時間や手順が短縮されることによる恩恵は大きいので、

「昨日も同じ手順で面倒な処理をしていた」

と心当たりがある方は導入を検討してみてはいかがでしょうか。

明日は@blockさんです!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityをGitHub Actionsで動かす際にライセンス認証周りで注意するべき点

さんざん手こずったので初投稿です(やけくそ)。

GitHub ActionsでUnityのライセンス認証周りで撃沈しすぎた。
正しいライセンス認証の方法と注意点をここに記す。

GitHub Actionsのsecretsにulfファイルの内容を保存しているものとする。キーは"ulf"。

- run: |
    echo -n "$ULF" > unity.ulf
    /opt/Unity/Editor/Unity -nographics -batchmode -quit -logFile -manualLicenseFile ./unity.ulf || exit 0
  with:
    ULF: ${{ secrets.ulf }}

上記コードでライセンス認証は正しく行える。

Initiating legacy licensing module

 Load manual activation license file.

LICENSE SYSTEM [20191127 7:6:38] Load license file from: ./unity.ulf

LICENSE SYSTEM [20191127 7:6:38] Next license update check is after 2019-11-27T15:24:07


 License file loaded.

logFileの出力は上記の通り。
認証が正しく行えると「Next license update check is after ほげほげ」と出力される。

注意点0 echoのオプション

echo -n

echoコマンドのオプションに必ず-nを指定するべし。
これは最後の改行コードを出力しないという意味である。
何故か知らないが、一文字でも余計な文字が加わると認証にしくじる(10敗)。

注意点1 環境変数をダブルクォートでくくる

echo -n "$ULF"

環境変数の中身をechoしたいならばダブルクォートでくくる必要がある。
くくらない場合は単に$ULFと出力される(50敗)。

注意点2 環境変数を使う

環境変数ULF(名前は何でもいい)にsecrets.ulfを設定するべし。

echo -n ${{secrets.ulf}}

と仮に記述したらulfが複数行なのでエラー吐いてジョブが死ぬ(2敗)。

注意点3 ulfの中身は絶対に外部に見せない

ulfは機密情報なので明かしてはならない(0敗)。
デバッグ時に自分が見れる情報は全て他の人が見れると考えられる。
故に間違えてもそれに気付けない。コワイ!

感想・終わりに

一回5分~7分×60回つまり5~7時間無駄にした上で得た教訓を活かしてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity(C#),Python】API通信勉強メモ②Flaskでローカルサーバー立ち上げ

今回やること

この記事は前回の勉強の続きです。
【前回】:【Unity(C#)】API通信勉強メモ①

前回できなかったPostの処理を学びます。

なんもわからんなりの解釈が山盛りなのでマサカリ、オールオッケーです。

Flask

Flask(フラスク)は、プログラミング言語Python用の、軽量なウェブアプリケーションフレームワークである。標準で提供する機能を最小限に保っているため、自身を「マイクロフレームワーク」と呼んでいる。

Wikipediaより引用

今回はFlaskというPythonのウェブアプリケーションフレームワーク1を使用して
ローカルにアプリケーションサーバーを立て、Unity側からHTTPリクエスト(POST)を送る
までやってみようと思います。

おおよそ、参考リンクに沿って進めていきます。

【参考リンク】:Pythonと連携する方法

Flaskのインストール

$pip install flask

GETリクエスト

まずはFlaskで立てたローカルのサーバーにGETリクエストを送ってみます。

Python側の処理
from flask import Flask

app = Flask(__name__)


@app.route("/", methods=['GET'])
def index():
    return "HIKAKIN「ブンブン!ハローユーチューブ!」"


if __name__ == "__main__":
    app.debug = True
    app.run()

Unity側の処理は下記リンクから拝借しました。
【参考リンク】:UnityでHTTPに接続する

Unity側でHTTPリクエストを送るスクリプト
using System.Collections;
using UnityEngine.Networking;
using UnityEngine;

public class HTTPGet : MonoBehaviour {

    //接続するURL
    private const string URL = "http://localhost:5000/";

     void Start()
    {
        //コルーチンを呼び出す
        StartCoroutine("OnSend", URL);
    }

    IEnumerator OnSend(string url)
    {
        //指定したURLでGET
        UnityWebRequest webRequest = UnityWebRequest.Get(url);

        //URLに接続して結果が戻ってくるまで待機
        yield return webRequest.SendWebRequest();

        //エラーが出ていないかチェック
        if (webRequest.isNetworkError)
        {
            //通信失敗
            Debug.Log(webRequest.error);
        }
        else
        {
            //通信成功
            Debug.Log("Get" + " : "+webRequest.downloadHandler.text);
        }
    }
}

GetHIKAKIN.gif

成功しました。
①Python側(VSC)でデバッグを開始
②UnityでPlay
という順番です。

POSTリクエスト

次はFlaskで立てたローカルのサーバーにPOSTリクエストを送ってみます。
@app.route("/", methods=['POST', 'GET'])にPOSTを追加しただけです。

from flask import Flask

app = Flask(__name__)


@app.route("/", methods=['POST', 'GET'])
def index():
    return "HIKAKIN「ブンブン!ハローユーチューブ!」"


if __name__ == "__main__":
    app.debug = True
    app.run()

実際にやってみて思ったこととしては結局POSTとGETは何が違うんだよってことです。
この疑問に関しては下記リンクを見て一旦深く考えるのを止めることにしました。
【引用元】:GETとPOSTの違いについて

本当はGETでやるべきこともPOSTでできてしまうのです。
やろうと思えばすべての処理をPOSTで作れてしまうのです。
この辺りは思想的な話もあるので、何とも言えない部分です。

次回やること

Postの処理も上手くいったので次回はUnity側から入力した情報を登録 & ログインする機能を作っていきます。

とりあえずわかっていることとしては、
リクエストを送る際に情報を渡す方法として、
Unity側にWWW.Formが用意されていることです。

    //POSTする情報
    WWWForm form = new WWWForm();
    form.AddField("user_id", idInputField.text, Encoding.UTF8);
    form.AddField("password",passInputField.text, Encoding.UTF8);

上記のようにUnity側でログイン画面に入力したIDやパスワードをサーバーに送れる。。。はずです。


やりました→【Unity(C#),Python】API通信勉強メモ③簡易版ログイン機能の実装

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityにkintoneアプリに溜めたゲームスコア情報を表示させる

はじめに

Unityのゲーム内から、kintone環境のアプリ(ウェブデータベース)のレコード情報をREST APIで取得する方法を案内します。

この記事の例では、ゲームスコアを記録するkintoneアプリからデータを取得し、Unity内のオブジェクトにそのスコアリストのデータを反映させます。

連携イメージ.png

JSONを簡単に取り扱うためにSimpleJSONを使用します。
SimpleJSONの準備に関しては下記を参考にしてください:
https://qiita.com/will-yama/items/19078a905ef4207977e4

kintoneアプリの準備

まずゲームスコアを記録するアプリを作りましょう。
kintone環境を持っていない方はcybozu developer networkのこのページから1年間無料で使用できる開発者ライセンスのkintone環境を手に入れてください。

フィールドの設定

プレイヤー名とスコアを記録するために、文字列(1行)数値フィールドを配置します。
それぞれの設定画面で適当なフィールド名と、playernamescoreというフィールドコードを設定します。このフィールドコードは後ほどREST APIを叩くときに必要になります。
scoreApp.jpg

フォームの保存をしたら、『設定』タブをクリックします。

APIトークンの設定

『APIトークン』をクリックし、この記事の通りにAPIトークンを生成します。アクセス権はレコードの閲覧だけで大丈夫です。APIトークンを生成したら、設定の保存をします。

アプリの公開

アプリがkintoneユーザに利用できる状態にするために、『アプリを公開』ボタンをクリックします。すでに一度アプリの公開をしている場合、ボタンは『アプリを更新』と表示されます。とりあえず、ボタンを押しましょう。

データの追加

アプリの公開が出来たら、レコードの一覧画面に移動します。
データが入っていない状態なので、+ボタンをクリックして適当なダミーデータを追加しましょう。
Screen Shot 2019-11-26 at 20.10.50.png

ダミーデータを入力し終わった画面がこちらです。
Screen Shot 2019-11-26 at 21.15.38.png

Unityからkintoneアプリのデータを取得する

Unityの適当なオブジェクトにスクリプトを追加しましょう。
スクリプトからkintoneにアクセスする方法を案内します。

レコードを複数取得する

まず例として、全てのレコードを取得するコードです。
{サブドメイン名}{APIトークン}{アプリID}は適宜自分のkintone環境に合わせて設定してください。

testAPI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using SimpleJSON;

public class testAPI : MonoBehaviour
{
    const string domain = "{サブドメイン名}.cybozu.com";
    const string APItoken = "{APIトークン}";

    void Start()
    {
        string app = "{アプリID}";
        string query = System.Uri.EscapeDataString("order by playername desc");
        string fields = System.Uri.EscapeDataString("fields[0]") + "=" + System.Uri.EscapeDataString("$id")
        + "&" + System.Uri.EscapeDataString("fields[1]") + "=" + System.Uri.EscapeDataString("score")
        + "&" + System.Uri.EscapeDataString("fields[2]") + "=" + System.Uri.EscapeDataString("playername");

        StartCoroutine(
            getKintoneRecords(
                (JSONNode JSONresponse) => 
                {
                    HandleAPIresponse(JSONresponse);
                }, 
                app, 
                query, 
                fields
            )
        );
    }

    private IEnumerator getKintoneRecords(System.Action<JSONNode> callBack, string app, string query, string fields)
    {
        //APIリクエストの準備
        string APIparameters = "app=" + app + "&query=" + query + "&" + fields + "&totalCount=true";
        string RequestURL = "https://" + domain + "/k/v1/records.json?" + APIparameters;
        UnityWebRequest request = UnityWebRequest.Get(RequestURL);
        request.SetRequestHeader("X-Cybozu-API-Token", APItoken);

        //APIのリクエストを送信
        yield return request.SendWebRequest();

        //レスポンスをJSONNode型に格納
        string JSONstring = request.downloadHandler.text;
        Debug.Log("JSONstring--> " + JSONstring);
        JSONNode JSONnode = JSON.Parse(JSONstring);

        //JSONNode型のレスポンスをcallBackに渡す
        callBack(JSONnode);
    }

    private void HandleAPIresponse(JSONNode APIresponse)
    {
        //レスポンスを用いた処理
    }
}

レスポンスされるJSONの中身はこのような形になります。

{ 
   "records":[ 
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"302544"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ojisan man"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"7"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"304267"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ojisan man"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"2"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"331928"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"kerokero_B"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"6"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"294357"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"kero99powers"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"3"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"312555"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ken99"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"5"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"340232"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Unicorn_Z"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"9"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"300042"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Unicorn_Z"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"1"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"305288"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Magical Piano"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"10"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"255522"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"JJ88"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"8"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"244302"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"JJ88"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"4"
         }
      }
   ],
   "totalCount":"10"
}

このリクエストではqueryパラメータで名前順でレコード情報を取得するようにしました。queryパラメータを無視する場合、レコードID順に返ってきます。
fieldsパラメータにはJSONの中に含めて欲しいフィールドの情報を指定します。このパラメータを無視する場合、各レコードに対してかなり多くのフィールド情報が返ってくるので、JSONの読みやすさのためにも指定することをお勧めします。ちなみにですが、fieldsパラメータの中で指定した $id はレコード番号のフィールドを指しています。レコード番号のフィールドコードを代わりに記載しても同じ動きをします。

クエリを工夫する

スコアリストのデータを扱うので、下記の条件でレコード情報を取得したいと思います:
- スコアが高い順
- Top 3のみのスコア
- プレイヤー名とスコアの情報

Start()内のクエリをこのように変更します:

void Start()
{
    string app = "12";
    string query = System.Uri.EscapeDataString("order by score desc limit 3");
    string fields = System.Uri.EscapeDataString("fields[0]") + "=" + System.Uri.EscapeDataString("playername")
    + "&" + System.Uri.EscapeDataString("fields[1]") + "=" + System.Uri.EscapeDataString("score");  

    StartCoroutine(
        getKintoneRecords(
            (JSONNode JSONresponse) => 
            {
                HandleAPIresponse(JSONresponse);
            }, 
            app, 
            query, 
            fields
        )
    );
}

レスポンスのJSONは下記の通りになります:

{ 
   "records":[ 
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"340232"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Unicorn_Z"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"331928"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"kerokero_B"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"312555"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ken99"
         }
      }
   ],
   "totalCount":"10"
}

order by score desc で JSON内のレコード情報がスコアの値の降順で並びます。
limit 3 で、最初の3つのレコードの情報だけJSONに含まれるようにします。

オブジェクトへの応用

最後に、このデータをUnity内のオブジェクトに応用します。

オブジェクトの準備

まず、テキスト情報が調整しやすい下記の無料アセットを使います:

Menu Chalk Board
https://assetstore.unity.com/packages/3d/characters/menu-chalk-board-101989
screenshot of the Menu Chalk Board asset found on the Unity Asset Store

menuboardのprefabをシーンに入れます。
アセット内のCanvas配下のTitleMenuオブジェクトの詳細はインスペクタからいじることが可能です。
Titleオブジェクトは好みの内容に変え、Menuオブジェクト内のテキスト情報は全て消しましょう。デフォルトのテキストが少し読みにくかったので、私は下記のように設定をしました:
Screen Shot 2019-11-27 at 11.05.25.png

スクリプトの準備

この記事で活用していたスクリプトは適当なオブジェクトに追加していたと思いますが、menuboardCanvasオブジェクトに移動させましょう。

また、テキストの内容をスクリプトでいじるため、

using UnityEngine.UI;

をスクリプトの最初の方で宣言します。

最後に、まだ処理を記載していなかったHandleAPIresponse関数内に下記の内容を追記します。

private void HandleAPIresponse(JSONNode APIresponse)
{
    //kintoneアプリのレコード情報を変数に格納
    string FirstPlayersName = APIresponse["records"][0]["playername"]["value"].Value;
    string FirstPlayersScore = APIresponse["records"][0]["score"]["value"].Value;
    string SecondPlayersName = APIresponse["records"][1]["playername"]["value"].Value;
    string SecondPlayersScore = APIresponse["records"][1]["score"]["value"].Value;
    string ThirdPlayersName = APIresponse["records"][2]["playername"]["value"].Value;
    string ThirdPlayersScore = APIresponse["records"][2]["score"]["value"].Value;

    //『Menu』の名前を持つ子オブジェクトのTextコンポーネントの内容を上書きする
    GameObject CanvasMenu = this.gameObject.transform.Find("Menu").gameObject;
    Text CanvasMenuText = CanvasMenu.GetComponent<Text>();
    CanvasMenuText.text = "1. " + FirstPlayersName + "   " + FirstPlayersScore + "p\n"
                        + "2. " + SecondPlayersName + "   " + SecondPlayersScore + "p\n"
                        + "3. " + ThirdPlayersName + "   " + ThirdPlayersScore + "p";
}

シーンをplayしてみて、下記のようにスコア情報がkintoneから取得出来たら成功です。
Screen Shot 2019-11-27 at 11.09.12.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kintoneアプリに溜めたゲームスコア情報をUnity内に表示させる

はじめに

Unityのゲーム内から、kintone環境のアプリ(ウェブデータベース)のレコード情報をREST APIで取得する方法を案内します。

この記事の例では、ゲームスコアを記録するkintoneアプリからデータを取得し、Unity内のオブジェクトにそのスコアリストのデータを反映させます。

連携イメージ.png

JSONを簡単に取り扱うためにSimpleJSONを使用します。
SimpleJSONの準備に関しては下記を参考にしてください:
https://qiita.com/will-yama/items/19078a905ef4207977e4

kintoneアプリの準備

まずゲームスコアを記録するアプリを作りましょう。
kintone環境を持っていない方はcybozu developer networkのこのページから1年間無料で使用できる開発者ライセンスのkintone環境を手に入れてください。

フィールドの設定

プレイヤー名とスコアを記録するために、文字列(1行)数値フィールドを配置します。
それぞれの設定画面で適当なフィールド名と、playernamescoreというフィールドコードを設定します。このフィールドコードは後ほどREST APIを叩くときに必要になります。
scoreApp.jpg

フォームの保存をしたら、『設定』タブをクリックします。

APIトークンの設定

『APIトークン』をクリックし、この記事の通りにAPIトークンを生成します。アクセス権はレコードの閲覧だけで大丈夫です。APIトークンを生成したら、設定の保存をします。

アプリの公開

アプリがkintoneユーザに利用できる状態にするために、『アプリを公開』ボタンをクリックします。すでに一度アプリの公開をしている場合、ボタンは『アプリを更新』と表示されます。とりあえず、ボタンを押しましょう。

データの追加

アプリの公開が出来たら、レコードの一覧画面に移動します。
データが入っていない状態なので、+ボタンをクリックして適当なダミーデータを追加しましょう。
Screen Shot 2019-11-26 at 20.10.50.png

ダミーデータを入力し終わった画面がこちらです。
Screen Shot 2019-11-26 at 21.15.38.png

Unityからkintoneアプリのデータを取得する

Unityの適当なオブジェクトにスクリプトを追加しましょう。
スクリプトからkintoneにアクセスする方法を案内します。

レコードを複数取得する

まず例として、全てのレコードを取得するコードです。
{サブドメイン名}{APIトークン}{アプリID}は適宜自分のkintone環境に合わせて設定してください。

testAPI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using SimpleJSON;

public class testAPI : MonoBehaviour
{
    const string domain = "{サブドメイン名}.cybozu.com";
    const string APItoken = "{APIトークン}";

    void Start()
    {
        string app = "{アプリID}";
        string query = System.Uri.EscapeDataString("order by playername desc");
        string fields = System.Uri.EscapeDataString("fields[0]") + "=" + System.Uri.EscapeDataString("$id")
        + "&" + System.Uri.EscapeDataString("fields[1]") + "=" + System.Uri.EscapeDataString("score")
        + "&" + System.Uri.EscapeDataString("fields[2]") + "=" + System.Uri.EscapeDataString("playername");

        StartCoroutine(
            getKintoneRecords(
                (JSONNode JSONresponse) => 
                {
                    HandleAPIresponse(JSONresponse);
                }, 
                app, 
                query, 
                fields
            )
        );
    }

    private IEnumerator getKintoneRecords(System.Action<JSONNode> callBack, string app, string query, string fields)
    {
        //APIリクエストの準備
        string APIparameters = "app=" + app + "&query=" + query + "&" + fields + "&totalCount=true";
        string RequestURL = "https://" + domain + "/k/v1/records.json?" + APIparameters;
        UnityWebRequest request = UnityWebRequest.Get(RequestURL);
        request.SetRequestHeader("X-Cybozu-API-Token", APItoken);

        //APIのリクエストを送信
        yield return request.SendWebRequest();

        //レスポンスをJSONNode型に格納
        string JSONstring = request.downloadHandler.text;
        Debug.Log("JSONstring--> " + JSONstring);
        JSONNode JSONnode = JSON.Parse(JSONstring);

        //JSONNode型のレスポンスをcallBackに渡す
        callBack(JSONnode);
    }

    private void HandleAPIresponse(JSONNode APIresponse)
    {
        //レスポンスを用いた処理
    }
}

レスポンスされるJSONの中身はこのような形になります。

{ 
   "records":[ 
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"302544"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ojisan man"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"7"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"304267"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ojisan man"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"2"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"331928"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"kerokero_B"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"6"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"294357"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"kero99powers"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"3"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"312555"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ken99"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"5"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"340232"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Unicorn_Z"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"9"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"300042"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Unicorn_Z"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"1"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"305288"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Magical Piano"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"10"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"255522"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"JJ88"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"8"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"244302"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"JJ88"
         },
         "$id":{ 
            "type":"__ID__",
            "value":"4"
         }
      }
   ],
   "totalCount":"10"
}

このリクエストではqueryパラメータで名前順でレコード情報を取得するようにしました。queryパラメータを無視する場合、レコードID順に返ってきます。
fieldsパラメータにはJSONの中に含めて欲しいフィールドの情報を指定します。このパラメータを無視する場合、各レコードに対してかなり多くのフィールド情報が返ってくるので、JSONの読みやすさのためにも指定することをお勧めします。ちなみにですが、fieldsパラメータの中で指定した $id はレコード番号のフィールドを指しています。レコード番号のフィールドコードを代わりに記載しても同じ動きをします。

クエリを工夫する

スコアリストのデータを扱うので、下記の条件でレコード情報を取得したいと思います:
- スコアが高い順
- Top 3のみのスコア
- プレイヤー名とスコアの情報

Start()内のクエリをこのように変更します:

void Start()
{
    string app = "12";
    string query = System.Uri.EscapeDataString("order by score desc limit 3");
    string fields = System.Uri.EscapeDataString("fields[0]") + "=" + System.Uri.EscapeDataString("playername")
    + "&" + System.Uri.EscapeDataString("fields[1]") + "=" + System.Uri.EscapeDataString("score");  

    StartCoroutine(
        getKintoneRecords(
            (JSONNode JSONresponse) => 
            {
                HandleAPIresponse(JSONresponse);
            }, 
            app, 
            query, 
            fields
        )
    );
}

レスポンスのJSONは下記の通りになります:

{ 
   "records":[ 
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"340232"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"Unicorn_Z"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"331928"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"kerokero_B"
         }
      },
      { 
         "score":{ 
            "type":"NUMBER",
            "value":"312555"
         },
         "playername":{ 
            "type":"SINGLE_LINE_TEXT",
            "value":"ken99"
         }
      }
   ],
   "totalCount":"10"
}

order by score desc で JSON内のレコード情報がスコアの値の降順で並びます。
limit 3 で、最初の3つのレコードの情報だけJSONに含まれるようにします。

オブジェクトへの応用

最後に、このデータをUnity内のオブジェクトに応用します。

オブジェクトの準備

まず、テキスト情報が調整しやすい下記の無料アセットを使います:

Menu Chalk Board
https://assetstore.unity.com/packages/3d/characters/menu-chalk-board-101989
screenshot of the Menu Chalk Board asset found on the Unity Asset Store

menuboardのprefabをシーンに入れます。
アセット内のCanvas配下のTitleMenuオブジェクトの詳細はインスペクタからいじることが可能です。
Titleオブジェクトは好みの内容に変え、Menuオブジェクト内のテキスト情報は全て消しましょう。デフォルトのテキストが少し読みにくかったので、私は下記のように設定をしました:
Screen Shot 2019-11-27 at 11.05.25.png

スクリプトの準備

この記事で活用していたスクリプトは適当なオブジェクトに追加していたと思いますが、menuboardCanvasオブジェクトに移動させましょう。

また、テキストの内容をスクリプトでいじるため、

using UnityEngine.UI;

をスクリプトの最初の方で宣言します。

最後に、まだ処理を記載していなかったHandleAPIresponse関数内に下記の内容を追記します。

private void HandleAPIresponse(JSONNode APIresponse)
{
    //kintoneアプリのレコード情報を変数に格納
    string FirstPlayersName = APIresponse["records"][0]["playername"]["value"].Value;
    string FirstPlayersScore = APIresponse["records"][0]["score"]["value"].Value;
    string SecondPlayersName = APIresponse["records"][1]["playername"]["value"].Value;
    string SecondPlayersScore = APIresponse["records"][1]["score"]["value"].Value;
    string ThirdPlayersName = APIresponse["records"][2]["playername"]["value"].Value;
    string ThirdPlayersScore = APIresponse["records"][2]["score"]["value"].Value;

    //『Menu』の名前を持つ子オブジェクトのTextコンポーネントの内容を上書きする
    GameObject CanvasMenu = this.gameObject.transform.Find("Menu").gameObject;
    Text CanvasMenuText = CanvasMenu.GetComponent<Text>();
    CanvasMenuText.text = "1. " + FirstPlayersName + "   " + FirstPlayersScore + "p\n"
                        + "2. " + SecondPlayersName + "   " + SecondPlayersScore + "p\n"
                        + "3. " + ThirdPlayersName + "   " + ThirdPlayersScore + "p";
}

シーンをplayしてみて、下記のようにスコア情報がkintoneから取得出来たら成功です。
Screen Shot 2019-11-27 at 11.09.12.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む