FreelyApps

個人によるアプリ開発の日記です。アプリの収入だけで生活できるようになるのが目標です。UnityでAndroid向けのゲームアプリを作成しています。


    アプリ『トランプ・7並べ』を公開しました。
    Android/iOS https://goo.gl/zsFces

    タグ:初級

      このエントリーをはてなブックマークに追加 Clip to Evernote
    List<T>クラスは非常に便利なクラスです。配列のように大きさが決まっていないので、要素が増えたり減ったりするものを扱うのに適しています。
    トランプゲームを作るときにカード一つ一つにint型のIDを割り当てています。一度に複数のカードを出すといったときにList<int>で複数のカードを表すと扱いが簡単です。リストの分だけ処理をforeachで行えば良いからです。

    Listを使うときに失敗したことをメモしておきます。たまに「あれ、どうなってるんだっけ?」となるもので、先日テストコードを書きました。

    1.Listを引数に渡したとき、内部で要素を足したり消したりすると影響が残る
    このスクリプトをUnityで適当なゲームオブジェクトにアタッチしてみた結果は次のようになりました。
    printListTest
    見てもらえば大体わかると思いますが、ListAddやListRemoveに渡したリストの内容が変わります。List<T>はクラスなので、参照型ということですね。参照型を引数に渡したときの挙動は気を付けないと、バグになりやすいです。

    2.リストのループ内でリストを変更してはいけない
    このスクリプトをUnityで適当なゲームオブジェクトにアタッチしてみた結果は次のようになりました。
    printListTest2
    この例は実行するとエラーを起こしますが、コンパイルは通ります。これはforeachループ内でリストに変更をしていることが問題です。(list.Remove(2)のところです。)
    実行すればわかるバグですが、この例よりも複雑なことをする場合には意外と気づきにくいバグになります。
    リストの要素を一つずつ検査していって、ある条件になっているものを除きたいというときに同じループ内で決してしまうということをやってしまうとエラーになります。RemoveAllメソッドを使うか、いったん削除対象を別のリストに入れてからそのリストのループ内で元のリストの要素を消していくことになります。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unityでゲームを作るとしてもやはりプログラミングが必要です。通常のゲームプログラミングとは異なる考えで作ることにもなるので、プログラミングをやったことがある人はむしろ混乱するかもしれません。
    Unityのプログラムはスクリプトと呼ばれ、 これをゲームオブジェクトというものにくっつけることで動きます。ゲームオブジェクトは様々な機能のスクリプトをくっつけることができるものです。”もの”というのはそれ自体で何かするのではなく、機能をつけることでライトになったり、カメラになったり、モデルになったりと何でもなれるけれど何でもないという置き場所のような意味です。

    何かを始めるときに覚えることが多いと嫌になります。UnityのGUI操作は覚えることがそれなりに多いので、プログラミングはとりあえず作れるようになるくらいで始めるのが良いと思います。少なければいくつでも良いですが、3つだとわかりやすいと思ったので3つの関数について説明します。

    ゲームを作るために必要な3つの関数とは、
    1. Update
    2. Start
    3. Awake 
    のことです。この名前をつけたメソッドはUnityから呼び出されて処理されるという特徴があります。これはイベント関数と呼ばれています。Updateは毎フレーム呼ばれる最も重要な関数です。ゲームの処理はここに書いていくことになるでしょう。この関数だけあればゲームを作ることもできますが、初期化は別に分けられていた方が都合が良いです。そのための処理がStartとAwakeです。 
    名前からだと微妙なところですが、Awakeが先でその後にStartが呼ばれます。通常はStartだけ使うだけで十分だと思います。AwakeとStartの微妙な違いを理解できるようになったら、他のイベントも覚えていることでしょう。

    よくAwakeとStartが呼ばれないということで問題になることがあります。大抵の場合、そのスクリプトがついているゲームオブジェクトがアクティブでないかスクリプト自身が有効でないと思います。
    それ以外で呼ばれないとすれば、ゲームオブジェクトにつけてないか名前の打ち間違えでしょう。 

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unityではイベント関数と呼ばれる特殊な関数があります。これはゲームオブジェクトにアタッチされたスクリプトの中で特別な名前のメソッドがUnityから呼ばれるという機能です。

    よく使うものを挙げると、 
    • Awake()
    • Start()
    • Update()
    • OnDestroy()
    などです。

    イベント関数を使う上で問題になることが多いのが、名前を間違うことです。名前を間違えただけなので修正は容易なのですが、問題が発覚しにくいことが厄介なところです。
    名前を間違っていても特にコンパイルエラーは発生しません。そのためプログラム的な問題はないと判断されて、後になって実は問題があるということになります。Unityから呼び出されなくても文法的には問題ないため、検出できないバグになるのです。

    OnCollisionEnter(Collision)みたいに特定のクラスを引数に取る場合も注意が必要です。イベント関数の名前が合っていても引数の型が間違っているということがあります。このときどのようになるかを例を挙げて調べてみました。
    void OnCollisionStay(int n)のように定義すると、以下のようにエラーが発生しました。
    event-argerror
    しかしながら、void OnCollisionStay()というように引数を空にしてみるとイベントが発生したタイミングに正しく呼ばれていました。
    つまり、イベント関数が引数を取る場合、引数があっているか空であれば呼ばれるということです。(もちろん名前が合っているとして)

    イベント関数の名前を間違ったり、引数の型を間違っていてもエラーが発生しないことがあります。
    正しくないイベント関数を書かないようにすることは絶対には防げないので、起こりにくくする方法を紹介することにします。


    VSTUを使っている場合は便利機能でイベント関数を自動で実装することができます。これを使うのが最もミスの起こりにくい方法だと思います。あまり詳しくないイベントを使う時などはこの機能を使っておくのが良いです。

    Visual Studioでイベント関数を追加したいソースファイルを開いて、ソース上で右クリックをすると下のメニューが現れます。
    vs-event

    Implement MonoBehavioursとQuick MonoBehavioursとが用意されているので、どちらかをクリックします。

    Implement MonoBehavioursの場合は、次のウィンドウが現れます。
    vs-implement
    チェックしたイベント関数が一度に追加でき、メソッドの説明をコメントできたりするのでお勧めです。ソースに自動的にプログラムが書かれるので間違うことがなく、積極的に使うべき機能だと思います。

    Quick MonoBehavioursの場合は、次の小さなウィンドウが現れます。
    vs-quick
    入力欄にイベント名を一部でも入れると候補が検索して現れます。候補を選べばメソッドが追加されます。
    こちらの機能はイベントの名前を知っている場合、素早く追加することができるという熟練者向けの機能と言えます。一度に追加できるのは1つまでです。

    VSTUを使って自動的に追加されたイベント関数にはpublic void Awake()のようにpublicが付きますが、publicはなくても問題ありません。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unity5.1からUnityEngine.Assertionsが使えるようになりました。スクリプトリファレンスはこちらに載っています。
    アサートは開発時に有用な機能です。Unityだけでなく、色々なプログラミング言語に同じような機能があります。どのような場合もプログラムの検証用に用いられます。
    例を挙げると、ある変数の値が0であるべき場所でそうなっているかを調べたり、値の範囲が想定内に収まっているかを調べるために使われます。

    基本的にデバッグ版のみに有効化するものです。リリース版には検証用のコード(Assertも含む) は取り除かれ余計な処理をせずに高速に実行するべきだからです。
    デバッグであれば実行速度が遅くなったとしても問題を検知できる方が重要なので、Assertを有効化して問題が起こっていないかを調べるのです。

    Assertとは英単語で意味は「主張する」といったものです。それゆえ条件を満たしているかを「主張する」機能に使われるようになったようです。 
    大抵の場合は条件を満たさないときにエラーメッセージを出力するか例外を発生させます。UnityEngine.Assertionsではこのどちらもサポートしていますが、エラーメッセージを出力するほうで十分だと思います。例外の処理を忘れると、おかしな挙動になってしまうのです。



    UnityEngine.Assertionsの使い方を説明していきましょう。

    using UnityEngine.Assertions;を宣言しておき、判定したいところでAssert.IsTrue(bool値のもの);というように書けば良いです。Assert.IsTrueの場合は引数の値がtrueであれば何もせず、falseであるとエラーになります。第2引数の指定もでき、そこにはメッセージを指定できます。どのようなエラーなのかわかりやすくするためにコメントを書いておくことをお勧めします。
    他にもIsNotNull(nullでないことを保証する)とかAreEqual(値が一致するか保障する)などがあります。

    このアサートはUNITY_ASSERTIONSが定義されているとき有効であり、ないときはコードから消えます。Development BuildのときはUNITY_ASSERTIONSが自動で定義されるようですが、UNITY_ASSERTIONSを自分で定義する方が便利だと思いました。

    using UnityEngine.Assertions.Must;を宣言すると、Assertを利用した拡張メソッドが使えるようになります。bool、int 、floatなどの型にメソッドが追加され、(数式).MustBeEqual(0);というようにアサートを書くことができます。(拡張メソッドなので、using UnityEngine.Assertions.Must;は必須になります。)

    Assert.raiseExceptionsをtrueに設定するとエラーを表示するのではなく、例外を発生させます。デフォルトはfalseなのでエラー表示がされるだけです。例外処理を書いてアサートを処理したい場合はtrueにすることになるでしょう。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unity AdsのSDKはアセットストアからダウンロードします。

    Unity AdsのSDKはC#で書かれているので、C#で実装するのが一番簡単です。基本的な実装の流れはドキュメントのサンプルに書いてある通りです。 このサンプルをシーンに存在するGameObjectにつけて、GameIDと呼ばれるゲームごとに固有なIDを設定するだけで動きます。GameIDはUnity Adsの管理サイトの登録済みゲームの一覧が見れる画面で見ることができます。(日本語の場合、ゲームIDと書いてあります)

    サンプルコードの重要な所だけ説明しておきます。

     Advertisement.isSupported がtrueでない場合は、iOS/Androidではないプラットフォームを選んでいるのでUnity Adsは動きません。これはtrueだったら処理を続けるというだけのことです。

    Advertisement.Initialize  が初期化を行います。呼び出し方はゲームIDを引数に渡して呼ぶだけです。ゲームIDを間違ってしまうと、得られた報酬が実は違うゲームのものだったということになりかねません。これは十分に注意して書く必要があります。

    サンプルのOnGUIでは、Advertisement.Show を呼び出しています。特に準備できたか関係なしに実行されていることがわかります。Advertisement.isReady() はボタンの表示を変えているだけです。
    Advertisement.Show を呼び出すと広告の表示をします。必ず成功するわけではありません。このメソッドの引数にラムダ式を渡していますが、それにAdvertisement.Show の実行結果を渡します。(渡されるタイミングはわかりませんがいずれ渡されるのは確実のようです。)失敗、広告がスキップされた、広告が最後まで見られたの3通りの結果があります。サンプルでは結果をログに出しているだけですが、この引数によって処理を変えれば広告を見たときだけリワードを渡すといったことができます。

    大雑把に言うと、Advertisement.Initialize を行った後にAdvertisement.Show を呼べば広告が表示されます。広告が表示できないこともありますが、Advertisement.Show を呼んだときに処理がうまくいっていれば広告が出ます。その2つだけで実装は可能です。

    サンプルの説明は以上です。
    一応使えるものですが、実用には向かないと思います。なぜなら通信が遅いときや通信が失敗したときのことを考えられていないように思うからです。
    サンプルのままだと広告再生をしても失敗するということが多く起こると思われます。これについては今度説明したいと思います。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Unityのエディター上では簡単にFPSを表示できます。
    ゲームビューのStatusボタンを押すと、画面の右中段に表示されます。
    簡易的に調べられるので便利です。
    実機上の確認には使用できないので端末の性能を測ることに使えません。
    つまり、リリースするときの機種次第では目安程度の意味しかありません。
    FPSが急激に変わったりすることを見つけるとかに使いましょう。

    FPSの表示をするにはOnGUIを使うのが簡単です。
    Unity UI(uGUI)を使ってもかまいません。 
    表示方法は何でも良いです。 

    FPSを測るには2通りあります。
    • 定義通り、1秒間に何回更新が行われたかカウントする方法 
    • 更新間隔を測り、その逆数をFPSとする方法
    1秒間を測りその間に何回更新されたかをカウントして、FPSを求めます。
    FPS = (更新回数)
    定義通りの値であり、整数値が返ります。利点は見やすく、ゲームの1秒ごとのパフォーマンスが把握できることです。1秒というのはそれなりに長いので、パフォーマンスが良い悪いという指標に使いやすいです。
    欠点は瞬間的なパフォーマンスの悪化を見逃すことと実装の面倒さです。
    1秒ごとというのを判定し、そのたびに初期化をして繰り返すといったことになります。

    更新間隔を測ることから求める方法は、測った更新間隔でこの後も処理が続くと仮定して1秒間に何回更新されるかを決定しています。
    FPS = 1 / (更新間隔) 
    になります。
    1フレーム前の更新時刻を 記録しておけば毎フレームFPSを求めることができます。この方法の 利点は瞬間的な処理の速さを知ることができることと実装が簡単ということです。欠点は瞬間的なゲームのパフォーマンスしか測れないことです。 

    FreelyAppsでは2番目の方法を使っています。
    そのまま使うと継続的なパフォーマンスがわかりにくいため、平均を用いてある程度の長さでのパフォーマンスを測っています。
    最新の更新間隔だけでなく、いくつか前の更新間隔も記憶しておくということです。



    fFPSとfAveFPSには毎フレーム更新された値が入ります。
    上では30フレーム分の更新間隔を平均し、その更新間隔からfAveFPSを求めました。
    この値をOnGUIかUnity UIで出せばいいわけです。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Application.OpenURLという関数は呼び出すと、ブラウザを開き、引数に指定したURLに飛ぶことのできるものです。

    Application.OpenURL("http://freelyapps.blog.jp/");
    というように書けば、ブラウザが開きます。一旦アプリの実行はされなくなります。
    音を鳴らそうとしていたりすると、ブラウザを閉じてアプリに戻ってきたときに再生されたりします。
    あまり重要な処理は、この関数の前後で呼ばない方が良さそうです。

    この関数を使うと、アプリ内から自分の作った他のアプリの一覧のページ(Google Playの開発者ごとのページ)に誘導したり、Twitterへ投稿のリクエストをするといったことができます。
    アプリ内でWebページを見るということはできませんが、簡単に外部のWebページに誘導できるので、ヘルプページの作成なんかには役立つと思います。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    以前の記事でMeasurement Protocolを使って、アプリのイベントを計測しようとしていました。
    ユーザーがどのステージに入ったとか、どの画面に入ったことなどを計測することでゲームの改善やバグの発見に役立てることができるからです。

    調べていると、海外で実装できているサイトがありました。
    さっそくダウンロードし、試してみると動きました。
    私のコードと比較して何が違うのか調べたところ、送信しているパラメータに違いがありました。
    anというアプリケーション名を指定するものを送る必要があったのです。
    公式の解説にも設定は必須ではないとあるので、気づきませんでした。
    これを設定しないと計測できないので、解説が不十分であると思います。
    より正確に言うと、モバイルアプリをトラッキングするという設定にした場合にanが必須ということです。

    Google Analyticsの「新しいプロパティ」を作る画面でトラッキングの対象をモバイルアプリと選んでいました。
    計測対照がアプリなのだから適切であると思います。
    ただし、結果的にはこれがうまくいかない原因になったのです。

    トラッキングの対象をモバイルアプリに選んだ場合、
    Measurement Protocolで情報を送るにはv,tid,cid,t以外にanが必須ということです。

    http://www.google-analytics.com/collect?v=1&tid=UA-XXXXXXXX-X&cid=0&t=event&an=YourAppName
    みたいにすれば計測ができます。
    anの値はプロパティ名と関係なくても計測できました。
    存在していることが重要みたいです。

    問題が解決して良かったです。
    公式のページに載っている情報に足りない情報があるというのは、困りましたね。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    Google アナリティクスの機能としてHTTPリクエストを送ることでデータを集計することができます。Measurement Protocolというものです。
    これを使うとUnityからHTTP リクエストを送信してGoogle Analyticsに情報を送ることができます。Unityで作ったゲームを何らかのSDKを使わずにスクリプトだけでGoogle Analyticsと連携させることができるということです。

    UnityではWWWクラスを使うと簡単にHTTPリクエストが送れます。
    WWW www = new WWW(URLを文字で書く);
    というようにするだけでアクセスできます。

    Measurement Protocolが要求するURLを作成し、
    WWWクラスにそれを渡せば、Google Analyticsで統計がとれるはずです。

    実際に試してみたのですが、
    管理画面でアクセスがとれていません。
    通信は成功しているようでレスポンスがあります。

    私にはお手上げです。
    もう少し調べてみようと思いますが……

    【追記】
    解決しました。

    このページのトップヘ