原カバンは鞄のお店ではありません。

Unityを使ったゲーム制作のあれこれを綴っていきます。

【Unity】Android版からiOS版へ移植するまでのTips

iOS版テスト中

そういえば芥川賞作家の平野啓一郎センセイが突然、『お笑い芸人とはどうあるべきか』みたいなことを呟き始めたのを見て、流石にお顔がバカリズムに似ているだけあって文学だけでなく『芸人論』にも深い見識をお持ちなのだなぁと、感心したり、しなかったり、しなかったりしながら今日も「Dull Things No Life」の製作に励んでいるわけですが、ようやくiOS版でも実機のアルファテストを進めることが出来るようになりました。

 

f:id:Karvan:20190305232157p:plain

 

AndroidよりもiOSの方がメモリ管理には厳しいという印象があるのですが、今のところ順調に進んでいます。後はメモリ管理より厳しいAppleStoreの審査まで進捗が滞りなく完了してくれることを祈るばかりです。

 

f:id:Karvan:20190305232312j:plain

 

Android版からiOS版へ

「Dull Things No Life」の開発環境としてはWindowsPCで開発しているので、まず先にAndroid版を開発し、その完成版をiOS版へ変換するという手順になっています。

 

ただ、Unityで製作したアプリをiPhone等の実機で動かすための手順としては

  1. UnityプロジェクトのプラットフォームをiOSに切り替える
  2. Unityでビルドし、Xcodeプロジェクトを生成する
  3. Xcodeで2.生成したプロジェクトをビルドして実機(iPhone等)で動作させる

となります。

 

このためiOS版の開発を行う場合は、どうしてもXcodeが動作する環境(=iOSが動作する環境)が必要なので、今回の場合は

  1. Windows上で作成したUnityのプロジェクトをiOS版へSwitch Platform
  2. それをMacBookの方に丸ごとコピー
  3. iOS版のUnityでプロジェクトをオープン⇒ビルドして、Xcodeプロジェクトを生成する

という手順で開発を行っていました。

 

ただ、その作業の中で色々な問題が発生して対処に追われたので、備忘録も兼ねて記事にしたいと思います。

 

諸問題と対処法

■問題1:iOS Build Supportをインストールしてなかった

Unityはマルチプラットフォームに対応しているのでAndroid版からiOS版へ変換は「Build Settings」の「Switch Platform」で一発で出来のでそこまでは非常に簡単です。(時間は掛かるけど)

 

もちろんiOS版へ変換するには事前に「iOS Build Support」のパッケージがインストールされていることが必須なのですが、今回、そのパッケージをUnityインストール時にすっかり入れ忘れていました

 

■対処1:Unityインストールバッチを再度実行

Unityインストールバッチを再度実行し(Unityはアンインストールしない)、インストールモジュールを選択するウィンドウで「iOS Build Support」のみを選べば追加でインストール可能です。

 

■問題2:ビルドボタンが押せない

上記の対処でプラットフォームの切り替えは行えたのですが、今度はUnityのビルド画面でビルドボタンがグレーアウトされて押せない、表示されているエラーを見てみるとGraphinsAPIの設定がおかしいようで。。。

 

■対処2:Auto Graphics APIの設定を見直す
Android版からiOS版へ変換するとビルドに必要な情報(アプリアイコンや、CompanyNameや、ProductName等)はそのまま残っているので特に変更する必要はないのですが、Graphics APIの設定が「Metal」のみとなっている場合はあります。

(iOS12からOpenGL ESが非推奨になった所為?)

f:id:Karvan:20190305232806p:plain

 

とりあえずこのままではビルドが進まないので、「Other Settings」の「Auto Graphics API」のチェックを外して「OpenGLES2」「OpenGLES3」が含まれているか確認⇒
「OpenGLES2」「OpenGLES3」が含まれていない場合は「+」を押して追加します。

 

■問題3:ビルドエラーが発生してXcodeプロジェクトが生成されない 

今回の場合、上記の対処を行った後にビルドボタンを押すと、ビルドエラーとなり肝心のXcodeプロジェクトが生成されない事態に。試行錯誤を繰り返してやっと以下の結論に達しました。

 

■対処3:Windowsのプロジェクトを丸ごとコピーしない
前述のようにWindows上で作成したプロジェクトをMacBookの方に丸ごとコピーして、iOS版のUnityでプロジェクトをオープン⇒ビルドしていたのですが、そうするとビルドに不要なファイル、ディレクトリが含まれたままでエラーとなるようです。

 

なので、プロジェクトを丸ごとコピーするのではなく「Assets」と「ProjectSettings」のフォルダ、「Temp」フォルダを削除した「Library」フォルダをコピーして、シーンファイルをクリック⇒プロジェクトを再構築することでビルドエラーは発生しなくなりました。

 

ちなみに「Library」フォルダをコピーしたのは、ゲーム内で「TimeLine」と「Cinemachine」を使っており、その定義が「Library」フォルダ内に含まれているからです。

「TimeLine」や「Cinemachine」を使っていない場合は「Assets」と「ProjectSettings」のフォルダのみのコピーで大丈夫だと思います。

 

まとめ

  • 「iOS Build Support」をインストールし忘れていたら、Unityのインストールバッチを再度実行して「iOS Build Support」のみを選択する
  • ビルド前に「Auto Graphics API」のチェックを外して「OpenGLES2」「OpenGLES3」が含まれているかチェックする
  • Windowsで作成したUnityのプロジェクトをMac側にコピーするときは「Assets」と「ProjectSettings」のフォルダのみ(場合によっては「Library」フォルダ(Tempフォルダを除く))をコピーする

 

今回はXcodeプロジェクト生成までに発生した問題について記載しました。
それ以後の作業で発生した問題についてはいずれ記事にしたいと思います。

 

【Unity】アセット『Easy Mobile』を使ってAdmob広告を実装

デザインを変えた

第二弾アプリをリリースするにあたって気分を一新しようと、当ブログのデザインを変えてみました。


まぁこのブログの読者の方々は定期的に訪れてくださる方よりも、Google検索で何かしらのキーワードに引っかかってここに流れ着いた可哀想な方々が大多数なので気づかない、ってかどうでもいい、とは思うのですが、一応お知らせまで。

 

後、気づかないうちにAdsenseの審査に通ってた。今月は800円ぐらいもらえます。有難うございます。

 

Android版アルファテスト完了

前回の記事で大騒ぎしていた問題が以外にアッサリと片付いたので「Dull Things No Life」のAndroid版についてはアルファテストの完了までこぎつけました。

 

f:id:Karvan:20190225205850j:plain

 

後は少しパラメータを調整して正式リリースするだけなのですが、本来の予定より大幅に遅延したし、特に予約トップ10とか利用してリリース日を予告してるわけでもないし、別にリリースを待ち望んでいる民意があるわけでもないし、「民意」って言葉を頻繁に使うやつらは胡散臭いし、で、もうここまできたらiOS版と同時にリリースしようとの結論に至ったので、現在はiOS版の製作に注力しています。

 

f:id:Karvan:20190225210410j:plain

 

iOS版はAndroid版と中身は変わらないのでビルドと実機による動作確認だけ、とは思っていますが、なにせGooglePlayとは異なりAppleStoreへアプリを掲載するには厳しい審査を通らないといけないので、リジェクとされたらどうしよう、と今からビクビクしています。リジェク理由とか英語でくるんでしょ?Google先生フル活用しないといけない。。。

 

なんとか審査が通りますように・・・

 

広告を手軽に実装したい

さて、今日のモバイルゲームには、広告、課金処理、通知から共有および評価システムまで、さまざまな「事実上の標準」機能があります。
これらはゲーム本編とはあまり関係のない機能なのですが、とはいえ、DL数を増やしたり、マネタイズのことを考えると、ゲーム本編の開発と同じぐらい注力して実装する必要があります。

 

まぁ、Google先生に尋ねてみればこれらの処理について詳しく紹介している記事を数多く見つけることができるので、
それらを参考にしながら処理を組み込んでいくことは、ゲーム開発を出来るぐらいのスキルがあれば難しくないことだと思います。

 

だが、しかし・・・

f:id:Karvan:20190225211014p:plain面倒くさい

 

いくらそれほど難しくないとはいえ、コードもそこそこ書かないといけないし、ゲーム本編を開発する時ほどの時間を掛けたくないも事実です。

 

そんなこんなを考慮して機能統合系のアセット『Easy Mobile』を使うことにしました。
(まぁ、前回の記事で紹介したGDPR対応の機能も含まれている、という事も理由になっていますが) 

assetstore.unity.com

事前準備

アセットを使って手軽に、とはいえAdMobへの申し込みやらアプリの登録やらの作業は避けて通れないので、アセットを組み込む前に以下の準備は事前に行う必要があります。

 

・AdMob に申し込む

 AdMobに登録が済んでいない場合は申し込みをします。 

support.google.com

・アプリIDを確認する

  1. https://apps.admob.comから AdMob アカウントにログイン
  2. サイドバーから [アプリ] ⇒[アプリを追加] を選択
  3. アプリを既に公開している場合は[検索]して追加、未公開の場合はアプリ名とプラットフォームを入力して追加
  4. サイドバーで [アプリ] ⇒[アプリの設定] でアプリIDを確認

 

・広告を作成

  1. https://apps.admob.comから AdMob アカウントにログイン
  2. サイドバーで [広告ユニット] ⇒[広告ユニットを追加] を選択
  3. 作成したい広告を選んで広告ユニットを作成
  4. 「広告ユニット」 ⇒「作成した広告ユニット名」を選択

 

詳細はAdMobヘルプを参照してください。

 

EasyMobileでの設定

最初にEasyMobile側で広告(Advertising)のモジュールを有効にする必要があります。

[Window]> [Easy Mobile]> [Settings]に移動してから、[Advertising]タブの右側にあるトグルをクリックして、モジュールを有効化します。

 

f:id:Karvan:20190225212334p:plain

 

次に[Advertising]の項目をクリックすると設定画面に遷移します。
ここでAdmobのSDKが未だインポートされていない場合は、その旨のメッセージが出ているので[Download Google Mobile Ads Plugin]ボタンをクリックしてプラグインをダウンロード⇒インポートしてください。

 

f:id:Karvan:20190225212453p:plain

 

AdmobのSDKがインポートされると以下のような画面になるので、アプリIDと広告IDを入力します。その他の項目はデフォルトのままでも問題ありません。

 

f:id:Karvan:20190225212558p:plain

 

『Easy Mobile』では複数の広告ネットワークに対応しているので、デフォルトで表示する広告ネットワークを設定します。
今回の場合は全てAdmobで問題ありませんが、広告タイプごとに異なるネットワークを使用し、プラットフォームごとに選択を変えることができます。

 

f:id:Karvan:20190225212727p:plain

 

また、『Easy Mobile』では広告の可用性を定期的にチェックし、広告が読み込まれていないか消費されている場合は読み込みを実行してくれます。
Auto-Ad Loading欄にその設定があるのですが、特にデフォルトのままで変更する必要はないです。

 

f:id:Karvan:20190225212903p:plain

 

ここまで設定したら後はスクリプトでの実装になります。

 

スクリプトでの実装(リワード広告)

リワード広告を表示する方法では、広告が既に読み込まれている必要があります。
そのため、表示する前に広告の掲載状況を確認する必要があります。
準備完了を確認して広告を表示する処理はこんな感じ

 

f:id:Karvan:20190225213042p:plain

 

RewardsAdCompletedイベントは、リワード広告が完了するたびに発生します。
このイベントを発生後に広告を見たことに対してユーザーに報酬を与えます。
それ以外の場合はRewardedAdSkippedイベントが発生します。
実装例はこんな感じになります。

 

f:id:Karvan:20190225213139p:plain

 

これで広告(リワード広告)の実装は完了です。

 

手順をまとめると

  1. アプリID、広告IDを確認する
  2. EasyMobileのウィンドウにアプリID、広告IDを設定する
  3. EasyMobileのAPIを使って広告表示を実装する

 

広告の実装だけで言うと、EasyMobileを使わなかった場合の工数もあまり変わらない気がしますが、定期的に広告の読み込みを実行してくれる機能と、複数の広告ネットワークが使える機能はそこそこ有効なのかな、とは思います。

 

『Easy Mobile』では広告以外にもGDPRへの対応、課金や通知処理、ゲーム画面からGIFを作るなどの機能も含まれているので、それらも実装したい方には工数を省く手助けとなると思います。

 

【Unity】GDPR対応と状況報告

状況報告

本来の予定なら今回の記事を更新するタイミングで、現在製作中のアプリ「Dull Things No Life」のAndroid版に関して「Google Playにリリースしました!」とお知らせを掲載するはずだったのですが、後述する問題により今のところアルファ版リリースで進捗が留まっています。

 

f:id:Karvan:20190219221455j:plain

 

一般公開直前のこのタイミングで進捗が止まってしまうのは予想外で非常に残念で仕方ありませんが、ずっと頭を抱えているだけでは事が進まないので何とか問題を解決できるように努力していきたいと思います。

(追記:解決しました^_^;)

 

とはいえ宣伝

首を垂れてばかりいても仕方ないのでアプリの宣伝をします。

おちこんだりもしたけれど、私はげんきです。

「Dull Things No Life」で登場する障害物についての紹介。

 

Ascii

BGMに合わせて立体化した文字が現れます。

スライディング動作で回避してください。

出現するタイミングは毎回同じなので、慣れてくれば簡単にかわせます。

f:id:Karvan:20190219221943g:plain

 

Window

MontorBikeが近づくと窓の一部が壊れるので、その壊れた隙間を狙ってジャンプしてください。
どこが壊れるかは毎回ランダムなので、じっくりと観察する必要があります。

f:id:Karvan:20190219222037g:plain

 

Net

前回紹介したShutterとは逆で、初期状態では通路がネットで閉じられています。しかしMontorBikeが近づくとその一部が消滅するので、その空いた空間を通って進みます。

半回転しながら避けていくイメージです。

f:id:Karvan:20190219222220g:plain

 

Circle

これは名前だけの紹介です。どんな障害物なのかは実際のPlayで確かめてください。

 

障害物の紹介は今回で最後です。
ここまで載せた情報は正式リリースまでに一つのページに纏めたいと思います。

 

で、ここからが本編

 

EU一般データ保護規則(GDPR)対応

昨年、スマホ用アプリの開発者の間で騒がれていたので知っている方も多いと思いますが、現在EUでは一般データ保護規則(GDPR)とやらが施行されており、EU諸国で単純に広告を埋め込んだアプリを展開する事はNGとなっています。

 

よって広告表示有りのアプリをEU諸国にも配布しようと思えばGDPR対応が必須となるわけですが、元来面倒くさがり屋で不勉強な性質なので、やらなきゃいけないとは分かってはいるものの、対応が後回し後回しとなっていました。まるで夏休み最終日に宿題を終わらせようとする小学生みたいに。

 

現在GDPR対応についてGoogle先生に尋ねてみると、対応内容が詳細に書かれた記事がアチコチに発見できます。個人的には以下の記事が非常に参考になりました。アプリの広告にAdMobのみを使っている方はその記事の内容で十分対応可能だと思います。

 

qiita.com

ざっくりと概要だけ

GDPR対応の手順につい細かく書き出すと長くなるので、ざっくり纏めると以下のようになります。(AdMobを使っている場合)

 

AdMob側の対応

  1. https://apps.admob.com からAdMob アカウントにログイン
  2. [ブロックの管理] > [EU ユーザーの同意]の順にクリック
  3. 表示される「EU ユーザーの同意」ページで、広告技術プロバイダの選択で「広告技術プロバイダのカスタム グループ」を選び、Googleだけが選択されていることを確認
  4. 「変更を保存」を押す

 

アプリ側の対応

  1. ユーザの居住地をチェックし欧州経済地域(EEA)地域かどうか判定する
  2. 欧州経済地域(EEA)地域の場合、Personalized対象となる広告を表示してよいかの同意を取る。(EEA地域以外の場合は以後の処理は不要です)
  3. 広告を表示する(リクエストする)際に、Personalized対象広告に対しての同意情報を反映させる
  4. ユーザがいつでも同意を変更or取り消しできるようにする

 

コレだけ見ると特に難しいことをする必要はないみたいです。

 

アプリ側の対応は自力でスクリプトを組む必要がありますが、私は以下のアセットを使って実装しました。

 

assetstore.unity.com

アセットを使う決め手となったのはアセット内にあるデモ用のダイアログの処理がほぼそのまま使える事で、「同意をしますか?同意した場合は・・・」みたいな文章もそのままでよかったので非常に手間が省けたと思います。

 

f:id:Karvan:20190219223506p:plain

こんな感じのダイアログ、文章がほぼそのまま使えます。

同意情報はPlayerPrefsに保存され、再度ダイアログを開くとPlayerPrefsから同意情報がロードされてダイアログに反映されます。

 

GDPR対応に頭を悩ませている方は一度検討されてはどうでしょうか?

 

 

 

【Unity】ダメージ表現にはカメラを手ブレ風に

GDPR対応とは

もう既にゲーム本編の作成は終わっているのですが、これを正式リリースするためには諸々の作業が必要でして、何より前作をリリースした時と状況が異なるのは『GDPR対応』とか言う面倒くさい作業が必要になっているようで、一体それは何?から始まって何かしら英語の文章を作らないといけない事がわかって、英語を勉強をしてこなかったことを今更後悔して、それでも仕方ないのでGoogle先生の力を借りようにも、その前に『同意してください』的なお堅い文章を書くこと自体が出来なかったりして、それじゃぁに参考になりそうな文章を探そうとネットを彷徨っているうちに何故か添い寝JKにキスをしようとして店員に土下座して謝る動画を見ているとか、そんな無駄な日々を過ごして進捗が遅れています、どうしよう。あとGDPR対応についてはいずれ記事に書こう。

 

最初に宣伝

さて「Dull Things No Life」に登場する障害物紹介の二回目です。

 

Display

BGMに連動して文字を画面に表示します。

このアプリのアイコンにも登場する予定の障害物です。

 

f:id:Karvan:20190122223555p:plain

こんなやつ

 

特におかしな動作はしないのでタイミングを計ればかわす事ができます。

f:id:Karvan:20190212233622g:plain

 

下をくぐってかわすタイプ以外にも飛び越えてかわすタイプがあります。

f:id:Karvan:20190212233801g:plain

 

Shutter

MotorBikeが迫ってくると通路の片側を閉じます。

事前に「右へ」「左へ」の表示が出るのでシャッターが閉じ始めたらそちらへ移動しながら壁をぐるっと一周廻ってかわします。

f:id:Karvan:20180822001122g:plain

動画では難しそうですが一度コツを掴むと意外と簡単にかわせます。

Pillar

空中から上下方向にレーザーを発射します。

レーザーが発射されない箇所には矢印が表示されるので、そこを通って先に進みます。個人的には一番難易度の高い障害物だと思います。

f:id:Karvan:20190212234112g:plain

反射神経が問われる障害物です。

 

障害物紹介は次回で最後になります。

 

カメラを揺らす

「Dull Things No Life」はいわゆるRUNゲームなので障害物に当たってはダメなのですが、他のRUNゲームのように「一発死」はしない(ゲームモードによって)ので、当たったよ!=ダメージを受けたよ!的な表現をあの手この手でしています。
SEを鳴らしたり、パーティクルを表示したり、画面に「MISS」と表示したり。。。

 

その中でも『カメラをランダムに揺らす』というのは非常に有効で、誰が見ても「あ、これはアカンな」と言うのが伝わる。なにせ画面が揺れるし。

 

カメラを揺らすにはTween系のAPIを使ってもいいし、カメラ用のアセットを使っても良いのですが、スクリプトを自作しても簡単なので紹介したいと思います。

public class CameraShaker : MonoBehaviour {
    [Header("Shake")]
    public Transform ShakeObject = null;   // ここにカメラオブジェクトを設定する
    public float ShakeIntensity = 0.02f;   // カメラの揺れの強さ
    public float ShakeDecay = 0.002f;      // 揺れの減算値
    public float ShakeAmount = 0.2f;       // 揺れの強さ係数
    
    private Vector3 originPosition;
    private Quaternion originRotation;
    
     void Start()
    {
        originPosition = ShakeObject.localPosition;
        originRotation = ShakeObject.localRotation;
    }
   
    public void Do()
    {
        StopAllCoroutines();
        StartCoroutine(Shake());
    }
    
    public IEnumerator Shake()
    {
        float shakeIntensity = ShakeIntensity;
        while (shakeIntensity > 0)
        {
            ShakeObject.localPosition = originPosition + Random.insideUnitSphere * shakeIntensity;
            ShakeObject.localRotation = new Quaternion(
                originRotation.x + Random.Range(-shakeIntensity, shakeIntensity) * ShakeAmount,
                originRotation.y + Random.Range(-shakeIntensity, shakeIntensity) * ShakeAmount,
                originRotation.z + Random.Range(-shakeIntensity, shakeIntensity) * ShakeAmount,
                originRotation.w + Random.Range(-shakeIntensity, shakeIntensity) * ShakeAmount);
            shakeIntensity -= ShakeDecay;
            yield return false;
        }
        ShakeObject.localPosition = originPosition;
        ShakeObject.localRotation = originRotation;
    }
}

上のソースをオブジェクトにアタッチ→EditorからShakeObjectにカメラオブジェクトを設定、必要なタイミングでDoメソッドをコールするだけです。

 

実際に動作させるとこんな感じ

f:id:Karvan:20190212234844g:plain

 

カメラを揺らす演出はいろんな場面に使えると思います。やる過ぎると酔うけど


 

【Unity】窓シェーダーを使ってみた

ゴール前が一番しんどい

どこかのブログに「ゲーム作りは80~90%出来上がってからが大変」みたいな記載があって、当初はそれを疑っていたのですが、いざ自身が制作する身になってみると本当にその通りらしく、3日間頭を抱えたバグの原因がスクリプトにたった一行足らなかっただけだったりして、仕様書も書かずに行き当たりばったりで作っている自分が悪いとはいえ、ゴールを目の前にして足踏み状態が続く苛立ちとか心の叫びを文字におこしたら結構すごいわ、とか、わけの分からない言葉が頭を巡っている日々が続いています。

 

窓シェーダー

そういえば以前「窓越しにオブジェクトを表示する」窓シェーダーを紹介したのですが、そのときは当該の記事をリンクするだけで実際のユースケースについては触れていませんでした。

 

styly.cc

窓シェーダーを使用すると「窓越しにオブジェクトを表示する = 窓越しに見ないとオブジェクトは表示されない」といった表現が可能になるのでビックリするような仕掛けを作ることができます。

 

使い方も簡単で「窓」オブジェクトと「窓の向こうに置く」オブジェクトのそれぞれに専用のシェーダーをアタッチするだけです。

 

実際のシェーダーのコードは上記のリンクを参照してください(コードの転記はしません)。

 

こんな感じの絵を作る

f:id:Karvan:20190205232731p:plain

 

「Dull Things No Life」ではタイトル画面でMoterBikeが登場するアニメで使用しています。MoterBikeが転送されて現れるようなイメージを表現したかったんです。

 

作り方は単純でMoterBikeに「窓の向こうに置く」用シェーダを適用して、「窓」側のオブジェクトの奥(カメラから見て)に配置
ただ、「窓」が一面だけでは立体感がでないので二面用意して、その上下にそれっぽいスプライトを配置しています。

 

f:id:Karvan:20190205232952p:plain

 

こんな感じ、ちなみに「窓」側のオブジェクトは見えない(表示されない)です。

で、後は「窓」側のオブジェクトのサイズをDoTweenを使って動かします。

 

f:id:Karvan:20190205233050g:plain

 

結構いい感じに出来たのではないでしょうか?

 

で、ここから宣伝

「Dull Things No Life」では主に柱やCUBEなどが自機であるMoterBikeの前に立ちふさがりますが、それ以外にもステージによっては特殊な動きで自機の行く手を阻む障害物が存在します。

 

これらの障害物はその動作を良く見れば回避方法は分かるのですが、初見では意外と厳しいかもしれません。MoterBikeも結構な速さで動いているし。
なのでレビューサイト等で「初見殺しじゃん、クソゲー」とか言われない為にも、その幾つかを回避方法とあわせて紹介したいと思います。

 

Missile

空中から自機に向かって飛んでくるのでスライディングでその下を潜り抜けて回避します。自機が移動しても追尾して真直ぐ飛んでくるのでかわすタイミングが難しい障害物です。

f:id:Karvan:20190205233418g:plain

 

どうしても難しいなら自機をローリングさせれば回避できます。

f:id:Karvan:20190205233454g:plain

 

Rain

天井から無数のBOXが降り注ぎます。近づくと安全地帯が表示されるのでそちらに進んで回避します。安全地帯にはBOXが降って来ません。

f:id:Karvan:20190205233609g:plain

 

Box

上空に向かってレーザーを発射します。一部のBOXからは発射されないので、その空いたところをジャンプして回避します。
動きを良く見るとレーザーを発射するBOXは事前に回転するので、回転しないBOXの位置へ自機を移動⇒ジャンプします。

f:id:Karvan:20190205233831g:plain

 

この他にもまだまだあるのですが、それは次回以降に紹介したいと思います。

 

 

【Unity】負荷削減のTipsとか

突然の通知

GooglePlayにアプリをリリースして開発者登録をしていると時折Googleから通知メールが届くのですが、大抵(ってかほとんど)が英語で書かれているので、学生時代に英語が嫌いすぎて理系を選択した私としては読むのが面倒でそのまま放置していました。が、しかし、、先日、何気にGoogleのコンソールを開くと赤枠でデカデカと「ポリシー違反のため、1 つ以上のアプリが Designed for Families プログラムから削除されました。」との表示が。

 

どうやらGooglePlayのポリシーが最近変更になったようで、おそらく「交換条件として広告を表示してはいけない」ってのに違反していると思われる。


つまり、「広告を視聴するとスタミナ回復」だとか「広告視聴でコンティニュー」だとかが軒並みNGということで、イヤイヤ、

 

f:id:Karvan:20190129201805p:plain


それじゃぁ「ステージクリア毎に広告を強制表示」みたいな手法が良いっていう事?それはウザすぎる。いまさらバナー広告に移行しようとは思わないし、もういいや。。。ってこれも放置していたら、当該アプリのAdwordsの広告表示回数が10分の1以下になった。ギャフン

 

そして宣伝

そんな感じでGoogleから虐げられながらも近々リリース予定のアプリの宣伝

 

「Dull Things No Life」では左右に動いて障害物を避ける以外に、画面をタップすることで主機であるMotorBikeに独自のアクションをさせて障害物をかわす事ができます。

 

アクションの種類は3種類で、それぞれ目の前の障害物に応じてMotorBikeが自動的に判断し、その動作を行います。

 

■ドリフト

f:id:Karvan:20190129202017g:plain

 

■ジャンプ

f:id:Karvan:20190129202121g:plain

 

■スライディング

f:id:Karvan:20190129202221g:plain

 

ただ、いつでもタップすればよい、と言うわけではなくてMotorBikeの前方にある黄色いラインに障害物が差し掛かると赤色に変わるので、そのタイミングで画面をタップします。

 

要は音ゲーで良くある、ここのラインにノーツがきたらタップ!と同じ操作だと思ってください。

 

このアクション動作による回避方法は「Dull Things No Life」では非常に重要で、障害物の一部にはアクション動作をさせないと回避不可なものがあります。

 

次回は「Dull Things No Life」で登場する特殊な障害物について紹介したいと思います。

 

負荷軽減をしなくては・・・

携帯向けのアプリを作成しているとどうしても突き当たる問題が、開発用PCと実機(携帯端末)とのスペック差

 

前回の記事でも書いたようにPC上ではスムーズに動くのに実機ではモッサリ動作、音楽と同期させようとするとズレて動作したりなどゲームとして成り立たなくなるので出来るだけ軽量に動くように対処する必要があります。

 

負荷軽減のまず第一歩としてよく取り上げれるのは「ドローコール(SetPassCall)を減らす」と言う題目で以下のような対処方法が有名です。

 

ドローコール(SetPassCall)を減らす対策

  • 動かないオブジェクトはstaticにチェックを入れておく
  • 複数マテリアルを1つのテクスチャにまとめる
  • メッシュの結合を行う(専用アセットが必要です「Mesh Baker」とか)
  • カメラのEffectをはずす
  • 影を描画しない

 

これらは確かに有効な方法ですが、主にGPU負荷に対する軽減策となっているのでCPUの負荷に対してはスクリプトを見直す必要があります。

 

スクリプトによる負荷軽減

スクリプトの見直しとして主に取り上げられる対策は

  • 不要なStart,Updateメソッドを削除する
  • FindやGetComponentなど処理の重いメソッドを減らす
  • JobSystemを使ってマルチスレッドで処理する
  • foreachやstringの結合などGCが発生するものは避ける

 

等がありますが、これに加えて以下の方法も意外と有効です。

 

  • gameObject.tag == "タグ"ではなく gameObject.CompareTag("タグ")を使う

 

  • Materialのプロパティを操作をする際に文字列でなくユニーク ID で指定する
int material_Color = Shader.PropertyToID(“_Color”);
material.SetColor(material_Color, Color.white);

 

  • Animatorのステートの指定は文字列でなくHash値を使用する
int anim_Attack = Animator.StringToHash(“attack”);
animator.SetTrigger(anim_Attack);

 

それでもダメなら・・・

上記の対策をしても未だモッサリ動作が直らない場合は、画面の解像度を下げる、という手があります。

ここ最近の携帯端末はカメラの性能競争が激しく、結果としてゲームを動かすにはオーバースペック気味の解像度を持ってたりします。

 

なので、この解像度を下げることでGPUの描画性能を上げて負荷軽減につなげる手法です。やり方はScreen.SetResolutionで画面の解像度を指定するだけ。

 

Screen.SetResolution( Screen.width*0.5f , Screen.height*0.5f, true);

 

上記の場合は解像度を半分に下げています。携帯の画面サイズだと解像度が半減したとしても意外とバレません。


ただ、テキスト等のUIも解像度が半減するのでネイティブ解像度と比較して若干見難くなるかもしれないので注意が必要です。

 

ドローコールやらスクリプトやら見直した後の最後の切り札として使ったほうが良いかと思います。

 

参考資料:

qiita.com

baba-s.hatenablog.com

 

【Unity】Objectを音楽と同期させて動かす時の注意

最初に宣伝から

現在、開発中のゲーム「Dull Things No Life」ですが、ようやく完成の目処が立ってきたので今回の記事からそのゲーム内容について紹介をしていきたいと思います。

 

f:id:Karvan:20190122223555p:plain


「Dull Things No Life」はいわゆるラン系ゲームというやつで、操作キャラクターが自動で走っているところをタップ操作で左右に移動させ、迫り来る障害物をかわしてゴールを目指して進んでいく、といった内容のゲームとなっています。

このゲームの操作キャラクターは赤色のMotorBikeで、画面の左右をタップすることでMotorBikeも左右に移動します。
またMotorBikeの走る経路はトンネルのように壁で囲まれていますが、上下左右どこの壁にも移動することが出来ます。

 

f:id:Karvan:20190122223646g:plain

 

こんな感じ、大きな柱が走路を塞いでいる場合は左右の壁に移動してそれを避ける事ができます。

画面の左右をタップするだけで難しい操作はありません。まぁ、類似のアプリは多々あるので「ああ、よくあるやつね」と思って頂いて結構です。

 

ただ、「Dull Things No Life」ではMotorBikeは左右移動だけでなく特殊な動作で障害物を避けることが出来るのですが、宣伝が長くなるのでこれについてはまた次回紹介したいと思います。

 

で、本題

UnityではObjectを移動させる処理は様々ありますが、よく使われる手法としてUpdate内で移動速度×前フレームからの時間差分=移動量を計算してObjectのtransformに反映する、という方法があります。

 

このとき前フレームからの時間差分にはTime.deltaTimeを使用しますが、このdeltaTimeはTime.timeScaleに影響を受けます。

 

Time.timeScaleはUnity内(ゲーム内)の時間の定義しているので、Time.timeScale = 1であれば現実の時間と同じ時間、この値を小さくすると現実の時間 > ゲーム内の時間となり、例えばtimeScale = 0.5とすると、deltaTimeが1.0(sec)だとしても現実の時間は2.0(sec)経過していることになります。

 

通常、timeScaleを意図的に変更しない限りは(timeScale = 1のままであれば)、現実の時間=ゲーム内の時間となるのでdeltaTimeを使用しても現実の時間と食い違うことはなく特に問題ない、と思っていました。

 

だが、しかし・・・

Mobile端末でゲームを動かす場合、PCと比べると演算性能や描画性能は劣るので、PC上のUnityEditorで確認した動作よりももっさりした(処理に時間が掛かる)動作になるのは仕方ないことだと思います。

 

ただ、どうもUnity内部にて(私の推測だけど)、処理に時間が掛かる分だけゲーム内のtimeScaleを調整しているようで、deltaTimeと現実の時間が一致しない状態になります。
つまり、こちらはtimeScaleを変更していないのに、現実の時間 > ゲーム内の時間、みたいな事象になるということ。

 

まぁ、現実の時間とリンクしない、ゲーム内の時間だけで完結するようなゲームの場合、それでも問題ないのでしょうが、音楽と同期させてObjectを動かしたい場合はちょっと問題です。

 

何が問題なのか

AudioClipによるSEやBGMの再生はtimeScaleの影響を受けません。つまり、かならず現実の時間と同じ時間だけ経過して音声を再生していきます。一方、Objectの方はtimeScaleの影響を受けてゲーム内の時間で動作するとなると、例えば、下図のような典型的な音ゲーを作る場合

 

f:id:Karvan:20190122224035p:plain

 

こんな感じの仕様となるので、各ノーツはそれに対応する音が再生されるより前に画面に表示する必要があります。

 

f:id:Karvan:20190122224156p:plain

 

しかし、移動処理でdeltaTimeを使用していると現実の時間 > ゲーム内の時間なのでノーツ移動が間に合いません。

 

f:id:Karvan:20190122224257p:plain

 

これはゲームとして致命的です。しかもUnity内部にて処理速度に応じて勝手に調整されているので(あくまで私の推測)、こちら側(製作者側)で遅くなるのを見越して移動速度を調整するような対処も行う事ができません。

 

なのでこんなときは・・・

timeScaleに影響ない前フレームからの時間差分を得る場合にはTime.unscaledDeltaTimeを使用します。

 

deltaTimeとunscaledDeltaTimeの違いはtimeScaleの影響ありなしだけなので、通常時はdeltaTime=unscaledDeltaTime=現実の時間となっていますが、上記のように音楽と同期させるために必ず(勝手にtimeScaleが変わっても)現実の時間とリンクが必要な場合はunscaledDeltaTimeを使用して処理を組み込む必要があります。

 

ちなみに、Objectを移動させるのにiTweenやDoTweenを使っていても特にオプションを指定してない限りは同様の現象になります。また、Animatorでも同様です。

 

以下にtimeScaleを考慮しない場合のオプションを記載します。

 

  • iTweenの場合:ignoretimescaleプロパティをtrueに設定する

   Hashtable ht = new Hashtable ();

   ht.Add ("ignoretimescale", true);

 

  • doTweenの場合:Updateオプションをtrueに設定する

   DOTween.To( ~ ).SetUpdate( true );

 

  • Animatorの場合:updateModeプロパティにUnscaledTimeを設定する

        animator.updateMode = AnimatorUpdateMode.UnscaledTime;

 

注意事項

前述のようにunscaledDeltaTimeはtimeScaleを考慮しないので、例えばPause処理などでtimeScale=0としていても関係なく動作します。

 

また、オブジェクトが一旦非Active状態になると、その間の差分時間が加算されていくのでActive状態に戻ってUpdateでunscaledDeltaTimeを取得すると、最初フレームでunscaledDeltaTime = 非Active状態だった時間、が返ってきて、一気に時間が経過したような動作になるようです。


これについては以下のkan.kikuchiさんのブログに詳しく書かれています。

 

kan-kikuchi.hatenablog.com

 

 

 

 

 

◇プライバシーポリシー

●個人情報の利用目的

当ブログでは、メールでのお問い合わせ、メールマガジンへの登録などの際に、名前(ハンドルネーム)、メールアドレス等の個人情報をご登録いただく場合がございます。

これらの個人情報は質問に対する回答や必要な情報を電子メールなどをでご連絡する場合に利用させていただくものであり、個人情報をご提供いただく際の目的以外では利用いたしません。

●個人情報の第三者への開示

当サイトでは、個人情報は適切に管理し、以下に該当する場合を除いて第三者に開示することはありません。

・本人のご了解がある場合
・法令等への協力のため、開示が必要となる場合

個人情報の開示、訂正、追加、削除、利用停止
ご本人からの個人データの開示、訂正、追加、削除、利用停止のご希望の場合には、ご本人であることを確認させていただいた上、速やかに対応させていただきます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。

●免責事項

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。

当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。

当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

●プライバシーポリシーの変更について

当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。

修正された最新のプライバシーポリシーは常に本ページにて開示されます。