個人開発ブログ
いざ「収益化しよう!」と思った時、避けて通れないのが広告の実装ですよね。
ただし、本記事はUnity Services LevelPlayのセットアップや、ironSourceダッシュボードでの広告ユニット設定などは既に終わっている前提で進めるので、まだの方は、ironSource公式ドキュメントなどを参考に準備を済ませておいてください。
目次
-
メインコード
-
使い方と解説
-
まとめ
メインコード
以下のコードを、新しく作成した AdsManager.cs にコピー&ペーストして使ってください。
using System; using System.Collections; using UnityEngine; using Unity.Services.Core; using Unity.Services.LevelPlay; public class AdsManager : MonoBehaviour { public static AdsManager Instance = null; [SerializeField] private string gameId = "YOUR_GAME_ID"; [SerializeField] private string rewardedAdUnitId = "YOUR_REWARDED_AD_UNIT_ID"; [SerializeField] private string interstitialAdUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID"; [SerializeField] private string bannerAdUnitId = "YOUR_BANNER_AD_UNIT_ID"; [SerializeField] private bool enableDebugLogs = true; private Action<bool> onRewardedAdCompleted; private Action<bool> onInterstitialAdCompleted; private Action<bool> onBannerAdCompleted; private LevelPlayRewardedAd rewardedAd; private LevelPlayInterstitialAd interstitialAd; public LevelPlayBannerAd bannerAd; private bool isInitialized = false; public bool isStart = false; // 広告の読み込み状態を追跡 private bool isRewardedAdLoading = false; private bool isInterstitialAdLoading = false; private bool isShowingRewardedAd = false; private bool isShowingInterstitialAd = false; private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(this.gameObject); } else { Destroy(this.gameObject); } } IEnumerator Start() { yield return StartCoroutine(InitializeAds()); if (isInitialized && Application.internetReachability != NetworkReachability.NotReachable) { ShowBannerAd((completed) => { LogMessage($"Banner ad initialization: {completed}"); }); } isStart = true; } private IEnumerator InitializeAds() { LogMessage("Starting ads initialization..."); var initTask = UnityServices.InitializeAsync(); yield return new WaitUntil(() => initTask.IsCompleted); if (initTask.IsFaulted) { LogMessage($"Unity Services initialization failed: {initTask.Exception}"); yield break; } LogMessage("Unity Services initialized successfully"); bool initSuccess = false; bool initFailed = false; LevelPlay.OnInitSuccess += (info) => { LogMessage($"LevelPlay initialized successfully: {info}"); initSuccess = true; isInitialized = true; }; LevelPlay.OnInitFailed += (error) => { LogMessage($"LevelPlay initialization failed: {error}"); initFailed = true; }; LevelPlay.Init(gameId); float timeout = 10f; float elapsed = 0f; while (!initSuccess && !initFailed && elapsed < timeout) { elapsed += Time.deltaTime; yield return null; } if (!initSuccess) { LogMessage("LevelPlay initialization timeout or failed"); yield break; } LogMessage("Ads initialization completed successfully"); // 初期化後に広告インスタンスを作成 InitializeAdInstances(); } // 広告インスタンスを一度だけ作成 private void InitializeAdInstances() { // リワード広告の初期化 var rewardConfig = new LevelPlayRewardedAd.Config.Builder() .SetBidFloor(15) .Build(); rewardedAd = new LevelPlayRewardedAd(rewardedAdUnitId, rewardConfig); RegisterRewardedAdEvents(); // インタースティシャル広告の初期化 var interstitialConfig = new LevelPlayInterstitialAd.Config.Builder() .SetBidFloor(9) .Build(); interstitialAd = new LevelPlayInterstitialAd(interstitialAdUnitId, interstitialConfig); RegisterInterstitialAdEvents(); LogMessage("Ad instances initialized"); } private void RegisterRewardedAdEvents() { if (rewardedAd == null) return; rewardedAd.OnAdLoaded += OnRewardedAdLoaded; rewardedAd.OnAdLoadFailed += OnRewardedAdLoadFailed; rewardedAd.OnAdDisplayed += OnRewardedAdDisplayed; rewardedAd.OnAdDisplayFailed += OnRewardedAdDisplayFailed; rewardedAd.OnAdRewarded += OnAdRewarded; rewardedAd.OnAdClosed += OnRewardedAdClosed; rewardedAd.OnAdClicked += OnRewardedAdClicked; StartCoroutine(PreloadRewardedAdDelayed()); } private void RegisterInterstitialAdEvents() { if (interstitialAd == null) return; interstitialAd.OnAdLoaded += OnInterstitialAdLoaded; interstitialAd.OnAdLoadFailed += OnInterstitialAdLoadFailed; interstitialAd.OnAdDisplayed += OnInterstitialAdDisplayed; interstitialAd.OnAdDisplayFailed += OnInterstitialAdDisplayFailed; interstitialAd.OnAdClosed += OnInterstitialAdClosed; interstitialAd.OnAdClicked += OnInterstitialAdClicked; StartCoroutine(PreloadInterstitialAdDelayed()); } // ========== リワード広告 ========== public void ShowRewardedAd(Action<bool> onCompleted) { LogMessage("ShowRewardedAd called"); if (!isInitialized) { LogMessage("Ads not initialized yet"); onCompleted?.Invoke(false); return; } if (isRewardedAdLoading || isShowingRewardedAd) { LogMessage("Rewarded ad already loading or showing"); onCompleted?.Invoke(false); return; } if (bannerAd != null) CloseBannerAd(); onRewardedAdCompleted = onCompleted; isRewardedAdLoading = true; LogMessage($"Loading rewarded ad... IsAdReady: {rewardedAd?.IsAdReady()}"); if (rewardedAd != null && rewardedAd.IsAdReady()) { LogMessage("Rewarded ad already loaded, showing immediately"); isRewardedAdLoading = false; ShowRewardedAdInternal(); } else { LogMessage("Loading new rewarded ad"); rewardedAd?.LoadAd(); } } private void ShowRewardedAdInternal() { if (rewardedAd != null && rewardedAd.IsAdReady() && !LevelPlayRewardedAd.IsPlacementCapped(rewardedAdUnitId)) { LogMessage("Showing rewarded ad..."); isShowingRewardedAd = true; rewardedAd.ShowAd(rewardedAdUnitId); } else { LogMessage($"Rewarded ad not ready. IsAdReady: {rewardedAd?.IsAdReady()}, IsCapped: {LevelPlayRewardedAd.IsPlacementCapped(rewardedAdUnitId)}"); if (bannerAd != null) ViewBannerAd(); onRewardedAdCompleted?.Invoke(false); } } private void OnRewardedAdLoaded(LevelPlayAdInfo info) { LogMessage($"Rewarded ad loaded: {info}"); // ユーザーが広告を要求していた場合のみ表示 if (isRewardedAdLoading) { isRewardedAdLoading = false; ShowRewardedAdInternal(); } else { LogMessage("Rewarded ad loaded but not requested by user - keeping it ready"); } } private void OnRewardedAdLoadFailed(LevelPlayAdError error) { LogMessage($"Rewarded ad load failed: ErrorCode={error.ErrorCode}, ErrorMessage={error.ErrorMessage}"); isRewardedAdLoading = false; if (bannerAd != null) ViewBannerAd(); onRewardedAdCompleted?.Invoke(false); } private void OnRewardedAdDisplayed(LevelPlayAdInfo info) { LogMessage($"Rewarded ad displayed: {info}"); } private void OnRewardedAdDisplayFailed(LevelPlayAdInfo info, LevelPlayAdError error) { LogMessage($"Rewarded ad display failed: ErrorCode={error.ErrorCode}, ErrorMessage={error.ErrorMessage}"); isShowingRewardedAd = false; if (bannerAd != null) ViewBannerAd(); onRewardedAdCompleted?.Invoke(false); } private void OnAdRewarded(LevelPlayAdInfo info, LevelPlayReward reward) { LogMessage($"User rewarded: {reward.Name} x {reward.Amount}"); } private void OnRewardedAdClosed(LevelPlayAdInfo info) { LogMessage($"Rewarded ad closed: {info}"); isShowingRewardedAd = false; if (bannerAd != null) ViewBannerAd(); onRewardedAdCompleted?.Invoke(true); // 次回のために事前読み込み(表示はしない) StartCoroutine(PreloadRewardedAdDelayed()); } private void OnRewardedAdClicked(LevelPlayAdInfo info) { LogMessage($"Rewarded ad clicked: {info}"); } private IEnumerator PreloadRewardedAdDelayed() { yield return new WaitForSeconds(1f); LogMessage("Preloading next rewarded ad"); rewardedAd?.LoadAd(); } // ========== インタースティシャル広告 ========== public void ShowInterstitialAd(Action<bool> onCompleted) { LogMessage("ShowInterstitialAd called"); if (!isInitialized) { LogMessage("Ads not initialized yet"); onCompleted?.Invoke(false); return; } if (isInterstitialAdLoading || isShowingInterstitialAd) { LogMessage("Interstitial ad already loading or showing"); onCompleted?.Invoke(続ける11:24false); return; } if (bannerAd != null) CloseBannerAd(); onInterstitialAdCompleted = onCompleted; isInterstitialAdLoading = true; LogMessage($"Loading interstitial ad... IsAdReady: {interstitialAd?.IsAdReady()}"); if (interstitialAd != null && interstitialAd.IsAdReady()) { LogMessage("Interstitial ad already loaded, showing immediately"); isInterstitialAdLoading = false; ShowInterstitialAdInternal(); } else { LogMessage("Loading new interstitial ad"); interstitialAd?.LoadAd(); } } private void ShowInterstitialAdInternal() { if (interstitialAd != null && interstitialAd.IsAdReady() && !LevelPlayInterstitialAd.IsPlacementCapped(interstitialAdUnitId)) { LogMessage("Showing interstitial ad..."); isShowingInterstitialAd = true; interstitialAd.ShowAd(interstitialAdUnitId); } else { LogMessage($"Interstitial ad not ready. IsAdReady: {interstitialAd?.IsAdReady()}, IsCapped: {LevelPlayInterstitialAd.IsPlacementCapped(interstitialAdUnitId)}"); if (bannerAd != null) ViewBannerAd(); onInterstitialAdCompleted?.Invoke(false); } } private void OnInterstitialAdLoaded(LevelPlayAdInfo info) { LogMessage($"Interstitial ad loaded: {info}"); // ユーザーが広告を要求していた場合のみ表示 if (isInterstitialAdLoading) { isInterstitialAdLoading = false; ShowInterstitialAdInternal(); } else { LogMessage("Interstitial ad loaded but not requested by user - keeping it ready"); } } private void OnInterstitialAdLoadFailed(LevelPlayAdError error) { LogMessage($"Interstitial ad load failed: ErrorCode={error.ErrorCode}, ErrorMessage={error.ErrorMessage}"); isInterstitialAdLoading = false; if (bannerAd != null) ViewBannerAd(); onInterstitialAdCompleted?.Invoke(false); } private void OnInterstitialAdDisplayed(LevelPlayAdInfo info) { LogMessage($"Interstitial ad displayed: {info}"); } private void OnInterstitialAdDisplayFailed(LevelPlayAdInfo info, LevelPlayAdError error) { LogMessage($"Interstitial ad display failed: ErrorCode={error.ErrorCode}, ErrorMessage={error.ErrorMessage}"); isShowingInterstitialAd = false; if (bannerAd != null) ViewBannerAd(); onInterstitialAdCompleted?.Invoke(false); } private void OnInterstitialAdClosed(LevelPlayAdInfo info) { LogMessage($"Interstitial ad closed: {info}"); isShowingInterstitialAd = false; if (bannerAd != null) ViewBannerAd(); onInterstitialAdCompleted?.Invoke(true); StartCoroutine(PreloadInterstitialAdDelayed()); } private void OnInterstitialAdClicked(LevelPlayAdInfo info) { LogMessage($"Interstitial ad clicked: {info}"); } private IEnumerator PreloadInterstitialAdDelayed() { yield return new WaitForSeconds(1f); LogMessage("Preloading next interstitial ad"); interstitialAd?.LoadAd(); } // ========== バナー広告 ========== public void ShowBannerAd(Action<bool> onCompleted) { if (!isInitialized) { LogMessage("Ads not initialized yet"); onCompleted?.Invoke(false); return; } onBannerAdCompleted = onCompleted; // バナー広告の設定 var configBuilder = new LevelPlayBannerAd.Config.Builder(); configBuilder.SetSize(LevelPlayAdSize.BANNER); configBuilder.SetPosition(LevelPlayBannerPosition.BottomCenter); configBuilder.SetDisplayOnLoad(true); configBuilder.SetRespectSafeArea(true); configBuilder.SetPlacementName("DefaultBanner"); configBuilder.SetBidFloor(0.3); var bannerConfig = configBuilder.Build(); bannerAd = new LevelPlayBannerAd(bannerAdUnitId, bannerConfig); // イベント登録 bannerAd.OnAdLoaded += OnBannerAdLoaded; bannerAd.OnAdLoadFailed += OnBannerAdLoadFailed; bannerAd.OnAdDisplayed += OnBannerAdDisplayed; bannerAd.OnAdDisplayFailed += OnBannerAdDisplayFailed; bannerAd.OnAdClicked += OnBannerAdClicked; LogMessage("Loading banner ad..."); bannerAd.LoadAd(); } private void OnBannerAdLoaded(LevelPlayAdInfo info) { LogMessage($"Banner ad loaded: {info}"); if (bannerAd != null) { bannerAd.ShowAd(); onBannerAdCompleted?.Invoke(true); } else { onBannerAdCompleted?.Invoke(false); } } private void OnBannerAdLoadFailed(LevelPlayAdError error) { LogMessage($"Banner ad load failed: {error}"); onBannerAdCompleted?.Invoke(false); } private void OnBannerAdDisplayed(LevelPlayAdInfo info) { LogMessage($"Banner ad displayed: {info}"); } private void OnBannerAdDisplayFailed(LevelPlayAdInfo info, LevelPlayAdError error) { LogMessage($"Banner ad display failed: {error}"); } private void OnBannerAdClicked(LevelPlayAdInfo info) { LogMessage($"Banner ad clicked: {info}"); } public void LoadBannerAd() { if (bannerAd != null) { LogMessage("Reloading banner ad..."); bannerAd.LoadAd(); } } public void CloseBannerAd() { if (bannerAd != null) { LogMessage("Hiding banner ad"); bannerAd.HideAd(); } } public void DestroyBannerAd() { if (bannerAd != null) { LogMessage("Destroying banner ad"); bannerAd.DestroyAd(); bannerAd.Dispose(); bannerAd = null; Resources.UnloadUnusedAssets(); } } public void ViewBannerAd() { if (bannerAd != null) { LogMessage("Showing banner ad"); bannerAd.ShowAd(); } } // ========== ユーティリティ ========== private void LogMessage(string message) { if (enableDebugLogs) { Debug.Log($"[AdsManager] {message}"); } } private void OnDestroy() { // イベント登録解除 if (rewardedAd != null) { rewardedAd.OnAdLoaded -= OnRewardedAdLoaded; rewardedAd.OnAdLoadFailed -= OnRewardedAdLoadFailed; rewardedAd.OnAdDisplayed -= OnRewardedAdDisplayed; rewardedAd.OnAdDisplayFailed -= OnRewardedAdDisplayFailed; rewardedAd.OnAdRewarded -= OnAdRewarded; rewardedAd.OnAdClosed -= OnRewardedAdClosed; rewardedAd.OnAdClicked -= OnRewardedAdClicked; rewardedAd.Dispose(); } if (interstitialAd != null) { interstitialAd.OnAdLoaded -= OnInterstitialAdLoaded; interstitialAd.OnAdLoadFailed -= OnInterstitialAdLoadFailed; interstitialAd.OnAdDisplayed -= OnInterstitialAdDisplayed; interstitialAd.OnAdDisplayFailed -= OnInterstitialAdDisplayFailed; interstitialAd.OnAdClosed -= OnInterstitialAdClosed; interstitialAd.OnAdClicked -= OnInterstitialAdClicked; interstitialAd.Dispose(); } if (bannerAd != null) { bannerAd.OnAdLoaded -= OnBannerAdLoaded; bannerAd.OnAdLoadFailed -= OnBannerAdLoadFailed; bannerAd.OnAdDisplayed -= OnBannerAdDisplayed; bannerAd.OnAdDisplayFailed -= OnBannerAdDisplayFailed; bannerAd.OnAdClicked -= OnBannerAdClicked; bannerAd.Dispose(); } } }
使い方と解説
さて、コードをコピペした後の具体的な使い方についてお話ししますね。
このマネージャーは「シングルトン」という仕組みを使っているので、一度シーンに置いてしまえば、どこからでも簡単に呼び出せます。
セットアップの手順
まずは、Hierarchyに空のGameObjectを作成し、名前を「AdsManager」にでもします。
そこに先ほどのスクリプトをアタッチしてください。
Inspectorに以下項目が表示されるので、
ironSourceのダッシュボードから取得したIDを入力します。
・Game Id: アプリのゲームID
・Rewarded Ad Unit Id: リワード広告のID
・Interstitial Ad Unit Id: インタースティシャル広告のID
・Banner Ad Unit Id: バナー広告のID
これだけで準備は完了です。
Awakeメソッド内で DontDestroyOnLoad を呼んでいるので、シーンを切り替えてもこのマネージャーは消えずに残り続けてくれます。
広告を表示
リワード広告を表示:
ユーザーが動画を最後まで見たら報酬をあげたい時、こんな風に書けます。
AdsManager.Instance.ShowRewardedAd((completed) => {
if (completed) {
// ここに報酬を付与する処理を書く
Debug.Log("報酬をゲット!");
} else {
// 広告が読み込めなかった、または途中で閉じられた場合
Debug.Log("報酬はなし...");
}
});
インタースティシャル広告を表示:
ステージクリア時などに全画面広告を出したい時はこちら。
AdsManager.Instance.ShowInterstitialAd((completed) => {
// 広告が終わった後の処理(次のステージへ進むなど)
});
バナー広告を表示:
別途バナー広告を出したい時はこちら。(デフォルトでは基本常時表示)
AdsManager.Instance.ShowBannerAd((completed) => {
// 広告が終わった後の処理(切り替えなど)
});
広告の事前読み込み
広告って、いざ表示しようとした時に読み込み始めると、数秒の待ち時間が発生してユーザーの体験を損ねてしまいますよね。
このマネージャーは、初期化時や広告を閉じた直後に、次の広告を自動でバックグラウンドで読み込んでおきます。
ユーザーがボタン押した時には、既に準備ができている状態(IsAdReady)にしているので、ストレスなく広告を表示できるんです。
バナー広告の制御
全画面広告(リワードやインタースティシャル)が出ている時に、バナー広告が重なって表示されると、見た目も悪いしポリシー違反になる可能性もあります。
このコードでは、全画面広告を表示する瞬間にバナーを非表示にし、広告が閉じられたら自動で再表示するようにしています。
CloseBannerAd() と ViewBannerAd() が裏で制御されてるので、何も気にしなくて大丈夫です。
状態管理の徹底
「広告ボタンを連打されたらどうしよう?」という心配も無用です。
isRewardedAdLoading や isShowingRewardedAd といったフラグを使って、「今読み込み中か?」「今表示中か?」を厳密に管理しています。
既に処理が走っている場合は新しいリクエストを弾くようになっているので、予期せぬエラーを防ぐことができます。
まとめ
いかがでしたか?
今回は、LevelPlay(ironSource)の実装を楽にするマネージャースクリプトをご紹介しました。
広告実装って、最初は「面倒だな……」と感じるかもしれませんが、こうして1つのマネージャーにまとめてしまえば、次からのプロジェクトでも使い回せる最強の武器になります。
皆さんのゲーム開発が、少しでも快適になれば嬉しいです。
ぜひ、自分のプロジェクトに合わせてカスタマイズして使ってみてくださいね。
それでは、また別の記事でお会いましょう。。_(:3 」∠)_
☝Unity開発に関する最新情報をチェックしよう!
☝絵師必見!AI無断学習対策アプリ