Project Unknown's Blog

Peojct.Unknownと言う名前で細々とアプリ開発をやってるメンバーのブログです。

開発効率を上げ、手軽に拡張できるFSM「Arbor2」紹介

この記事はUnity アセット真夏のアドベントカレンダー 2017 : ATND 17日目の記事です。

はじめに

つらつらとArbor2の事例紹介の記事を書いていたら、Arbor2の作者のケットシーウェア @caitsithwareさんに、アドカレの紹介を戴いたので、勢いで参加です(∩´∀`)∩

さて、本題です。

Arbor2

Alt text

Arbor2を導入する事で、FSMベースのヴィジュアルスクリプティングを実現することが出来ます。(↓な感じ

f:id:project-unknown:20170816212003p:plain
プログラムベースじゃなくて、上記みたいに状態遷移図をポチポチしていくだけである程度のゲームが作れてしまうと言う夢のような機能ですね。

(勝手ながら私が思うに)Arbor2の競合として、PlayMakerが挙げられると思うのですが、PlayMakerと比べて私が特に秀でていると思うのは以下の通りです

  • 拡張性の高さ(拡張難易度が低い)
  • サポートが日本語
  • シンプルで迷うことが殆ど無い

拡張性が高いため、簡単に機能追加していけます。
例えば↓みたいに機能をエンジニアが用意し、プランナーやデザイナーがゲームを構築すると言う形で分業もし易いです。

f:id:project-unknown:20170816194149g:plain

この記事の構成

  • まず最初に導入部分として、簡単な機能を作る所まで
  • 拡張性が高い所の紹介
  • 実際開発している最中の機能事例の紹介

上記で行こうと思います。
後、2Dベースで紹介していますが、勿論3Dでも使えますよ!

説明を文字に起こすとかなりごちゃごちゃしてますが、実際にやってみるとビックリするほど簡単ですよ!
無料試用版もあるので、是非使ってみてください。

導入

より詳しい説明はArbor2公式のチュートリアルを参照いただく事として、ここでは最初の足がかりを紹介します。

ここでは、以下のgifの用に、画面クリックで吹き出しが切り替わる単純な動作を作る所まで紹介します。 (さり気なく宣伝ですが、キャラクタは活動中のProject.Unknownのマスコットキャラの「う〜のん」を使ってます。

f:id:project-unknown:20170816165936g:plain

上記の構成は以下の4つのSpriteで構成されています。

  • 「背景」Sprite
  • 「う〜のん」Sprite
  • 「・・・」Sprite
  • 「?」Sprite

でわでわ、早速作っていきます。

AssetStoreからimport

特に何も考えず全部Projectに突っ込みます。
f:id:project-unknown:20170816163211p:plain

CommponentからArborFSMでアタッチ

ArborをアタッチしたいGameObjectのInspectorから以下の用にArborFSMをアタッチ。
f:id:project-unknown:20170816164122p:plain

次に、下の画像のOpen Editorをクリックします。
f:id:project-unknown:20170816164428p:plain

専用のEditorが表示されます。ここにステートを設定していきます。 f:id:project-unknown:20170816164506p:plain

「マウスクリックで次のステートへ」機能を作成

右クリックすると下の画像のようになるので、「ステートを作成」をクリックします。 f:id:project-unknown:20170816164617p:plain

これで空っぽのステートが作成されます。 f:id:project-unknown:20170816164644p:plain

「New State」と書いてある右側の歯車をクリックして「挙動を追加」をクリックします。
f:id:project-unknown:20170816164756p:plain

すると初期に用意された機能一覧が表示されます。
f:id:project-unknown:20170816164851p:plain

Behaviorから「Transition > Input > ButtonDownTransition」を選択。
Transitionは、次のステートに遷移させる事を指しています。今回選択した、ButtonDownTransitionは、マウス等がクリックされれば次のステートに遷移します。

現段階で、Arbor Editorが以下の用になっていると思うので、

f:id:project-unknown:20170816170632p:plain

遷移させたいステートを造ります。先ほどと同じ要領で右クリック -> 「ステートを作成」をクリック。

f:id:project-unknown:20170816170728p:plain

後は、「開始ステート」のButton Down Transitionの遷移先に、追加で作ったステートを選択します。

f:id:project-unknown:20170816171015g:plain
(キャプったら荒ぶった感じになってしまった(;・∀・)

Sprite変更

ここで、吹き出しを切り替える設定を埋め込みます。
追加で作ったステートで、挙動の追加 -> 「Renderer > SetSprite」を選択。
Targetと、Spriteに入力する所があるので、今回はSprite部分に切り替えたいSpriteをセットします。

また、次にクリックされた際に、別ステートに選択させたいので、先程と同様に、ButtonDownTransitionを追加します。

f:id:project-unknown:20170816171509p:plain

仕上げ

吹き出しを元に戻すステートを追加し、全てのステートをつなぎ合わせると以下のようになります。

f:id:project-unknown:20170816171624p:plain

動作確認

f:id:project-unknown:20170816173200g:plain

見て頂ければ分かるのですが、現在どのステートに居るのか、そのステートは何回目遷移してきたのかが視覚化されており、デバッグ機能としても非常に優秀です。

拡張性

お次は、拡張性の所を少しご紹介します。
Arbor2は、最初から用意されている機能を修正する事も出来ますし、自分で挙動をホイホイと追加することもできます。

既存の機能の修正

ArborのライセンスはEULAとなるかと思うので、デフォルトにあるコードを載せておりません。一部コードの抜粋で紹介を行いますが、問題がある場合は削除するのでご連絡ください。

導入部分でも登場した、ButtonDownTransitionに、ボタンが押された際に現在どのステートなのかをLogに出力するように改修を加えてみましょう。
まず、先程の例だと、全て「New State」になっているので、Logが分からないことになるので、以下のキャプチャのようにステート名を変更します。

f:id:project-unknown:20170816190642p:plain
(それぞれ「Start」「QuestionState」「SilentState」で名前を設定)

次に、実際にコードをいじっていきます。
↓の用に「スクリプト編集」をクリックすると該当するコードを直接編集できるようになります。

f:id:project-unknown:20170816181005p:plain

Updateメソッド内のInput.GetButtonDownのif文の中に以下のコードを埋め込む。

Debug.Log("Current State : " + state.name);

「state.name」で現在のステート名を取得できます。stateについての詳細はArbor: State Diagram Editor: State Class Referenceを御覧ください。

これを実行すると、ログはこんな感じで出力されます。

f:id:project-unknown:20170816191002p:plain

新規に挙動を追加

次に自分の好きなようにArbor2に機能(挙動)を追加します。

ここで作るものは、SpriteRendererの色を変更する機能を追加してみます。

Project Windowで、右クリック -> Create -> Arbor -> StateBehaviour -> 言語を選択
ファイル名は「ArborChangeSpriteColor.cs」としました。

f:id:project-unknown:20170816202126p:plain

コードの中身は以下な感じです。
(Arborに関する所にコメントを入れてます。

gist.github.com

上記で保存すると、ArborFSMの挙動追加で↓みたいに今回追加した機能を追加出来ます。
f:id:project-unknown:20170816204851g:plain

でわ、早速これを導入部分で作ったものに組み込んでみます。
1秒に1度う〜のんの色が変わるようにします。

う〜のんにArborFSMをアタッチして、こんな感じでFSMを編集します。
f:id:project-unknown:20170816204239p:plain

  • TimeTransitionは指定した秒数が経過したら次のステートに遷移させる機能です。
  • Arbor Change Sprite Colorに変更したいSpriteRendererを登録し、色もセットします

実行してみます。

f:id:project-unknown:20170816204456g:plain
(う〜のんがこわい…

こんな感じで、機能を自分で埋め込んでいくと、最終的に以下のように、開発しているゲーム独自に特化した機能を揃えることができ、
コアに作り込まないと行けない所は、ゴリゴリコードを書いて、
レベルデザイン等は、Arbor上で行うと言った作業の割り振りが出来そうです。

f:id:project-unknown:20170816194149g:plain
(懺悔すると、上記はgif用にメニューを用意しただけで、中身は空っぽの機能だらけです

他の機能実例

以下に、これまでに記載したより具体的なArbor2の実例を記してますので、もし興味があればmm

project-unknown.hatenablog.com

project-unknown.hatenablog.com

まとめ

紹介のはずがダラダラと色々詰め込んでしまいました(;・∀・)
総括すると、デフォルトで用意されている機能だけでもだいぶ効率的に開発出来ますし、
かゆい所に手が届かなかったら自分でサクッと機能追加出来る意味で、おすすめなAssetですよ(∩´∀`)∩

Unity アセット真夏のアドベントカレンダー 2017 : ATND次の担当は、baba_sさんで「Hierarchy を拡張する多機能アセット「PRO Hierarchy + Memory Monitoring + Navigator for Selecting」紹介」ですね!個人的に勢いで買ったは良いけど使わずにいるAssetなので凄い楽しみです。


参考

written by ゆう@あんのうん

ArborでuGUIのボタンを活性/非活性にする

Arbor上からuGUIのボタンのinteractableをいじりたい時のサンプルです。

凄い簡単ですが、以下のコードを「ArborButtonInteractable.cs」とかで好きな場所に保存すると、「挙動追加 > UI > Button > ボタンの活性、非活性」から使えるようになります。

gist.github.com

使い方Sample

前回の↓の記事の延長で行います。

project-unknown.hatenablog.com

やりたい事

  • 戸棚が開いていたらまたたびボタンを活性化させたい
  • 逆に戸棚が閉まったらまたたびボタンを非活性化させたい

戸棚の状態を見てState先を変えるコード

今回はArborの常駐ステートで常に監視する方針ですすめます。
まずは、以下のコードで戸棚の状態を見て、戸棚が開いていたら遷移するステート、逆にしまっていたら遷移するステートを選択できるようなコードを用意します。

gist.github.com

Arbor FSM編集

  • ArborOpenDoorTransition
  • ArborButtonInteractable

上記を、↓のように組みます。

f:id:project-unknown:20170815225646p:plain

以下が実行結果です。

f:id:project-unknown:20170815230020g:plain

(ふと思ったけど、こうも開発中の画面をポンポンだして良いものだろうか…(;・∀・)

written by ゆう@あんのうん

Arbor2で状態に応じてButtonの表示/非表示、Buttonタップ時のMessageを検知する

書こう書こうと思っていたArbor2の備忘録を書いていきます。

やろうとすること

凄いざっくりですが、以下の事をやろうと思います。

  • ゲームにとあるキャラ(今回は猫としてます)が登場したら、ボタンが表示される
  • ボタンをタップしたら、GameManagerクラス等でイベントキャッチと非表示処理

はじめに

インストール等、Arbor2って?と言うところは以下の公式を参照してください。

arbor.caitsithware.com

また、今回は絶賛開発中のゲームから抜粋してきているので、名前の付け方等、所々「?」となるかもですがご容赦ください。

Hierarchyを準備する。

今回はuGUIを使います。なので、Canvasに、以下の構成でぶら下げます。

f:id:project-unknown:20170814164316p:plain

Canvasは空のオブジェクトです。
Matatabiというのは、今回のゲームは「またたびボタン」としたいので、その名前をおいています。Matatabi自体はCanvasです。
MatatabiButtonが今回、非表示/表示処理を行いたい対象で、Buttonを置いてます。

Matatabi(Canvas)の作業

Matatabiには、MatatabiButtonの表示/非表示処理を担ってもらいます。
MatatabiのInspectorに以下のComponentを追加します。

f:id:project-unknown:20170814164723p:plain

Arborの状態遷移を追加しています。
Open Editorで状態遷移を開きます。
ここで以下のような遷移を作成しています。

f:id:project-unknown:20170814164853p:plain

上記状態について一つずつ説明していきます。

ArborCatStateStageIn

これ自前で用意したものです。
猫が登場したらまたたびボタンを表示すると言う事を行いたい為、Catオブジェクトの状態をチェックし、Catオブジェクトのステータスが茂みに登場したら次の「またたびボタン表示」状態へ遷移させます。

実際にArborCatStateStageInは以下の処理を行ってます。

gist.github.com

if (_Cat.CurrentState == Cat.CatState.Stay_StageIn) {

で、Catオブジェクトの現在の状態を監視している簡単なScriptです。

これで保存すると、Arbor2上では以下の挙動が追加されてます。

f:id:project-unknown:20170814165406p:plain

(初めてこれを見た時、Arborすげええええええ!!!ってなった

後は、上記からArborCatStateStageInを選択し、Catオブジェクトをセットし、次のステートに紐付けを行います。

ActivateGameObject

この挙動はStateに入る直前とStateから出ていく時にGameObjectのActive, 非Activeを設定出来ます。

ここでは、このStateに入る時にActiveにしたいのと、非表示処理はボタンをタップした時に実施するので、EndActiveもチェックを入れた状態にします。

MatatabiButtonの作業

次はMatatabiButtonの作業を行います。
こいつにはボタンを押した時の処理を担ってもらいます。

Stateは以下な感じです。

f:id:project-unknown:20170814165828p:plain

Start

開始ステートは、MatatabiButtonがタップされたかだけ見ており、タップされたら、次の「またたびを投げる」Stateへ遷移させてます。

またたびを投げる

SendMessageGameObjectで、指定したGameObjectのメソッドを読んでいます。
上記の例では、GameManagerオブジェクトのDidTapMatatabiButton()をコールしています。
これで、GameManagerはMatatabiButtonがタップされたことを検知出来るようになります。

また、このStateのActivateGameObjectで、非表示処理を行いボタンを消してます。

実行結果

MatatabiとMatatabiButtonそれぞれでの実行結果を貼っておきます

Matatabi(Canvas)

f:id:project-unknown:20170814170438g:plain

MatatabiButton

f:id:project-unknown:20170814170501g:plain


最後に

Arbor2はまだまだ全然使いこなせていないですが、簡単に自分で機能を追加が出来るのは本当に便利です。
まだ購入していない人は是非Asset Storeで買っちゃいましょう!

written by ゆう@あんのうん

UnityのPosition周りの共通っぽい処理

Writtern by ゆう@あんのうん

以下のゲームジャムに参加し、その成果物をアプリ化すべく、現在リファクタリングを行っているのですが、
今後のゲームジャムであると私が楽になりそうな共通処理を抜き出しました。

project-unknown.hatenablog.com

Tranform.positionの各座標の操作は、readonlyになっている為、一度別な変数に置き換えて、編集してから再代入しないといけなく、その手間を省いたものです。
staticクラス化して外部から読めるようにしているのは、

ゲームジャムだと時間がまったくなく、クラス設計がぐちゃぐちゃになって1つのクラスで他のGameObjectをいじりまくるシーンが頻発しているので、 外部参照出来るようにしています。

※本来はPosiitonをいじる時点で専用のクラス化を行うのが設計上正しいと思ってます。

「BehaviourUtility.cs」と「NumberUtility.cs」のクラスを作成して、以下のソースコードを丸コピすれば動く(はずです。
コードより下に、軽い説明を記載していますので、一緒に参照ください。

gistが使い慣れていないせいか、space4, spaceインデント設定なのにtab化されてしまってます。申し訳orz

gist.github.com

以下、各コードを軽く紹介。

NumberUtility.cs

Utilityと書いてますが、2つしか機能がありません。

GetValueOrMaximum(float value, float limit)

いわゆる 「x %= y;」とかをするメソッドです。
ただ、私自身がコードのど真ん中に「x %= y;」とか書いてあると、ん?とコードリーディングが止まったりするので、私自身への可読性向上の為に、回りくどい書き方をしています。
使用例としては、

// GameObjectのX座標を10以上いかないようにする。
float x = gameObject.transform.position.x
x++;
NumberUtility.GetValueOrMaximum(x, 10);
GetValueOrMinimum(float value, float limit)

GetValurOrMaximumの逆です。説明は省略。

BehaviourUtility.cs

BehaviourUtility.PositionX,Y,Z

引数として渡されたGameObjectの各座標を取得します。

float posX = BehaviourUtility.PositionX(gameObject);

BehaviourUtility.PositionFrom

GameObjectの座標を引数で渡されたVectorで加算/減算します。

// gameObjectの座標を、Vector3(1,0,0)へ移動させます
BehaviourUtility.PositionFrom(ref gameObject, new Vector3(1,0,0));

BehaviourUtility.PositionFromX,Y,Z

BehaviourUtility.PositionFromの各座標のみ指定するVerです。

// gameObjectのX座標を1ずらします
BehaviourUtility.PositionFromX(ref gameObject, 1);
// gameObjectのY座標を1ずらします
BehaviourUtility.PositionFromY(ref gameObject, 1);
// gameObjectのZ座標を1ずらします
BehaviourUtility.PositionFromZ(ref gameObject, 1);

BehaviourUtility.PositionAt

GameObjectのTransform.positionを引数で渡されたVector3で置き換えます。
(単純に毎回gameObject.transform.positionと書きたくなかっただけです)

// gameObjectをVector3(1,0,0)でセットします
BehaviourUtility.PositionAt(gameObject, new Vector3(1, 0, 0));

BehaviourUtility.PositionAtX,Y,Z

BehaviourUtility.PositionAtの各座標Ver, 説明は省略

BehaviourUtility.PositionAtToMaximum, BehaviourUtility. PositionAtToMinimum

BehaviourUtility.PositionAtの最大値以上/最小値以下に移動しないように制限する機能です。

BehaviourUtility.PositionAtToMaximumX,Y,Z
// gameObjectを+1移動させます。(最大値の10を超えると、10がセットされたままになります)
BehaviourUtility.PositionAtToMaximumX(ref gameObject, 1, 10);
BehaviourUtility. PositionAtToMinimumX,Y,Z
// gameObjectを-1移動させます。(最小値の0より下回ると、10がセットされたままになります)
BehaviourUtility.PositionAtToMinimumX(ref gameObject, 1, 0);

余談 自分自身のPositionを変更する場合

今回公開したコードは、あくまで別クラスからの操作に特化させています。
自分自身のpositionをいじる場合は、上記みたいな煩雑なやり方をしなくても、親クラスに以下のようなコードを記載しておいて、PositionXとかでいじったほうが良いと思います。
(コードはWebで他の先人たちのコードを取り込んでいます。

gist.github.com

Unity 1 Week Game Jam お題「夏」

f:id:project-unknown:20170624232237p:plain Unity 1週間ゲームジャム | ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

今回も性懲りも無く参加しました!
んで、性懲りもなくレポート書いてきます!

作ったゲーム

https://unityroom.com/games/patapata-unon

↑からPlayできるので是非遊んでみてください!

f:id:project-unknown:20170805131631g:plain

ずっとずっとやりたかった、我がProjectのマスコット(何もタイトル出してないのにマスコットだけは作っていた)のう〜のんを使ったゲームです。

企画

前回、ギリギリまで参加する/しないで悩んでいて、結果作業時間が殆ど確保出来なかったので、同じ轍は踏まないように、月曜の朝から通勤時間を用いてデザイナのやよんとSlackを用いて相談。

夏と言えば?でパッと思いついたもので以下のものが絞れました。

  • スイカ
  • 風鈴
  • 汗 (俺の一押し)

企画の詰め

スイカ

真っ先に考えたのが、スイカでFPSの案でした。

  • 主人公はスイカの種を口から発射してEnemyを倒す
  • スイカの種は、口の中からなくなったら、新しく食べてリロード
  • 腹がいっぱいの場合はスイカが食べられないから、動き回って空腹ゲージを増やす
  • スイカはお母さんから補充されて、たまに種無しスイカが出て来る所にイライラポイントを作る

個人的に満腹ゲージの反対を行くと言う所と、スイカのFPSという所がおもろいやんと思ったのですが、
いかんせん開発が間に合いそうに無いと言う理由で見送りました(いずれ作ってみたい

通勤時間中、汗だくになっていたと言うのあって思いついた案でした。

  • 満員電車で汗が垂れ落ちてくるので、他の人に飛び散る前に拭き取る
  • あまりに連続して拭くと周りの女性から痴漢と勘違いされ人生が詰む

ここまで考えて、痴漢の所が最近話題と言うのと、社会的倫理としてどうよと思ったので没

風鈴

  • あるクーラーが買えない貧乏一家が暑くて耐えられなく、風鈴を拾ってくる。
  • ただ風が一切無い状態なので、風鈴が鳴らず哀愁を漂わせている。
    • 結局貧乏は止めて、おじいさんが風鈴が鳴らずに困っている設定になりました。
  • そこに主人公がこっそり影で風鈴を鳴らして涼しさを提供すると言うゲーム案が出ました。
  • パッと考えた感じでやよんと完全に意見があったのでこれで行こうと言う事になりました。

言い訳開始

前回でも載せてた以下のつぶやきですが、

完了と書いておきながら、現在この記事を書いている間も続行中です
なので、平日は家に帰るのが日付を超えてからじゃないと帰れなかったのでまったく作業出来ませんでした。

土曜

この日からガッツリ作業する予定だったのですが、

kenjin.unity3d.jp

上記に参加した為、作業を開始したのは夜でした。(凄い勉強になったので、個人的には行って良かったです。

夜から、やよんと合流して、製作開始です。

折角、今回新規に参加するんだから、Unityのバージョンを上げてしまえと勢いで2017.1.03fへupdateを行ったら、ものの見事につまりました。
(以下の記事に詰まった詳細を載せております)

project-unknown.hatenablog.com

予めどんなことをやるのかの大枠を決めていたと言うのと、
主人公を我がProjectのマスコットである「う〜のん」を使うと言う所もあり、
あまり議論を交わさずとも、殆どゴールの共有が出来ていました。
↓う〜のんのイメージ図

f:id:project-unknown:20170806030024p:plain f:id:project-unknown:20170806030034p:plain

ここでなんとなくでゴールの共有が出来ていたのは、自分らの中でう〜のんのキャラ付けが強烈に出来上がっていた為、
う〜のんをゲームに登場させると言うだけで、どんなタッチのゲームになるのかが想像できていたと言うのがでかいです。
(こう考えると、インパクトの強いキャラから考えてもゲーム企画もそうですが、コミュニケーションコストがかなり軽減出来るかもですね

この日は画像を用意してもらって、Unity上でざっくり動作させる所(以下Gif参照)で力尽きる。

f:id:project-unknown:20170806030631g:plain

日曜(最終日)

この日はお昼からガッツリ開発開始。
bitbucketに並べたかんばんのタスクが30個から一切減らない(消化スピードより、新たに見つかるもののスピードの方が早い)という絶望を噛み締めながら仕上げていきます。
相変わらず夜になっても、半分くらいしか開発が終わっていなく、ゲームデザインの調整をしている暇も無く、締め切りの20時が過ぎ去っていきます。

23時頃にある程度の完成の目処がたち、WebGLに初めて書き出してみたのですが、ここでWebGLで表示するとuGUIが尽く想定の斜め上を行く現象が発生
おそらくLayoutあたりの指定が甘かったのがあるのだと思うのですが、尽く小さくなっちゃってUIとしての機能を果たしてくれない状態でした。
(結局四の五の行っている状況ではなかったので、全てのUIを固定幅で指定してUploadしました。

開発部分のお話

使ったAsset

今回は、前回よりも余裕がなかったのでAssetを殆ど使いませんでした。   不自由なく使いこなしているAssetが少なかったので、自前でゴリゴリコードを書いたほうが早かったので…
使用したAssetは以下です。

  • EasySave2
    • 主に保存周りに利用
  • Arbor2
    • 上記にPlayMakerのセミナーに参加したと書きましたが、こちらの方が使い慣れているので、今回も採用。
    • AIとかのロジック部分にあてたかったのですが、そこまで使いこなしておらず、共通処理系(音を鳴らすや、画面遷移、ボタン操作等など)をArbor2を使ってPackage化してたので、それを流用する形で利用させていただきました
  • Game Music Pack - SUITE
    • BGMとして利用。ほんと使いやすい音楽が多くて重宝してます。

2Dを採用した理由

これまで世に出していないだけで、色々ゲームは作っていて、2Dの方が経験値として高かったと言うのと、やはりう〜のんのキャラ的に2Dの方が遥かに映えるので、ここは特に考えることも無く2Dで製造しました。

AI(おじいさんの実装)

  • 理想
    • 一定時間で振り向く
    • 引き戸を素早く開くと音に反応する
    • 風鈴が鳴りすぎると振り向く
  • 現実
    • 一定時間(乱数)で振り向く

余り作り込めて無いです。そのせいで挙動不審な勢いで振り向く時があります。

タッチ判定

なんだかんだでここに時間がかかってしまいました。(Asset買っておけば良かった…)
Eventシステムが余り使い慣れていないと言うのもあり、ドラッグとクリックでうまく処理を分ける所につまずいて居ました。
色々グーグル先生に尋ねたりして、UI周りのHandlerにDelegateを突っ込む形で実現

public class TouchEventHandler : BaseSingletonMonoBehaviourOnGameObject<TouchEventHandler>, IPointerDownHandler, IPointerUpHandler, IBeginDragHandler, IEndDragHandler, IDragHandler{

    //タップ中
    private bool _isPressing = false;
    public  bool  IsPressing{
        get{return _isPressing;}
    }

    //ドラック中か
    private bool _isDragging = false;
    public  bool  IsDragging{
        get{return _isDragging;}
    }

    //ピンチ中かのフラグ
    private bool _isPinching = false;
    public  bool  IsPinching{
        get{return _isPinching;}
    }

    //全フレームでのドラック位置(ワールド座標)
    private Vector3 _beforeTapWorldPoint;

    //ピンチ開始時の指の距離
    private float _beforeDistanceOfPinch;

    //タップ関係
    public event Action<bool> onPress       = delegate {};
    public event Action        onBeginPress  = delegate {};
    public event Action        onEndPress    = delegate {};

    //ドラッグ
    public event Action<Vector2> onDrag      = delegate {};
    public event Action<Vector3> onDragIn3D  = delegate {};
    public event Action          onBeginDrag = delegate {};
    public event Action          onEndDrag   = delegate {};

    //ビンチ
    public event Action<float> onPinch      = delegate {};
    public event Action        onBeginPinch = delegate {};
    public event Action        onEndPinch   = delegate {};

/* 以下省略 */

Animation

簡単なAnimationが多かったので、メカニムを使うのではなく、ここもコードでパラパラ漫画を使って乗り切ってます。
(どんだけ追い込まれているんだ…)
基本はAnimation部分をコルーチン化しておき、条件に応じてコルーチンを発動と言う形で動かしています。

反省点

Unityの機能を使いこなせてない

Unityそこそこ使ってきたつもりで居たけど、まったく使いこなせていない。
Unityの機能を使うより、コードで書いたほうが早いと言う判断が出る時点で駄目。

息をするように使えるようにスキルを挙げないといかん

共通化処理をもっと纏める。

前回書いていた処理を今回も書いていたと言うところはいただけないので、共通化する。
また、今回詰まったドラッグ+クリック周りの処理は良く出てくるはずなので、これも共通化処理として纏めておく。
ちなみに、今纏め始めている最中で、以下の用に纏めつつあります。

f:id:project-unknown:20170806034123p:plain

オブジェクト脳を鍛える

やっぱりテンパると1つのクラスの処理を纏めがちになっており、現在リファクタしているのですが、非常に読みにくい。
もっとオブジェクト脳を鍛えていかないといけないなーと猛省しております。
(業務でもSwiftとかバリバリオブジェクト指向で書いているので、ここは自信があったのですがダメダメでした。

感想

前回と同じ所で、やっぱり期限とお題があるのは本当にありがたいです。
このイベントのお陰で、今自分が持っている武器はなんだろう?しかもその武器は速度が出るのか?を常に考えて実装に入っているので、今自分が置かれている状況・スキルセットを振り返る良い機会になります。
また、一緒に弱点も見えて来るのと、勉強したい事柄も見えて来ます。

ぱたぱたう〜のんの今後

前回のFallStoneもやろうとして出来て居なかったのですが、折角ここまでの形にしたので、アプリ化を目指して現在進めています。
以下は、開発中のかんばん f:id:project-unknown:20170806034259p:plain

(既にタスクが30個もツンである(;・∀・)

そこまでクオリティある所まで持っていくのは厳しいかもですが、より遊び要素を追加したものを開発中ですので、リリースできた際は是非遊んでみてくださいね!

Unity2017.1.0f3にUpdateした際につまずいた所

ゆう@あんのうんです。

先週Unity1週間ゲームジャムに参加するにあたり、どうせならUnityを最新版にして参加しようとし、Updateした際に思いっきりつまずいた所の紹介と、私が取った解決法を記載します。

発生環境

  • Macbook Pro 2014モデル
  • OS Sierra
  • Unity5.3.x系からUnity2017.1.0f3へのUpdateで発生

発生した問題

japan.unity3d.com
上記Unity公式から、Unityの最新版へUpdateした際、インストールの最後に以下のエラーダイアログが表示されました。

Copying /Library/Application Support/Unity/Unity_v5.x.ulf to /Library/Application Support/Unity/Unity_lic.ulf: No such file or directory

なんかライセンサの更新の所に思いっきり引っかかっていそうなエラーです。
Google先生にご教示頂いた所、ライセンサのエラーは何個か見つかったのですが、私の様なエラーは発生していないような感じがします。

とりあえず、このままだとよくわからないので、Unityを立ち上げてみると、また上記と同じエラーダイアログが出ます。

対応内容

エラー内容を見る限りだと、Unity5系からUnity2017系にUpdateする際に、ライセンサをリネームしようとしている感じがしているので、ここを手動で行ってみます。

$ sudo cp /Library/Application Support/Unity/Unity_v5.x.ulf /Library/Application Support/Unity/Unity_v5.x.ulf.bk
$ sudo cp /Library/Application Support/Unity/Unity_v5.x.ulf /Library/Application Support/Unity/Unity_lic.ulf

(1行目は念のためのbackupを取ってます。)

これで立ち上げると、アカウントのActivate画面となった為、画面に従ってActivate処理を行います。
すると、Activateの最後に以下のエラーダイアログが表示されました。

Failed to write "/Library/Application Support/Unity/Unity_lic.ulf". Please verify you have write permissions to this file.

エラー内容を見る限りパーミションのエラーだったので、該当ファイルのパーミションを変更します。
(他のライセンサの所有者がMacのユーザ名だったので、rootからユーザへ変更します。

$ sudo chown {アカウント名} /Library/Application Support/Unity/Unity_lic.ulf

最終的に、ライセンサが格納されているディレクトリは以下の構成となりました

$ls -al /Library/Application Support/Unity/
drwxrwxr-x 6 root wheel 204 7 30 02:14 .
drwxr-xr-x 20 root admin 680 12 10 2016 ..
-rw-r-----@ 1 {アカウント名} wheel 1999 7 30 02:17 Unity_lic.ulf
-rw-r--r-- 1 {アカウント名} admin 1967 9 26 2015 Unity_v4.x.ulf
-rw-r-----@ 1 {アカウント名} wheel 1996 7 28 23:08 Unity_v5.x.ulf
-rw-r----- 1 root wheel 1996 7 30 02:14 Unity_v5.x.ulf.bk

上記対応後、再度Unityを立ち上げると再びアカウントのActivateに移ったのですが、Activate後は問題なく利用することが出来るようになりました。

この対応は問題なかったのか?

手動でライセンサをコピーしたり、パーミション変更を加えているので、対応が正しいのか不明だったのでUnityサポートに問い合わせさせていただきました。

以下が回答

稀有な現象で同様の事例については情報がないのですが、
あいにく動作を保証することはできません。しかし、おそらく問題はないかと思います。
何かしら問題が発生しましたら再度お問い合わせいただければと思います。

Unityサポートでも把握していない事象のようです。
一旦、問題なく利用できるようになりましたので、引き続きこのまま利用させていただこうと思います。
状況に進展がありましたら、またこちらで報告します。

Firebase(AdMob/Analytics)へ移行した際のメモ

またまたKeyHolderの作業中メモです。

f:id:project-unknown:20170723221403p:plain

お題の通り、Firebaseに諸々集約させようとしており、その際の作業ログです。

前提

KeyHolderでは、以下を利用しております。

AdMobとGoogleAnalyticsはGoogle製で、FirebaseもGoogleが買収してGoogleさんの持ち物ですが、 これまでの名残もあり、Firebaseと上記上げたものは別管理っぽくなっています。

折角、Appに特化した管理が出来るFirebaseが登場したので、これを機に移行してしまおうと思います。

クラッシュレポートもこの際にFirebaseにと考えたのですが、現在KeyHolderはFabricを利用しており、将来的にFirebaseのCrash ReportingはFabricに移行する(Firebaseのコンソールでも、Fabricの利用を勧めています)ので、このタイミングでは移行させません。
FirebaseでFabricをいじれるようになったタイミングで移行させます。

Firebaseとは?

詳細な説明は仕切れないので、ここの説明は他サイト様に委ねます。

firebase.google.com

project-unknown.hatenablog.com   (以前纏めた、主に料金についてヒアリングした結果も貼っておきます)

では、これから作業を開始します。

Firebaseから設定ファイルをProjectに突っ込む

FirebaseのコンソールからProjectを選択し、Overview -> プロジェクトの設定を選択します。

f:id:project-unknown:20170723220526p:plain

アプリを追加で、ご自身のアプリを追加します。
また、ダイアログで、GoogleServive-info.plistをDLするようにと出るのですが、念のため以下の設定を加えてからDLしたほうが良いです。

f:id:project-unknown:20170723220704p:plain

  • アプリID
    • Firebaseが勝手に振る識別子です。特に弄る必要はありません。
  • アプリのニックネーム
    • ストアに並べる名前と同じで良いです
  • バンドルID
  • App Store ID
    • App Storeに並べる時にIDですね。KeyHolderのURLを見てわかるように「idxxxxxxxxxx」のxxxxの部分を入れます
  • App ID Prefix
  • レポートで使用する通過
    • KeyHolderは広告且つ、日本でしか展開していないので、日本円にしました
  • タイムゾーン
    • ここも日本時間を設定

上記まで選択したが、画面上部にある「GoogleService-info.plist」をクリックしてダウンロードします。

f:id:project-unknown:20170723221251p:plain

FinderからDrag&DropでProjectに突っ込むだけです。

CocoaPodを弄る

全ての作業でCocoaPodsが出てくるので、設定を一括でここでやっちゃいます。

CocoaPodsよりinstall

以下で設定します

source 'https://github.com/CocoaPods/Specs.git'

target 'KeyHolder' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for KeyHolder

pod 'Firebase/AdMob'
pod 'Firebase/Crash'
pod 'Google/Analytics'


end

ここまで書いたら

pod install

でinstall実行。

AdMobをFireBase/AdMobに切り替える

スタートガイド  |  AdMob by Google  |  Firebase

上記に即した作業を行います。

AdMob Webの設定

やることは非常に簡単です。 まず、AdMobのサイトで、管理している広告をFirebaseにリンクさせます。

f:id:project-unknown:20170723212747p:plain

分析タブから、Firebaseにリンクさせたいアプリの「Firebaseにリンク」をタップするだけです。
既にFirebaseにProjectを作成している場合は、リンクをタップして、既存にあるProjectに紐付けをし、作っていない場合も新規に作るか聞かれるので、このタイミングで新規に作ってしまいます。

Firebaseのコンソールを見ると、無事に作成されています。 f:id:project-unknown:20170723213021p:plain

XCode上の作業

ATS周り

何故か、Firebase/Admobを入れてから、ATS周りでDebuggerがWarningを吐くようになりました。
昔良く見た、↓みたいなやつ

canOpenURL: failed for URL: "itms-books://

とりあえず、ATS周りの「App Transport Security Settings」の設定は埋め込んであるので、以下の設定を取り除いてしまいます。

-    <key>LSApplicationQueriesSchemes</key>
-   <array>
-       <string>itms-books</string>
-       <string>kindle</string>
-   </array>

これでWarningが消えました。(私だけなんかなぁ…)

コード修正

AdMobのコードが埋め込んであれば、やることは少ししかありません。 ProjectのAppDelegateでAdMobの初期設定を埋め込みます。

GADMobileAds.configure(withApplicationID: AdMobのアプリ管理ID)

場所は「didFinishLaunchingWithOptions」等のAppが立ち上がって直ぐが推奨されています。
これは何ぞ?という所ですが、どうやらApp立ち上げのタイミングで、該当するアプリ管理IDに紐づく広告の準備を行う事で、
後に広告リクエストが必要になったタイミングで、高速で広告を引くことが出来るんだとか(シミュレータ上の実感はあんま無いです)

ちなみにアプリ管理IDですが、
ca-app-pub-xxxxxxxxx/xxxxxxxxx形式じゃないです
ca-app-pub-xxxxxxxxx-xxxxxxxxx形式です

んで、アプリ管理IDですが、

f:id:project-unknown:20170723214315p:plain

上記から遷移して

f:id:project-unknown:20170723214400p:plain

上記青枠で括った所がアプリ管理IDですので注意ください。

Firebase Analyticsへ移行する

導入手順は以下に記しますが、KeyHolderではFirebase Analyticsに移行をやめました。
やめた理由については後述しましたので参考になさってください。

設定

設定は、これまでのGoogleService-info.plistとCocoaPodsの設定が完了していれば特にすることはありません。

コード

AppDelegate等でFirebaseを初期化します。

import Firebase

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        FIRApp.configure()
    }
}

次にEventを送信したい箇所で、以下の様にEventを送ります。

// import Firebaseだとエラーになったので、FirebaseAnalyticsを直接importしています。
import FirebaseAnalytics

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        FIRAnalytics.logEventWithName("load ViewController", parameters: nil)
    }
}

後は、ログ設計を行って、ログを取得したい箇所で突っ込めば良い感じなトラッキングができそうです。

KeyHolderで実装を見送った理由

まず、Firebase Analyticsと Google Analyticsとの方向性についてですが。
Googleによると

  • Firebase Analytics
    • アプリに特価で、アプリのみで解析を行う場合は、こっち
  • Google Analytics
    • webページ含めた場合はこっち

との事で、KeyHolderに関しては、Web2Appなどは特に行っていないので、方針に添ってFirebase Analyticsを採用しようかと考えたのですが、Firebase Anaylyticsは、アプリの中で発生するイベントを取得して分析を行う事を主に考えているので、Google Analyticsのようにスクリーンを個別に取得・分析するような機能は提供していないっぽい感じがします。(それっぽいAPIがありましたが、これは明らかにEventを送る際にどのViewだったかを送っているので、現在の画面単位での集計ではない感じがします)

KeyHolderのユーザ解析は、もちろんイベントトラッキングも行っていますが、画面毎のPV、またPVがDAU/MAUにどのように貢献しているのかと言う所を見ていたりするので、ログ設計をPV -> Eventに置き換えた設計を実施しないといけなく、これまでのKeyHolderのログ解析を考え直さないと行けない事に気づいたので、今回は見送る事にしました。

ただ、Firebaseコンソールで解析まで一括管理出来るメリットはかなり大きいので、ログ設計を見直した後に再度実装に乗り出そうと考えています。


まだ、Firebase版KeyHolderはリリースしていないので、実際にリリース開始してから不具合に気づくかもしれませんが…。結構簡単にFirebaseの実装は行けそうです。
とはいえ、FabricやFirebaseAnalyticsが残っているので、実質AdMobしか今回は対応していないのですがw

最後に宣伝ですが、今回何度も話題に出したKeyHolderは以下からinstall出来ますので、まだお持ちでない方は是非是非使ってみてくださいませ!

KeyHolder - シンプルにパスワード管理

KeyHolder - シンプルにパスワード管理

  • Yayoi Yabu
  • ユーティリティ
  • 無料