のにっき

AdMob管理クラス作った

こんにちは。

昨日プライバシーポリシー違反的な奴で

Googleに公開していたアプリが全滅してアタフタしました。。。

 

今回はGoogleAdMobを実機に搭載する際、

通化したクラスで管理すると楽そうなので作ってみました。

※追記 2019/06/05
ver17.以降は必要な処理が増えたのでまとめたリンクを貼っておきます
GoogleAdMobインポート後に必要な作業 ※ver.17以降 - のにっき

クラス内容
    /***********************************************************
        クラス名    : GoogleAds
        概要        : 広告管理クラス
    ***********************************************************/
    public class GoogleAds
    {
        //===============================
        // 変数定義
        //===============================
        // テスト用
        //string appId = "ca-app-pub-3940256099942544~3347511713";         
        //string adUnitId = "ca-app-pub-3940256099942544/6300978111";     
        //string adUnitId_Pnl = "ca-app-pub-3940256099942544/1033173712";
        // 本番用
        string appId = "ここに取得したIDを設定";          // アプリID
        string adUnitId_Bnr = "ここに取得したIDを設定";   // 【バナー】広告ID
        string adUnitId_Pnl = "ここに取得したIDを設定";   // 【インスタンス】アプリID
        // 変数
        BannerView bannerView;
        AdRequest request;
        InterstitialAd interstitial;

        /***********************************************************
           コントラクタ   : GoogleAds
       ***********************************************************/
        public GoogleAds()
        {
            MobileAds.Initialize(appId);
            bannerView = new BannerView(adUnitId_Bnr, AdSize.SmartBanner, AdPosition.Bottom);
            request = new AdRequest.Builder().Build();
            bannerView.LoadAd(request);
            interstitial = new InterstitialAd(adUnitId_Pnl);
        }

        /***********************************************************
           メソッド     : SetBanner_
           概要           : バナー表示・非表示処理
       ***********************************************************/
        //********************************************************
        // バナー表示
        //********************************************************
        public void SetBanner_On()
        {
            bannerView.Show();
        }
        //********************************************************
        // バナー非表示
        //********************************************************
        public void SetBanner_Off()
        {
            bannerView.Hide();
        }

        /***********************************************************
           メソッド     : SetPanel_On
           概要           : インスタンス表示処理
       ***********************************************************/
        public void SetPanel_On()
        {
            //--------------------------------------------------------
            // 広告出力処理
            //--------------------------------------------------------
            AdRequest request = new AdRequest.Builder().Build();
            interstitial.LoadAd(request);
            //--------------------------------------------------------
            // 広告関係のイベント追加 ※固有の処理があったら記入
            //--------------------------------------------------------
            // 広告が表示可能になったとき
            interstitial.OnAdLoaded += (handler, EventArgs) =>
            {
                interstitial.Show();
            };
            // 広告が閉じられたとき
            interstitial.OnAdClosed += (handler, EventArgs) =>
            {
                interstitial.Destroy();
            };
            // 広告がエラーになったとき
            interstitial.OnAdFailedToLoad += (handler, EventArgs) =>
            {
                interstitial.Destroy();
            };
        }
    }
使い方例

1.シーンに影響しないスプリクトに下記のようにクラスを定義しておく

    public static GoogleAds Cls_Add = null;

 2.広告を表示したいシーンのどこかのオブジェクトに
  下記のスプリクトを設定する
【例】Title_AdCntrl という名のスプリクトを作成
仕様:ゲーム起動時にバナー広告を液晶下部に表示
タイトル画面に戻るたびに、ランダムでインスタンス広告を表示する

 public class Title_AdCntrl : MonoBehaviour
{
    void Start()
    {
        //=======================================================
        // 広告表示
        //=======================================================
        // 初回起動判定
        if (Cmn.Cls_Add == null)
        {
            Cmn.Cls_Add = new Cmn.GoogleAds();
            Cmn.Cls_Add.SetBanner_On();
            return;
        }

        //=======================================================
        // 2回目以降はインスタンス表示抽せん
        //=======================================================
        int i_Ransu = 0;
        int i_seed = 0;
        System.Random rnd_Ransuu;
        i_seed = Environment.TickCount + (int)DateTime.Now.Ticks;
        rnd_Ransuu = new System.Random(i_seed);
        i_Ransu = rnd_Ransuu.Next(100);
        if (i_Ransu < 66)
        {
         // インスタンス表示
            Cmn.Cls_Add.SetPanel_On();
        }

    }
}

f:id:apuridasuo:20190405182413p:plain
図:スクリプトの設定場所


以上です。
インスタンス広告が閉じられた時にシーンを移動したい!等の
機種固有の処理があれば、クラス内の
「interstitial.OnAdClosed += (handler, EventArgs) =>」
の中身に記入したりと拡張も分かりやすくできるかなと思います。

一行分のコードが長いと勝手に改行されるのはどうにかできるのでしょうか?
はてな記法 勝手に改行」等で調べても分からないので困ってます・・・

Yoぶ~ん作成アプリ:プライバシーポリシー

情報収集モジュール

当社で配信するアプリでは、広告配信を目的として以下の広告配信事業者がご利用者の情報を自動取得する場合がございます。この情報から個人が特定されることはありません。取得する情報、利用目的、第三者への提供等につきましては、以下の広告配信事業者のアプリケーション・プライバシーポリシーのリンクよりご確認ください。

AdMob(Google Inc.)
https://policies.google.com/technologies/ads


Information gathering module

For the application to be delivered by our company, the following advertisement distribution companies may automatically acquire information of users for the purpose of advertisement distribution. There is NO personal identification from this information. Regarding information to be acquired, purposes of use, provision to third parties, etc., please confirm from the application · privacy policy link of the following advertisement distribution company.

AdMob (Google Inc.)
https://policies.google.com/technologies/ads

GoogleMobileAds.unitypackageインポートでアプリが起動しない時

※追記 2019/06/05
ver3.17.以降は必要な処理が増えていたのでまとめたリンクを貼っておきます
この対応で不具合がなおるかも・・・?
GoogleAdMobインポート後に必要な作業 ※ver.17以降 - のにっき

現象

現在最新【Version 3.16 】の「GoogleMobileAds.unitypackage」を
インポートしたらアプリが起動しなくなったお話です。

今回の記事は僕の環境だけ?
かつ、一時的なものだと思いますが、対処法は覚えておきたいのでメモしときます。

現象

|環境
・Unity ※. ver = 2017.4.24f1
・プラットフォーム:Android
・下記の作業を行う前に、実機デバッグで動作確認済み

|作業工程
1.新しく作成したアプリに「GoogleMobileAds.unitypackage」をインポートする
2.Unityエディター上のデバッグでは正常に動作した
3.実機に落として実機デバッグを行う
→アプリアイコンタップ後にアプリが起動せず
「アプリが停止しました」のエラーメッセージが表示された。
アプリが起動できなくなった・・・

|対応

  • 「GoogleMobileAds.unitypackage」でインポートしたファイルを削除して再ビルド

→正常に起動した=やっぱりこのパッケージに問題あるのか?

→やっぱり起動しない

  • 「GoogleMobileAds.unitypackage」のバージョンを1つ前の物をインポート

→これで見事に解決しました!
https://github.com/googleads/googleads-mobile-unity/releases

f:id:apuridasuo:20190404150326p:plain
ダウンロードした場所

根本的に・・・

原因はよく分からなかったのですが、
アプリが起動しなかったのは初めてでアタフタしてしまいました。

今後の対策としては、

  • 外からの物をインポートする時
  • シーンを新規に追加する時

上記のタイミングで必ずプロジェクトのバックアップを取ろうと決意しました。

適当なタイミングでバックアップとってると
今日みたいなときに解決のための行動でソースが崩れて
後々解決後に元に戻す作業が重くのしかかってしまいました。。。

LINQの第一歩

LINQはムズかしい!

C#を勉強していて便利そうだけど難しそうな「LINQ」です。

このLINQは、リストや配列操作に非常に役に立つライブラリなのですが、
調べると必ず出てくる「匿名クラス」や「ラムダ式」など。。。
難しくて断念した方もいるのではないでしょうか?

しかし、サイトで勉強した使い方とは少し違った素人っぽい使い方で
LINQを使ってみたら、分かりやすく考えることができました。

初めてLINQを使う方が、LINQの浅い部分を使って便利だなーと感じる方法
LINQにハマるきっかけを書ければと思います。

リスト操作後は同じ型のリストに代入しよう!

LINQはあるListに対して操作を行うライブラリになります。
【例】
 ListAの中から、”ある文字”が含まれる要素だけ取得したい
 ListAの要素すべての末尾に、”ある文字”を追加したい

なので、基本的には
「ListAにLINQのメソッドを使ってListBにしたい!」と思った時に使います。
例文でよくあるのが

List<string> ListA = new List<string>();

ListA.Add("あ");
ListA.Add("い");

var ListB = ListA.Select( x => x + "ある文字" );

このように、「var」型に代入することが多いので
代入後のListBは何なんだ・・・?と思う方がいると思います。
素人の僕はこういう書き方で書きます

List<string> ListA = new List<string>();
List<string> ListB = new List<string>();

ListA.Add("あ");
ListA.Add("い");

ListB = ListA.Select( x => x + "ある文字" ).ToList();

もしくは

List<string> ListA = new List<string>();

ListA.Add("あ");
ListA.Add("い");

ListA= ListA.Select( x => x + "ある文字" ).ToList();

こうすれば、代入後のListBが分かりやすくなります。
そうです!LINQは代入後の型が不定なではなく
ListAの方に引っ張られるだけなので、ToListやToArrayが使えます。
ListAの内容を保持する必要が無ければ、
下の方のように上書きするとさらに分かりやすいです。

引数は、ラムダ式は最低限利用!基本は関数でどうにかする!

先ほどの例文にもありましたが、
Selectメソッドの引数部分※「Select()の中身」 について説明します。

基本的なことしかしない例文であればギリギリ意味が分かるのですが、
いざ自分のやりたいことを書こうと思ったらシドロモドロになっちゃいます。。。
そんな時は、()内に処理を書くのではなく、関数を呼びましょう。

【例】ListAの中から、”ある文字”が含まれる要素だけ取得する

    //========================================
    // LINQ処理で呼び出す関数
    //========================================
    public static bool IsMojiSonzai(string str_Surch, string str_Word)
    {
        bool bl_Ret = false;
        bl_Ret = str_Surch.Contains(str_Word);
        return bl_Ret;
    }
    //========================================
    // 要素を取得する関数
    //========================================
    public void Main()
    {
        List<string> ListA = new List<string>();
        List<string> ListB = new List<string>();

        ListA.Add("あ_ある文字");
        ListA.Add("い");

        ListB = ListA.Where(x => IsMojiSonzai( x, "ある文字" ) ).ToList();
    }

外部関数を使うことで、Whereメソッドの引数はすっきりできたと思います。
それでもラムダ式の記法が入ってしまうので最低限の説明を行います。

【例】ListA.Where(x => IsMojiSonzai( x, "ある文字" ))の説明
・x  ListA[ n番目 ]の要素
・=> この矢印以降に記述した関数がWhereメソッドの引数となる
IsMojiSonzai( x, "ある文字" ) この部分にやりたいことを別の関数で作成して呼ぶ!
・Where(x => IsMojiSonzai( x, "ある文字" )) 
 →「IsMojiSonzai」が「true」となる要素のみListB に格納するという意味になる
 
今回はWhereメソッドを使っていますが、どのメソッドでも同じ記法が使えます。
ラムダ式を最小限にして、外部関数を使用すれば
相当分かりやすくLINQを使用することができます

メソッドは「Select、Where」だけ覚えて使ってみる!

LINQを使ってList操作を行う際に、
この2つのメソッドは即戦力になること間違いなしです!
他のメソッドも便利なのは当たり前ですが、とりあえずこの2つのメソッドで
LINQというものが凄いものだと実感し、慣れて欲しいです。

  • Select

リストのすべての要素に処理を行うメソッドです。
【例】ListAの要素に"まんがな"が含まれていたら要素先頭に"関西人"
   含まれていなければ"東京人"を追加する

        //========================================
        // LINQ処理で呼び出す関数
        //========================================
        public static string SetCategory(string str_Serif)
        {
            string str_Ret = "";
            // 標準語判定
            if(str_Serif.Contains("まんがな"))
            {
                str_Ret = "関西人:"+ str_Serif;
            }
            else
            {
                str_Ret = "東京人:"+ str_Serif;
            }

            return str_Ret;
        }
        //========================================
        // セリフ分け関数
        //========================================
        private void Main()
        {

            List<string> ListA = new List<string>();
            List<string> ListB = new List<string>();

            ListA.Add("こんにちは");
            ListA.Add("こんにちまんがなでっせ");
            ListA.Add("わてでばんがな");
            ListA.Add("なんですかそれは?");

            ListB = ListA.Select(x => SetCategory(x)).ToList();
        }

【例】ListA.Select(x => SetCategory(x))の説明
ListBに、「 SetCategory( ListA[ n ] ) ※ n = ListAの全要素 」の戻り値を格納する
リストのすべての要素を引数として外部関数の処理を行い、
戻り値をListBに格納するイメージです。

  • Where

リストの要素に判定を行い、"true"となる要素を取得する
※"false"となる要素を排除するイメージです
使い方は
上記『【例】ListAの中から、”ある文字”が含まれる要素だけ取得する 』参照

LINQメソッドは併せて使用できる!

SelectとWhereを同時に使用してList操作を行うことも可能です
【例】ListAの要素に"まんがな"が含まれていたら要素先頭に"関西人"追加
   含まれていなければ要素から排除する

        //========================================
        // LINQ処理で呼び出す関数
        //========================================
        public static bool IsKansai(string str_Serif)
        {
            bool bl_Ret = false;
            // 標準語判定
            if (str_Serif.Contains("まんがな"))
            {
                bl_Ret = true;
            }
            else
            {
                bl_Ret = false;
            }

            return bl_Ret;
        }
        public static string SetCategory(string str_Serif)
        {
            string str_Ret = "";
            str_Ret = "関西人:"+ str_Serif;
            return str_Ret;
        }
        //========================================
        // セリフ分け関数
        //========================================
        private void Main()
        {

            List<string> ListA = new List<string>();
            List<string> ListB = new List<string>();

            ListA.Add("こんにちは");
            ListA.Add("こんにちまんがなでっせ");
            ListA.Add("わてでばんがな");
            ListA.Add("なんですかそれは?");

            ListB = ListA.Where(x => IsKansai(x)).Select(x => SetCategory(x)).ToList();
        }

「Where(x => IsKansai(x))」が「"まんがな"が含まれていなければ要素から排除する」
「Select(x => SetCategory(x))」が「含まれていたら要素先頭に"関西人"」の役割です
外部関数を呼ぶ形式なので、リストの選別・置換を1行で記入できます。
実処理部分がとてもすっきりするので見やすく修正しやすいと思います。

LINQはムズかしい!!!

以上が、僕が行ったLINQに慣れるための第一歩です。
上記の組み込み方を知るだけでもLINQが便利で使いやすいものであることが体感できます
しかし、上記の方法は
LINQメソッドの便利さをかなり制限しています!
ある程度LINQに慣れたら他のサイトを見ても
それなりに書いてる意味がわかる様になってます。
ラムダ式、匿名クラスの考え方」など本当に使えるようになった方がいい
便利要素はたくさんありますので
ぜひ、皆さんLINQについて勉強してみてください。

スピーカ管理クラス作ってみた

こんにちは。
初めての記事なので拙いですが大目に見てください。

今回は、音の出力を管理するクラスを作成しました。
どのゲームを作っていても必ず必要になるのが音です。

音の出力・停止・上書き・音量調整など考えることが多くてめんどくさいので、
クラスで管理するとそれなりに簡単にできるようになりました。

クラス内容【C#

    /********************************************************************
        クラス名    : SoundIf
        概要        : サウンド管理
    ********************************************************************/
    public class SoundIf
    {
        //=======================================
        // 変数定義
        //=======================================
        int i_Ch = 0;
        // サウンド格納
        public AudioClip[] Sd_Se;
        public AudioClip[] Sd_Bgm;
        public AudioClip[] Sd_Voice;
        // スピーカー管理
        public AudioSource Audio_Voise;
        public AudioSource Audio_Bgm;
        public AudioSource[] Audio_Se;

        /********************************************************************
           コントラクタ   : SoundIf
        ********************************************************************/
        public SoundIf(AudioClip[] Snd_Se, AudioClip[] Snd_Bgm, AudioClip[] Snd_Voice)
        {
            //=======================================
            // 変数初期化
            //=======================================
            i_Ch = 0;
            Sd_Se = Snd_Se;
            Sd_Bgm = Snd_Bgm;
            Sd_Voice = Snd_Voice;
        }

        /*******************************************************************
           メソッド       : SetSpeaker
           概要           : スピーカー作成処理
        *******************************************************************/
        public void SetSpeaker(GameObject Obj_Canvas)
        {
            //======================================
            // スピーカー作成
            //======================================
            Audio_Voise = new AudioSource();
            Audio_Bgm = new AudioSource();
            Audio_Se = new AudioSource[2];
            Audio_Voise = Obj_Canvas.AddComponent<AudioSource>();
            Audio_Bgm = Obj_Canvas.AddComponent<AudioSource>();
            Audio_Se[0] = Obj_Canvas.AddComponent<AudioSource>();
            Audio_Se[1] = Obj_Canvas.AddComponent<AudioSource>();

            //======================================
            // スピーカー初期設定
            //======================================
            SetVolume(0);
        }

        /******************************************************************
           メソッド       : DestroySpeaker
           概要           : スピーカー削除処理
        ******************************************************************/
        public void DestroySpeaker()
        {
            //======================================
            // スピーカー削除
            //======================================
            Destroy(Audio_Voise);
            Destroy(Audio_Bgm);
            Destroy(Audio_Se[0]);
            Destroy(Audio_Se[1]);
        }

        /******************************************************************
           メソッド       : SetVolume
           概要           : スピーカー音量設定処理
        ******************************************************************/
        public void SetVolume(int i_Mode)
        {
            //======================================
            // 変数定義 ※設定する音量をモードとして管理している
            //======================================
            float[,] f_SetVol = new float[2, 4]
                {//     BGM,    VOICE,  SE1,    SE2
                    {   0.25f,  1f,     0.5f,   0.5f},  // 00:【例】タイトル画面
                    {   0.5f,   1f,     0.2f,   0.2f},  // 01:【例】プレイ画面
                };

            //======================================
            // ボリューム設定
            //======================================
            Audio_Bgm.volume = f_SetVol[i_Mode, 0];
            Audio_Voise.volume = f_SetVol[i_Mode, 1];
            Audio_Se[0].volume = f_SetVol[i_Mode, 2];
            Audio_Se[1].volume = f_SetVol[i_Mode, 3];

        }

        /******************************************************************
           メソッド       : OutSnd系
           概要           : サウンド出力処理
        *******************************************************************/
        /******************************************************************
           : BGM
        ******************************************************************/
        public void OutSnd_Bgm(int i_Param)
        {
            Audio_Bgm.Stop();
            Audio_Bgm.loop = true;
            Audio_Bgm.clip = Sd_Bgm[i_Param];
            Audio_Bgm.Play();
        }
        /*****************************************************************
           : SE ※isCover=前の音を消すかどうか
        ******************************************************************/
        public void OutSnd_Se(int i_Param, bool isCover)
        {
            //----------------------------------------------------------------
            // チャンネル被らせ処理
            //----------------------------------------------------------------
            if (isCover == true)
            {
                Audio_Se[0].Stop();
                Audio_Se[1].Stop();
            }
            //----------------------------------------------------------------
            // 出力チャンネル更新
            //----------------------------------------------------------------
            if (i_Ch == 0)
            {
                i_Ch = 1;
            }
            else
            {
                i_Ch = 0;
            }
            //----------------------------------------------------------------
            // 出力処理
            //----------------------------------------------------------------
            Audio_Se[i_Ch].PlayOneShot(Sd_Se[i_Param]);
        }
        /*****************************************************************
           : Voice
        ******************************************************************/
        public void OutSnd_Voice(int i_Param)
        {
            Audio_Voise.Stop();
            Audio_Voise.PlayOneShot(Sd_Voice[i_Param]);
        }
    }

使い方【初期設定編】

①.適当なオブジェクト(今回は「ScriptMng」)に、
 使用する音データを配列化するためのスクリプト( Hige_MainCntrl )を設定する

Hige_MainCntrl の内容
    public AudioClip[] Snd_Se;            // Seで使用する音データを格納
    public AudioClip[] Snd_Bgm;        // Bgmで使用する音データを格納
    public AudioClip[] Snd_Voice;       // Voiceで使用する音データを格納

②.Inspector画面で、音データ配列にデータを設定する

f:id:apuridasuo:20190401111913p:plain
図:SoundIf仕様解説

③.シーン起動時にサウンド管理クラスを初期化し、
 音データの配列、スピーカーオブジェクトを設定する 

Hige_MainCntrl の内容
    void Start()
    {
        //==========================================
        // サウンド管理クラス初期化
        //==========================================
        // 音配列格納 ※今回は「Cmn」クラスにSoundIfクラスを定義している
        Cmn.cls_Sound = new Cmn.SoundIf(Snd_Se, Snd_Bgm, Snd_Voice);
        // サウンド管理スピーカー作成 
        // ※今回は「Canvas_Main」だが、シーン内のGameObjectなら何でもOK!
        Cmn.cls_Sound.SetSpeaker(Canvas_Main);
    }

↓このコードによって・・・

f:id:apuridasuo:20190401120330p:plain
図:Canvas_Main内のコンポーネント比較

使い方【メソッド解説】

  • SetSpeaker(GameObject Obj_Canvas)

上記③の説明の通り、指定したGameObject(Obj_Canvas)に
AudioSourceコンポーネントを作成する

  • DestroySpeaker()

作成したAudioSourceコンポーネントを削除する
シーン移動時等で使用できる

  • SetVolime(int i_Mode)

AudioSourceコンポーネントの音量を
「f_SetVol」の配列の指定番地(i_Mode)の音量に変更する

  • OutSnd_Bgm(int i_Param)

【初期設定編】②で作成した「Snd_Bgm」配列の
指定番地(i_Param)の音データを出力

  • OutSnd_Voice(int i_Param)

【初期設定編】②で作成した「Snd_Voice」配列の
指定番地(i_Param)の音データを出力

  • OutSnd_Se(int i_Param, bool isCover)

【初期設定編】②で作成した「Snd_Se」配列の
指定番地(i_Param)の音データを出力
「isCover=true」以前に出力した音を消す
「isCover=false」以前に出力した音を消さない


以上になります。
現状、Seを3つ以上鳴らすと前の音が消えてしまうので
「Audio_Se」配列を2つより多く持てば、
その分重ねて鳴らすことができるようになっています。

それなりに汎用性ができたかなと思いますが、
記事にしてみると修正点が見えてきました。。。

よろしければ使ってみたり、
ダメ出しをいただけると嬉しいです!

独学だと100%偏った考えになるので、
このブログでどんどんコードを載せて
どんどんダメ出しいただけるようになるのが今の目標です

はじめまして

 

こんにちは。

Unityでゲームを作り始めて1年ほどたった素人です。。。

※仕事ではなく独学ですので本当に素人です!

 

昔と今で作業のやり方にコツみたいなものが出来てきたので、

覚え書きとしてブログに残せたらいいなと思います。

 

典型的な三日坊主なのでいなくなっても気にせず

よろしくお願いいたします。