勉強不足で至らんブログ

勉強不足ですが色々と書いていきます。

失敗LT祭! 〜俺の話を聞いてくれ〜 登壇してきました。

【ついに今日!】失敗LT祭! 〜俺の話を聞いてくれ〜 - connpass

にてUnityのCI/CD周りについて発表してきました。

初LTだったのでドチャクソ緊張して早口になってました。

 

www.slideshare.net

 

幅広くエンジニアが集まっている場所だったので詳細は省かせてもらってます。Cloud CI/CDいいっすね!ってふわっと話せたかなって思ってます。

詳細は以下記事

qiita.com

 

UnityでCI/CDの選択肢をどう増やすか、増やす方法についてLT & 記事書いてます。何か参考になれば幸いです。

 

スライドでサラッと触れていますが

can build android with fastlane on CircleCI by MizoTake · Pull Request #8 · GabLeRoux/unity3d-ci-example · GitHub

 

Unity + fastlaneを使ったCircleCI上のandroidビルドが可能になりましたのでプルリクエストでの公開状態となっています。(2019/02/21)

 

fastlaneであれば配信周りも自由度が広がるので是非とも参考にしていただけたらと思います。

 

iOSは頭の中にフローがあるものの手元に環境がないので…そのうち…です…

CircleCIでUnityのTest&Buildを雰囲気理解で走らせた

毎度毎度の自己Qiita転載でございます。 CircleCIでUnityのTest&Buildを雰囲気理解で走らせた

CircleCIを使ってみたかった

CircleCIなら制限時間はありますが無料でCI環境が使えて、GitHubから直接連携ができるので楽そう! またSlack連携なども情報はたくさんあるので応用は色々とできそう!

…Unityで動かす情報すくないな?ってことで触ってみました。

さて今回参考にしたRepositoryは2つです

上記からunity3d-ci-exampleをforkして

を作ってCircleCI連携を試してみたものの、そのままではうまく行かなかったです。 なので、どう解決したのかをunity3d-ci-exampleをベースに話します。

セットアップ

CircleCIやDockerの登録やらなんやらの説明は省きます。 https://circleci.com/

基本的には公式サイトに行ってGitHubやBitBucketの連携登録をすれば簡単にできるかと思います。

https://www.docker.com/

MacLinuxの方はすんなりセットアップできると思います、Windowsの方はセットアップして起動できてなさそうであればhyper-vという項目をONにしないといけないのでこちらを参考にしてみてください。

unity3d-ci-exampleで最初わからなかったのがREADMEにあるHow to activateという項目… 要するにUnityのLicense認証なのですが少し手間でした。

またこの段階からDockerが必要となります。Docker初心者ですが調べつつ何とかなったのでコマンドも覚えているものは残しておきます。 今回使用するContainerはgableroux/unity3dです。

DockerHubからimageを落として来ないといけないので落としてきます

docker pull gableroux/unity3d

落とせたかどうかは

docker images

で確認できます。

落とせていたら

UNITY_VERSION=2018.2.3f1
docker run -it --rm \
-e "UNITY_USERNAME=username@example.com" \
-e "UNITY_PASSWORD=example_password" \
-e "TEST_PLATFORM=linux" \
-e "WORKDIR=/root/project" \
-v "$(pwd):/root/project" \
gableroux/unity3d:$UNITY_VERSION \
bash

UNITY_VERSIONやUNITY_USERNAME、UNITY_PASSWORDは適宜変えましょう。 何をしているかというとgableroux/unity3dを起動させるときに環境変数として値を渡しているみたいです。 コマンドの処理が終わるとDockerが起動してDocker上のbashが操作できるようになります。 一回Dockerから出たい時は

exit

だけ打てば出れます。再度入る時は入った時と同じコマンドでいいと思います。 次にDocker上で

xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-logFile \
-batchmode \
-username "$UNITY_USERNAME" -password "$UNITY_PASSWORD"

Unityの起動を行いLicense認証をしようと動きます。 うまくいくと

LICENSE SYSTEM [2017723 8:6:38] Posting <?xml version="1.0" encoding="UTF-8"?><root><SystemInfo><IsoCode>en</IsoCode><UserName>[...]

というxmlがログに現れるのでunity3d.alfという名前でホストのOSに保存しましょう。 次に https://license.unity3d.com/manual をホストのOSで開いてunity3d.alfを選択して送信します。 するとUnity_v2018.x.ulfというファイルがダウンロードされます。 How to activate的には、ここまでで区切りですがCircleCIの場合はもう少しセットアップが必要です。

Unity_v2018.x.ulfというのがUnityのLicenseあるよ!という証明するファイルになるのですが、そのままgit管理してしまうのは危険かもしれません。PlusライセンスやProライセンスだと他の人がアクティベートできてしまうからです。(たぶん) そこで自分でKEYを決めて暗号化をかけてCircleCI上で復号化して使おうじゃないか!という流れです。

次もホストOSでの処理になります。

export KEY=insert-your-strong-generated-key-here
openssl aes-256-cbc -e -in ci/Unity_v2018.x.ulf -out ci/Unity_v2018.x.ulf-cipher -k $KEY
git add ci/Unity_v2018.x.ulf-cipher
git commit -m "Add encrypted Unity_v2018.x.ulf using openssl aes-256-cbc KEY"

insert-your-strong-generated-key-hereを好きな文字列に置き換えて覚えておいてください。後々CircleCIの環境変数として保存します。 そして暗号化されたファイルがUnity_v2018.x.ulf-cipherとなります。間違ってもUnity_v2018.x.ulfを追加しないように気をつけてください。 そのためリポジトリとは別のディレクトリで作業してUnity_v2018.x.ulf-cipherのみリポジトリに追加する方が安全かもしれません。

CircleCIに環境変数を登録する

先ほど暗号化に使ったKEYをCircleCIに登録します。 CircleCIとリポジトリを連携するとリポジトリに対して設定が行えるようになります。設定画面にある 名称未設定.png

Enviroment Variablesの項目があり選択すると画像にはないですが右上にAdd VariablesというボタンがあるのでKEYという名前で環境変数を登録しましょう。

セットアップは終わりです。

config.ymlを書くぞ

CicleCIで処理して欲しい項目をyml形式で書くことになります。 保存場所はリポジトリのルートに.circlciフォルダを作って配下にconfig.ymlを追加してください。 今回使用したのは以下のymlです。(unity3d-ci-sampleのものをベースにしました)

version: 2
references:
  docker_image: &docker_image
    docker:
      - image: gableroux/unity3d:2018.2.6f1
  setup_unity_license_env_var: &setup_unity_license_env_var
    command: |
      mkdir -p /root/.cache/unity3d
      mkdir -p /root/.local/share/unity3d/Unity/
      openssl version
      openssl aes-256-cbc -md md5 -d -in ./ci/Unity_v2018.ulf-cipher -out /Unity_v2018.ulf -k $KEY
      export UNITY_LICENSE_CONTENT=`cat /Unity_v2018.ulf`
      echo "$UNITY_LICENSE_CONTENT" | tr -d '\r' > "/root/.local/share/unity3d/Unity/Unity_lic.ulf"
  remove_license_file: &remove_license_file
    command: |
      rm /Unity_v2018.ulf
      rm /root/.local/share/unity3d/Unity/Unity_lic.ulf
jobs:
  test_editmode:
    <<: *docker_image
    steps:
      # TODO: Add git to unity image so this is not required anymore
      # this will prevent following error on 'checkout' step:
      # Either git or ssh (required by git to clone through SSH) is not installed in the image. Falling back to CircleCI's native git client but the behavior may be different from official git. If this is an issue, please use an image that has official git and ssh installed.
      - run:
          command: apt-get update && apt-get install -y git && git --version
      - checkout
      - run:
          <<: *setup_unity_license_env_var
      - run:
          environment:
            TEST_PLATFORM: editmode
          command: |
            chmod -R 755 ./ci/test.sh
            ./ci/test.sh
      - run:
          <<: *remove_license_file
      - store_artifacts:
          path: '$(pwd)/$TEST_PLATFORM-results.xml'
          destination: '$TEST_PLATFORM-results.xml'
  test_playmode:
    <<: *docker_image
    steps:
      - run:
          command: apt-get update && apt-get install -y git && git --version
      - checkout
      - run:
          <<: *setup_unity_license_env_var
      - run:
          environment:
            TEST_PLATFORM: playmode
          command: |
            chmod -R 755 ./ci/test.sh
            ./ci/test.sh
      - run:
          <<: *remove_license_file
      - store_artifacts:
          path: '$(pwd)/$TEST_PLATFORM-results.xml'
          destination: '$TEST_PLATFORM-results.xml'
  build_StandaloneWindows:
    <<: *docker_image
    steps:
      - run:
          command: |
            apt-get update && apt-get install -y git zip && git --version
      - checkout
      - run:
          <<: *setup_unity_license_env_var
      - run:
          environment:
            BUILD_TARGET: StandaloneWindows
          command: |
            chmod -R 755 ./ci/build.sh
            ./ci/build.sh
      - run:
          <<: *remove_license_file
      - store_artifacts:
          path: './Builds/'
  build_StandaloneOSX:
    <<: *docker_image
    steps:
      - run:
          command: |
            apt-get update && apt-get install -y git zip && git --version
      - checkout
      - run:
          <<: *setup_unity_license_env_var
      - run:
          environment:
            BUILD_TARGET: StandaloneOSX
          command: |
            chmod -R 755 ./ci/build.sh
            ./ci/build.sh
      - run:
          <<: *remove_license_file
      - store_artifacts:
          path: './Builds/'
workflows:
  version: 2
  test_and_build:
    jobs:
      - build_StandaloneWindows
      - build_StandaloneOSX
      - test_editmode

これが コメント 2019-02-07 233248.jpg こうなります。

少し分解して解説を入れます。 setup_unity_license_env_varだけを見ます。

# なんでこれ追加したんだったか…無くて怒られたような…
mkdir -p /root/.cache/unity3d
mkdir -p /root/.local/share/unity3d/Unity/
openssl version
# 暗号化したファイルを復号化する処理
openssl aes-256-cbc -md md5 -d -in ./ci/Unity_v2018.ulf-cipher -out /Unity_v2018.ulf -k $KEY
export UNITY_LICENSE_CONTENT=`cat /Unity_v2018.ulf`
# 復号化した中身をファイルとしてUnity配下に保存
echo "$UNITY_LICENSE_CONTENT" | tr -d '\r' > "/root/.local/share/unity3d/Unity/Unity_lic.ulf"

復号化した中身をファイルとしてUnity配下に保存をしないと自分の場合動きませんでした。unity3d-ci-exampleにはなかったのですがwtanaka/docker-unity3dにはその記述があり書いてみたらライセンスが通りました。。。先駆者たちに感謝っ・・・・!圧倒的感謝っ・・・・!

あとはunity3d-ci-exampleのciフォルダ配下の.shに権限与えて動かしているだけです。 .shの中身はunityをコマンドで動かしているだけなので色々といじれるとは思います。 編集したり調べる際にはコマンド引数のリファレンスにだいたい乗っているので確認してみてください。

Testは基本的に成功知れていればいいと思いますがBuildは成果物がダウンロードできないと意味がないのでダウンロードする用意をします。 CircleCIにはArtifactsという機能がありArtifactsに保存したい成果物を登録しておけば長期的に保存ができるものになります。

unity3d-ci-sampleもBuildフォルダというものを作っておりフォルダごと保存するようになっています。 jobの詳細画面?でArtifactsが確認できます。 コメント 2019-02-07 231417.jpg

フォルダを成果物としているのでかなりバラバラになっています。(-customBuildPathの環境変数登録してなくてそのままなのはスルー) 1つ1つダウンロードしてられないのでzipにまとめます。

build_StandaloneWindows:
    <<: *docker_image
    steps:
      - run:
          command: |
            apt-get update && apt-get install -y git zip && git --version
      - checkout
      - run:
          <<: *setup_unity_license_env_var
      - run:
          environment:
            BUILD_TARGET: StandaloneWindows
          command: |
            chmod -R 755 ./ci/build.sh
            ./ci/build.sh
      - run:
          <<: *remove_license_file
      - store_artifacts:
          path: './Builds/'

一部抜粋ですが、apt-getでgitのついでにzipも一緒にインストールしておきます。最後の方にartifactsに登録しているのがわかると思います。 そしてbuild.shの一部を編集します。

if [ $UNITY_EXIT_CODE -eq 0 ]; then
  echo "Run succeeded, no failures occurred";
  cd $BUILD_PATH
  zip archive -r .
  cd /root/project
elif [ $UNITY_EXIT_CODE -eq 2 ]; then
  echo "Run succeeded, some tests failed";
elif [ $UNITY_EXIT_CODE -eq 3 ]; then
  echo "Run failure (other failure)";
else
  echo "Unexpected exit code $UNITY_EXIT_CODE";
fi

成功したときにartifactsに登録するディレクトリに移動してzip処理をします。そして後処理があるのでディレクトリをもとの位置に戻ります。 上記の編集を加えると

コメント 2019-02-07 231229.jpg

archive.zipになっているのがわかります。archive.zipを落として解答すればビルド結果が確認できるかと思います。

まとめ

CircleCIで一旦UnityのTestとBuildを動かす話はここまでです。Sampleをあげてくれている方がおりますがそのまま動かない場合があったので今回記事に残しておきます。 そのうちAndroidiOSのビルドもCircleCIでやりたいと思ってはいます…ネイティブのビルド自体はfastlaneとかでやっている人をみるので応用すればいけるかな?と思ってますがDocker知識が地味に必要そうなのでやる気次第ですぐにやるかもしれない…しないかもしれない… CircleCIやDockerは完全に初心者でやっているのでもっと効率のいい書き方とかあるよって話があれば教えて欲しいです!

転職ドラフトを使って転職を決めた

 

転職ドラフトを使って転職が決まりました。

Amazonギフトカードが欲しいので、こちらの記事は転職ドラフト体験談投稿キャンペーンに参加しています。

job-draft.jp

 

転職ドラフト以外も転職サービスは使ってはいましたのでそれを含めつつ記事に残そうかと…

転職のきっかけ諸々は別途退職エントリーを書いてみたいので書いてそのうち公開しようかと計画中

公開しました

チームラボを退職しました - 勉強不足で至らんブログ

 

転職ドラフトに登録したきっかけ

最初は自分の市場価値は今の会社からの給与で正当なのだろうか?と疑問になったところから始まった。でも市場価値なんてわからないし…という時に大学の先輩が転職を決めていたので相談をさせて頂いた。

そこで、自分で職務経歴などを書いてオファーが貰える「転職ドラフト」に登録してみて考えてみたらいいんじゃないかとアドバイスをもらい転職する思いは強くなかったが登録をしてみるか…くらいの気持ちでいたと思う。

その当時、別に自分で探して

www.green-japan.com

というのも登録していた。こっちも職務経歴のようなものを書いて登録するもの。転職ドラフト違ってオファー額は出ず、企業の方が「スカウト」「面談確約スカウト」などで声がかかって直接話をするというもの。ここでの面談も何回かしたが自分はうまくマッチングできずに終わってしまった。

 

ドラフト期間

自分は転職期間中2回ドラフトに参加した。

1回目は1件指名を頂けた。当時、希望年収をあえて書かずに登録していた。市場価値を知るため。そこで思った以上の額を提示されて面談をしたが、自分がやりたいこととは少し違ったのもありお断りをさせて頂いた。

2回目は3件指名を頂けた。1回目を基準に希望年収を書いていたら、その通りいただけたり、それ以上の額の提示があり驚いた。しかし、自分が行きたいのはゲーム業界だったのもありゲーム業界でない2件の企業にはお断りをさせて頂いた。そして、ゲーム業界の企業と面談をすることに

 

転職を決めた企業との面談

かなり話が合っていたと思う。自分のやりたいことや出来るスキルも活かせそうだと思えたし、自分が挑戦したいことにも「いいね!」という具合に話が弾んでいた気がする。特に個人制作を注目して話を振ってもらえたりして、話せたのはうれしかった。さらに面談をした方とTwitterをその場で交換することになったのは自分の中で面白かった。正直内心今後のツイート気にしなきゃいけないかな?とか思っていたが、僕は気にせず今も元気にツイートをしています。

 

転職に使ったツール

基本的にはGoogle Driveで管理をしてGoogle Documentで履歴書と職務経歴書を作って管理していた。

f:id:MakeTake:20190211105910j:plain

みたいな感じです。GitHubなどはリンクを貼って、企業にURLを送ったりpdfに変換して送信するだけの状態にしていた。あとは志望動機云々は書かなかった。企業によって変えるのが手間だったのもあり汎用的なものにしていた。

印刷を求められたときは普通の印刷用紙で特段問題はなかった。(実は問題があったとかだと申し訳ないです。すみません。。。)

ちなみにGoogle Documentに履歴書テンプレートがあって、編集したものなので誰でも簡単に作れる気がする。

職務経歴書Google Documentで作っていた。どこかから拾ったテンプレートを編集したものだったので割愛。

 

そしてGoogle Slideで過去の制作物をまとめていた。

f:id:MakeTake:20190209135232j:plain

動画があるものは動画のリンクを貼ってみれるようにして、学生時代のものも含めて作っていた。

 

基本的にGoogle Driveで管理することでPCがなくてもスマホでプレゼンできるのは強みだった。さらにGoogleのoffice系は編集履歴が追えるので何かあったときも対応が楽…

 

転職ドラフトを使ってみて

レジュメを書かないとドラフトに参加できないが、きちんとレジュメのレビューが入って自分がやってきたことを振り返る機会にもなった。

そして、自分がやってきたことに具体的な数字で価値が見えるのは明快でうれしい。 

最後に

転職活動中に色々な人に相談に乗ってもらいました。ありがとうございました!!志望通りの業界に行けます。3月は丸々有給消化で暇を持て余して過ごします!

 

GASから.assetを作ってプルリクを投げる

たまにやってる自分のQiita転載です。

GASから.assetを作ってプルリクを投げる - Qiita

Google Spread Sheetで文言とか持ってくるの…めんどいな

Google Spread Sheetで文言を管理することがあると思います。もちろん、Excel等もあると思いますが今回はSpread SheetとGASの連携による話になります。

Google Spread Sheetで文言管理するのはいいけど文字を打って写したり、GASを使ってファイルにしてDriveに保存してダウンロードする。などの手順を踏むかと思います。今回はそれすらもめんどくさくなったエンジニアの話です。

そんなこんなで、GASもapiを叩くことができるならGitHubapi叩けばよくね!?って思ったら最高に用途にあったライブラリを作っている方がいらっしゃいました。 GitHub API を GAS でいい感じで叩くためのライブラリを作った (未完)

最高です。GAS用のライブラリなのでSpread Sheetと直結です。

先に.gsが見たい方はこちら https://github.com/MizoTake/CreateAssetsFromGAS

UnityのSampleリポジトリはこちら https://github.com/MizoTake/CreateAssetsFromGASUnitySample

以降は解説に入りますが、GASのファイル作成やUnityのファイル作成など基礎的なところには触れていませんのでご了承ください。

導入する

GASのライブラリ何それおいしいの?ってところから自分は始まりました。おいしかったです(楽さ加減が)

キャプチャ.PNG

GASを開いたらリソースという項目があるのでクリックするとライブラリという項目が出るのでクリックします。

すると

キャプチャ.PNG

テキストフィールドに今回使用するGitHubのライブラリキーとなる1F4yn329GjHKdcXu9nm0uBZHFo40NGRUF8dfZCTHM1KjXpOXYr2BzIIcJを入力します。(GitHubのREADME.mdにもあります)

あとは、バージョンを最新に設定すれば終わりです。

Unityで.assetを作る

要するにScriptableObjectです。

第4章 ScriptableObject

等を参考に作ってみてください。 今回はSampleのプロジェクトを作成したので、それをベースにお話しします。 https://github.com/MizoTake/CreateAssetsFromGASUnitySample/blob/master/Assets/Message.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Message : ScriptableObject
{
    public Talk[] flow;

    [System.Serializable]
    public class Talk
    {
        public int id;
        public string name;
        public string message;
    }
}

キャプチャ.PNG

Signboardということで看板に話しかけた時に表示するメッセージだと仮定しておきます。

Inspectorには上図のように表示されます。 IdとかMessageは適当に入れています。

これで、.assetにプルリクを送る準備ができました。 何故先に作っておくかと言うと.metaを作っておきたいからです。

GASから.assetを作る

.assetを作るためにはScriptableObjectのテキスト情報を知らねばならないのでテキストエディタで開きます。 https://github.com/MizoTake/sLowZoo/blob/master/Assets/sLowZoo/Data/MessageSection/Signboard.asset

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInternal: {fileID: 0}
  m_GameObject: {fileID: 0}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 3db36c1731914ec4496d0d83b3360bc7, type: 3}
  m_Name: Signboard
  m_EditorClassIdentifier: 
  flow:
  - id: 0
    name: 
    message: "\u770B\u677F\u3060\u3088"
  - id: 0
    name: 
    message: "\u770B\u677F\u304B\u3082\u3057\u308C\u306A\u3044"
  - id: 0
    name: 
    message: "\u304A\u3084\u2026\u770B\u677F\u306E\u69D8\u5B50\u304C\u2026"

Sceneとかの構成と同じくyamlのようです。ここから編集が必要な情報はflow:以降の文字列になると思います。 ただし、日本語はutf16に変換されているようなのでgasでも変換処理が必要そうです。

処理の一部抜粋をしつつ少し解説します。

まず、.assetのflow:前の文字列を取得します。gasの文字列操作で頑張るとなんとかなります。

var githubUrl = 'https://raw.githubusercontent.com/MizoTake/CreateAssetsFromGASUnitySample/master/Assets/Signboard.asset'
// プルリク対象のテキスト情報をgithubからrawで持ってくる
var txtBlob = UrlFetchApp.fetch(githubUrl)
// "flow:"という文字列を検索し、indexを取得
var index = txtBlob.getContentText().lastIndexOf('flow:')
// flow: + 改行コード = 6とし、flow:以降の文字列を取得
var deleteTarget = txtBlob.getContentText().slice(index + 6)
// ScriptableObjectの参照情報である部分をheaderとして取得
var header = txtBlob.getContentText().replace(deleteTarget, '')

上記のコードでScriptableObjectのflow:までの文字列を取得できたので、中身となるidなどをSpread Sheetから取得し作成します。

まず使用するSpreadSheetはこちらです。 会話 キャプチャ.PNG

これを踏まえて以下の処理を使用します。

var targetName = 'Signboard'
var path = 'Assets/'

var sheet = SpreadsheetApp.openById('1KsmJTKSRGXMd1YdtJDLPzkp6xvDskaXRezc7pyq2WVQ').getSheetByName(targetName)
var fileName = targetName + '.asset'

var result = ""
// idの列を取得
var idRange = sheet.getRange(2, index('id'), sheet.getLastRow(), 1).getValues()
// nameの列を取得
var nameRange = sheet.getRange(2, index('name'), sheet.getLastRow(), 1).getValues()
// messageの列を取得
var messageRange = sheet.getRange(2, index('message'), sheet.getLastRow(), 1).getValues()
idRange.map(function(id, idIndex) {
  id.map(function(item, index) {
    if (item != "" && typeof item !== undefined) {
      // yamlのformatに合わせる
      var name = ''
      if(nameRange[idIndex] != '') {
        // escape関数でutf16に変換
        name = "\"" + escape(nameRange[idIndex]).split('%').join('\\') + "\""
      } 
      result += "    name: " + name + "\n"
      result += "    message: \"" + escape(messageRange[idIndex]).split('%').join('\\') + "\"\n"
    }
  });
});

function index(target) {
  var contentTitles = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]
  return contentTitles.indexOf(target) + 1
}

以上までやるとheaderとresultを結合すれば、.assetの中身がgasで作れちゃいます。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInternal: {fileID: 0}
  m_GameObject: {fileID: 0}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 3db36c1731914ec4496d0d83b3360bc7, type: 3}
  m_Name: Signboard
  m_EditorClassIdentifier: 
  flow:
  - id: 1
    name: 
    message: "\u770B\u677F\u3060\u3088"
  - id: 2
    name: 
    message: "\u770B\u677F\u304B\u3082\u3057\u308C\u306A\u3044"
  - id: 3
    name: 
    message: "\u304A\u3084\u2026\u770B\u677F\u306E\u69D8\u5B50\u304C\u2026"
  - id: 4
    name: 
    message: "\u770B\u677F\u3067\u3059\u3088"

結合結果です。

あとは、ライブラリさんに頼ってプルリクを出すだけです。

Githubにプルリクを出す

冒頭で紹介したライブラリを使用するには

  • UserName
  • MailAddress
  • Personal access tokens

が必要となります。

tokenは調べると情報は出てくるので割愛します。

そして、tokenを扱うことを前提としているので.gsに貼り付けることは基本的にしないようにしたいのでGASの機能であるユーザープロパティを使用します。

プロジェクトのプロパティから設定できるように見えるのですが、自分は何故か反映されずソースコードからであれば反映されたのでメソッドを用意しています。

// add user property from code
function setup() {
  var prop = PropertiesService.getUserProperties();
  prop.setProperty('NAME', '');
  prop.setProperty('EMAIL', '');
  prop.setProperty('GITHUB_TOKEN', '');
}

これに必要な情報を張り付けて1度実行すれば以降は入力する必要はありません。

次にpush対象とするリポジトリを設定します。

function setupGitHub() {
  var prop = PropertiesService.getUserProperties()
  var option = { name:prop.getProperty('NAME') , email:prop.getProperty('EMAIL') }
  return new GitHubAPI.GitHubAPI('MizoTake', 'CreateAssetsFromGASUnitySample', prop.getProperty('GITHUB_TOKEN'), option)
}

のように設定すれば大丈夫です。MizoTakeやCreateAssetsFromGASUnitySample部分はご自身の設定に置き換えてください。 ちなみにMizoTakeのところはOrganization名でも大丈夫です。

さて、コミットを作っていきましょう。 以降は、基本的にGitHubAPI情報を参考に見ていると「あーね」ってなる気がします。 https://developer.github.com/v3/

// 対象となるfileのpath, fileのテキスト情報, githubライブラリで使用しているクラスのインスタンス
function addCommitData(filePath, blobData, github) {
  var txtBlob = UrlFetchApp.fetch(githubUrl + filePath)
  var index = txtBlob.getContentText().lastIndexOf('flow:')
  // flow: + 改行コード = 6
  var deleteTarget = txtBlob.getContentText().slice(index + 6)
  var header = txtBlob.getContentText().replace(deleteTarget, '')

  // .assetのテキスト情報
  var blob = github.createBlob(header + blobData)
  // GitHub apiに沿った配列を作成
  commitData.push({
      'path': filePath,
      'mode': '100644',
      'type': 'blob',
      'sha': blob['sha']
    })
}

これでcommitDataという配列にcommitする情報を与えていきます。

function createCommit(github) {  
  var branch = github.getBranch(branchName)
  var pTree = github.getTree(branch['commit']['commit']['tree']['sha'])
  var origin = pTree['tree']  
  // 現在のtree情報をbaseとして新しいtree情報を与えます
  var data = {
    'base_tree': pTree['sha'],
    'tree': commitData
  }
  var tree = github.createTree(data)
  // commitのメッセージを決めれます。
  var commit = github.createCommit('new GSS Data', tree['sha'], branch['commit']['sha'])
  var result = github.updateReference(branchName, commit['sha'])
}

コミットを作ったのでプルリクに紐づけます。

// プルリクが既にあるとエラーのためめんどくさいからtry catch
function createPullRequest(date, github) {
  try {
    const previousDay = new Date(date.getTime() + 24 * 60 * 60 * 1000)
    // プルリクのタイトルを日付に設定
    var title = Utilities.formatDate(previousDay, Session.getScriptTimeZone(), "yyyy/M/d")
    // masterをマージ対象とする
    return github.createPullRequest(title, branchName, 'master')
  } catch (error) {
    Logger.log(error)
  }
}

これで成功するとプルリクが作れちゃいます!

キャプチャ.PNG

注意点としては

  • プッシュするbranchは先に作っておくこと(branchを作るapiまでカバーしていないため)
  • treeの情報を間違えると色んなデータが消えたりしたことになるので配列は確認をして扱っていくこと

UnityEditorで確認する

gitでbranchを自動プルリクのbranchに切り替えてpullをします。 そして、UnityEditorに戻ると

キャプチャ.PNG

4つ目の項目まで表示されています!

これでファイルを作ってプルリクを投げる自動化は、一区切りです。

おまけ: 定期的に自動でコミットをさせていく

キャプチャ.PNG

編集を押すと現在のプロジェクトのトリガーという項目があるので選択します。

キャプチャ.PNG

トリガーを追加とあるので選択します。

キャプチャ.PNG

上図のように設定すると毎日午前0時~1時の間に自動的にpushToGitHubという関数を実行します。 これをすることで、毎日自動的にコミットがされることになります。何もしなくてもプルリクなりコミットが作られます。便利

所感

ここまで自動化すると結構便利な気がしています。 これはUnityに限らず色んな静的なファイルに有効だと思うので色々応用するのは良い気がしています。

UnityのWebGLをVue.js使ってPWAに対応した表示してみた

自分のQiita転載でございます。

qiita.com

PWAを触ってみたかった

始めの動機はそんなもので、PWAというのがあるすごい!UnityはWebGLで吐ける!…いけるんじゃね? ってことでやってみました。

PWA for Unity Sample ezgif-5-edf42d3870eb.gif

はい結構適当ですが、UI Buttonを押してカウントアップするものです。

環境

UnityやVueのセットアップは他の記事を参考に行った方が良いと思うので今回は省きます。 Vueに関してはこちらを参考にさせて頂きました。 - Vue.jsで始めるPWA - VueコンポーネントでWindowサイズ変更検知&値取得

最初に言うとWeb畑の人間でないのでVue.jsとかの記述、設定諸々はよくわかってないです行き当たりばったりでやってるのでお手柔らかにお願いします。 Unity WebGLCSSの適応の仕方がわからなくて詰んで放り投げました。

以下が今回のプロジェクトリポジトリになります。 GitHub

一応、GitHub Pagesも試しましたが何故かAndroidで動かしたときにショートカットを追加とかの機能が動いてなかったぽいので今回はFirebase Hostingを使ってみました。

Unityの設定

設定もなにもWebGLでビルドできるようにコンポーネント追加してビルドするだけです。

ただ、ビルドする場所はVue.jsのstaticフォルダ配下にビルドするようにします。Vue.jsの静的なファイルを置くところらしいです。 個人的にはstaticフォルダ配下にUnityビルド用のフォルダを作ってまとめておくとよいと思います。

今回だとunityBuildというフォルダを作っています。

Vueの設定

UnityのWebGLの読み込みを自分で書いても良かったのですが既にライブラリがあったため使わせていただきました。 vue-unity-webgl

上記をインストールしてまずはindex.htmlのヘッダーに

<link rel="shortcut icon" href="<%= htmlWebpackPlugin.files.publicPath %>static/unitybuild/TemplateData/favicon.ico">
  <link rel="stylesheet" href="<%= htmlWebpackPlugin.files.publicPath %>static/unitybuild/TemplateData/style.css">
  <script src="<%= htmlWebpackPlugin.files.publicPath %>static/unitybuild/TemplateData/UnityProgress.js"></script>
  <script src="<%= htmlWebpackPlugin.files.publicPath %>static/unitybuild/Build/UnityLoader.js"></script>

を追加します。static配下のunitybuildフォルダ名は各自が命名したフォルダ名にしてください。

そして、App.vueを

<template>
  <div id="app">
    <header>
      <span>Vue.js PWA</span>
    </header>
    <main>
      <unity src="static/unityBuild/Build/unityBuild.json"
        v-bind="{ width: gameWidth, height: gameHeight }"
       unityLoader="static/unityBuild/Build/UnityLoader.js"></unity>
    </main>
  </div>
</template>

<script>
import unity from 'vue-unity-webgl'

export default {
  name: 'app',
  data: function () {
    return {
      gameWidth: window.innerWidth,
      gameHeight: window.innerHeight * 0.96 - 134 // 134はヘッダー等の値
    }
  },
  methods: {
    handleResize: function () {
      this.gameWidth = window.innerWidth
      this.gameHeight = window.innerHeight
    }
  },
  ready: function () {
    window.addEventListener('resize', this.handleResize)
  },
  beforeDestroy: function () {
    window.removeEventListener('resize', this.handleResize)
  },
  components: { unity }
}
</script>

/// <style>は初期状態のまま編集してないので略 ///

と編集することで、とりあえずはそれっぽくUnityのWebGLを表示できるかと思います。

PWAなのでモバイルでも動かすことを想定していますが、最初に出てくるアラートが鬱陶しい場合はテラシュールブログさんの 【Unity】WebGLとWebAssembly にあるモバイルで動作させるを参照してください。

Firebase

今回は静的ファイルばかりなのでhosting機能を使っています。 セットアップとデプロイに関しては公式のドキュメントで充分だと思います。 Firebase Hosting

所感

Vue.jsが楽… PWAなのでちゃんとホーム画面でインストールしたかのように扱えますし、オフライン動作部分を調整すればストアに出さなくてもゲームらしく出来るんじゃないか?と思います。 cssをきちんと適応させることはもちろんですが横画面にすることも考慮してできれば結構気楽にゲームなどをデプロイできる気がします あと、最近はPWAをWindows等の上でも動かせるのでデスクトップゲーム風とかもできるかもしれません。 本当はUnityでWebGLビルド時に勝手にVueProject作ってPWA環境にする!みたいなフレームワーク的なところまで妄想してましたが妄想で止まってしまいました。。

何かの参考になればと思います。

(GitHubのアラートはいつかなおすんだ…いつか…)

Vuforia Fusionを使った際に描画がおかしくなった

「はちゃめちゃAR らくがきらんど」というアプリの開発メンバーの1人として制作して起こった問題を書いておきます。

まず「はちゃめちゃAR らくがきらんど」がどういうアプリなのか下のツイートの動画にて大体の雰囲気がつかめると思います。

 

という、3Dオブジェクトを出してスプレーで塗れるARアプリになります。iOSでは現在リリース中のアプリです。

 

そして、ARKitを使っています!…が、現在Android版対応に伴いARKitオンリーを抜けてVuforia Fusionを使って開発を進めています!(Vuforia FusionはARCoreでもARKitでも対応端末であればマルチプラットフォームで良きに図らってくれるものです)

 

そこで問題となったのがカメラが異常にズームされる問題です。

 

いや、めっちゃ原因不明で焦りました。

Cameraの設定を見てもVuforiaにきちんとハンドリングされていて、それらしきエラーも出ないんですよ

 

そこで以下のSRDebuggerというAssetを導入して実機端末でDebug.Logとかを張ったんですが、めぼしいものはなく…途方に暮れていました…(SRDebuggerはめちゃ便利で実機で何かを確認するとき捗ります)

 

そんなところ、もう1人の開発メンバーが「ビルドオプションのMutithreaded Renderingの設定を外すと動くかも」と言ってくれて試したところ…

f:id:MakeTake:20180525092750p:plain

 

 

動くやんけ!!!

 

何てことはなかったです。原因さえわかれば…

Vuforiaでなくても、Androidで描画うまくいかない…コード見直してもわからないという場合には外してみるのもいいのかもしれません。

 

「はちゃめちゃAR らくがきらんど」のAndroid版は現在調整中ですがiOS版はリリースされているので気になった方は是非インストールして頂ければと思います!

 

はちゃめちゃAR!らくがきランド

はちゃめちゃAR!らくがきランド

  • Iwasa Kenta
  • ゲーム
  • ¥120

 

追記: Android版リリースされました!端末は限られますが是非インストールしてみてください!!

 

play.google.com

ScriptableObjectの入れ替えで振る舞いを変える

セルフQiita転載です。

qiita.com

はじめに

 ゲームを作っていて、必殺技の作成等を簡単に行えるようにできないだろうか?ということを考えたのが今回の発端です。そこで、ScriptableObjectにパラメーターとメソッドを定義して入れ替えるだけで挙動を変えれると簡単なのでは?と考えついて試してみたので備忘録として書きます。

最終的に、以下のようになります。 Sample1.gif

ScriptableObjectの入れ替えで振る舞いが変わります。

gifで動かしているプロジェクトは公開しているので、説明読むより触ってみたい!という方はご活用ください。 https://github.com/MizoTake/ChangeBehaviourWithScriptableObject

一連の流れ

 最初に、今回の処理がどういう流れで行われているのか書きます。

まず、gifにあったCubeはSpaceキーを押すとInspectorから代入されたScriptableObjectの振る舞いを実行します。 中身は以下のようになっています。 Cubeに貼られているスクリプトから

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ControllerInput : MonoBehaviour
{
    [SerializeField]
    private Rigidbody _rigid;
    [SerializeField]
    private Behaviour _behaviour;

    public Rigidbody Rigid { get { return _rigid; } }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            _behaviour.Move(this);
        }
    }
}

SpaceKeyが押されるとBehaviourというクラスのMoveメソッドを実行します。 次に、そのBehaviourというクラスです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class Behaviour : ScriptableObject
{
    public abstract void Move(ControllerInput input);
}

public static class BehaviourExtension
{
    public static void Init(this Behaviour behaviour)
    {
        Debug.Log("Initialize");
    }
}

これは、abstractを宣言しているので基底クラスです。継承先で振る舞いを書いて欲しいメソッドを定義しています。今回は、Moveメソッドになります。 そして、ScriptableObjectクラスを継承しているので継承先のクラスをScriptableObjectにできるようになります。 また、abstractクラスには、そのまま拡張メソッドを追加できるので共通で何かを行いたい場合等に使うと便利です。(今回はTips程度に書いています。)

次にgifの最初にJumpしていたクラスです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Jump : Behaviour
{

    public int Power;

    public override void Move(ControllerInput input)
    {
        this.Init();
        input.Rigid.AddForce(Vector3.up * Power, ForceMode.Impulse);
    }
}

これはBehaviourを継承してMoveの振る舞いを定義しています。そのためgifでは、JumpクラスがInputControllerのInspectorに代入され、Moveが呼ばれるためジャンプをしていました。

ここで便利になるのはScriptableObjectを作成した後、Powerの値を変えることでジャンプの高さも変えることが容易になるという点です。

また、this.Init()で呼び出すことによりabstractの拡張メソッドであるInitが呼ばれます。

ここまでが基本的な一連の流れになります。

次からは+αで便利だと思った部分を書きます。

sample2.gif

これは最初のgifでバラバラに実行されていた、ジャンプの振る舞いと色を変える振る舞いを複合して実行しているものになります。

まず、色を変えるクラスです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeMaterial : Behaviour
{

    public Material Target;

    public override void Move(ControllerInput input)
    {
        this.Init();
        input.gameObject.GetComponent<MeshRenderer>().material = Target;
    }
}

ScriptableObjectにした後、InspectorでMaterialを代入しています。そして、Jump同様にInputControllerのInspctorに代入することで動作します。

次に複合させたクラスです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Composite : Behaviour
{

    public Behaviour[] Behaviours;

    public override void Move(ControllerInput input)
    {
        this.Init();
        foreach (var behaviour in Behaviours)
        {
            behaviour.Move(input);
        }
    }
}

中身を見ると何てことはないと思います。配列をInspectorから入れて、for文で一気に実行するというものです。

ただ、Behaviourクラスがあるだけで振る舞いの複合やランダム実行などが簡単に定義でき、Compositeクラス自体もBehaviour継承クラスなので、InputControllerのInspectorに代入するだけで切り替えれるというのは便利だと思っています。

以上で今回の記事はすべてになります。 (…ScriptableObjectにメソッドが書けるのが個人的に驚きだった)

また、ScriptableObjectの作成に関しては、個人的に以下の記事がオススメです。 【UnityEditor】ScriptableObjectのアセットを右クリックから作れるようにするエディター拡張

右クリックから作れるようになるので簡単作成できるようになって便利でした!