using UnityEngine; using System.Runtime.InteropServices; /// /// Singleton that handles interstitial (non-rewarded) ads for WebGL games. /// /// SETUP: Add AutoCreateAdManagers to any GameObject in your first scene — /// it will create this manager automatically at runtime. /// /// USAGE: Call one of the public Show methods at the right moment in your game: /// InterstitialAdsManager.Instance.ShowInterstitialAdAfterLevelComplete(); /// InterstitialAdsManager.Instance.ShowInterstitialAdOnPause(); /// InterstitialAdsManager.Instance.ShowInterstitialAdOnBrowse(); /// InterstitialAdsManager.Instance.ShowInterstitialAdOnStart(); /// /// The manager pauses time and mutes audio automatically before the ad, /// then restores both when the ad closes. You do not need to pause/resume manually. /// public class InterstitialAdsManager : MonoBehaviour { [DllImport("__Internal")] private static extern void ShowInterstitialAd(string adType, string callbackName); [DllImport("__Internal")] private static extern void FocusUnityCanvas(); private static InterstitialAdsManager _instance; public static InterstitialAdsManager Instance => _instance; private float _prevTimeScale = 1f; private bool _prevAudioPause = false; private void Awake() { if (_instance == null) { _instance = this; DontDestroyOnLoad(gameObject); } else if (_instance != this) { Destroy(gameObject); } } // ------------------------------------------------------------------------- // Public API — call these from your game scripts // ------------------------------------------------------------------------- /// Show an interstitial ad after the player completes a level. public void ShowInterstitialAdAfterLevelComplete() => ShowInternal("next", "OnLevelCompleteAdClosed"); /// Show an interstitial ad when the player opens the pause menu. public void ShowInterstitialAdOnPause() => ShowInternal("pause", "OnPauseAdClosed"); /// Show an interstitial ad when the player returns to the main menu. public void ShowInterstitialAdOnBrowse() => ShowInternal("browse", "OnBrowseAdClosed"); /// Show an interstitial ad at the start of a round or session. public void ShowInterstitialAdOnStart() => ShowInternal("start", "OnStartAdClosed"); /// /// Show an interstitial ad with a custom ad type and callback name. /// /// H5 Games Ads type: "next", "pause", "browse", "start", or "preroll". /// Must match the handler name added to OnInterstitialAdClosed's switch. public void ShowInterstitialAdCustom(string adType, string callbackName) => ShowInternal(adType, callbackName); // ------------------------------------------------------------------------- // Internal // ------------------------------------------------------------------------- private void ShowInternal(string adType, string callbackName) { PauseForAd(); #if UNITY_WEBGL && !UNITY_EDITOR try { ShowInterstitialAd(adType, callbackName); } catch (System.Exception e) { Debug.LogError($"[InterstitialAdsManager] .jslib call failed: {e.Message}"); ResumeAfterAd(); OnInterstitialAdClosed($"{callbackName}|closed"); } #else // Editor simulation: ad closes immediately OnInterstitialAdClosed($"{callbackName}|closed"); #endif } // ------------------------------------------------------------------------- // Callback — called by the platform via SendMessage // Payload format: "callbackName|result" (result is always "closed") // ------------------------------------------------------------------------- /// /// Called by the platform via SendMessage after the ad closes. /// Do not rename this method — the platform calls it by name. /// public void OnInterstitialAdClosed(string payload) { if (_instance == null) return; var parts = string.IsNullOrEmpty(payload) ? new[] { "OnInterstitialAdClosed", "closed" } : payload.Split('|'); var callbackName = parts.Length > 0 ? parts[0] : "OnInterstitialAdClosed"; var result = parts.Length > 1 ? parts[1] : "closed"; Debug.Log($"[InterstitialAdsManager] Ad closed — callback: {callbackName}, result: {result}"); switch (callbackName) { case "OnLevelCompleteAdClosed": OnLevelCompleteAdClosed(result); break; case "OnPauseAdClosed": OnPauseAdClosed(result); break; case "OnBrowseAdClosed": OnBrowseAdClosed(result); break; case "OnStartAdClosed": OnStartAdClosed(result); break; default: Debug.LogWarning($"[InterstitialAdsManager] Unknown callback '{callbackName}' — resuming game."); ResumeAfterAd(); break; } } // ------------------------------------------------------------------------- // Ad-closed handlers — add your game logic in each TODO block // ------------------------------------------------------------------------- private void OnLevelCompleteAdClosed(string result) { ResumeAfterAd(); // TODO: Continue to the next level or show the results screen // Example: LevelManager.LoadNextLevel(); } private void OnPauseAdClosed(string result) { ResumeAfterAd(); // TODO: Show your pause menu or resume the game // Example: PauseMenu.Show(); } private void OnBrowseAdClosed(string result) { ResumeAfterAd(); // TODO: Navigate to your main menu or game selection screen // Example: SceneManager.LoadScene("MainMenu"); } private void OnStartAdClosed(string result) { ResumeAfterAd(); // TODO: Begin the game or the next round // Example: GameController.StartRound(); } // ------------------------------------------------------------------------- // Pause / resume helpers (called automatically — no need to call manually) // ------------------------------------------------------------------------- private void PauseForAd() { #if UNITY_WEBGL && !UNITY_EDITOR _prevTimeScale = Time.timeScale; _prevAudioPause = AudioListener.pause; Time.timeScale = 0f; AudioListener.pause = true; TryFocusCanvas(); #endif } private void ResumeAfterAd() { #if UNITY_WEBGL && !UNITY_EDITOR Time.timeScale = _prevTimeScale; AudioListener.pause = _prevAudioPause; TryFocusCanvas(); #endif } private void TryFocusCanvas() { #if UNITY_WEBGL && !UNITY_EDITOR try { FocusUnityCanvas(); } catch { } #endif } }