using UnityEngine; using System.Runtime.InteropServices; /// /// Singleton that handles 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 a Show method when the player opts in to watch a rewarded ad: /// RewardedAdsManager.Instance.ShowRewardedAdForHint(); /// RewardedAdsManager.Instance.ShowRewardedAdForExtraLife(); /// RewardedAdsManager.Instance.ShowRewardedAdForCoins(); /// RewardedAdsManager.Instance.ShowRewardedAdForPowerup(); /// /// Grant the reward only when result == "rewarded" (player watched the full ad). /// result == "closed" means the player skipped — do not grant the reward. /// /// 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 RewardedAdsManager : MonoBehaviour { [DllImport("__Internal")] private static extern void ShowRewardedAd(string rewardType, string callbackName); [DllImport("__Internal")] private static extern void FocusUnityCanvas(); private static RewardedAdsManager _instance; public static RewardedAdsManager 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 a rewarded ad in exchange for a hint. public void ShowRewardedAdForHint() => ShowInternal("hint", "OnHintReward"); /// Show a rewarded ad in exchange for an extra life or continue. public void ShowRewardedAdForExtraLife() => ShowInternal("extraLife", "OnExtraLifeReward"); /// Show a rewarded ad in exchange for in-game currency. public void ShowRewardedAdForCoins() => ShowInternal("coins", "OnCoinsReward"); /// Show a rewarded ad in exchange for a power-up. public void ShowRewardedAdForPowerup() => ShowInternal("powerup", "OnPowerupReward"); /// /// Show a rewarded ad with a custom reward type and callback name. /// Add a matching case to OnRewardedAdResult's switch to handle the result. /// public void ShowRewardedAdForCustom(string rewardType, string callbackName) => ShowInternal(rewardType, callbackName); // ------------------------------------------------------------------------- // Internal // ------------------------------------------------------------------------- private void ShowInternal(string rewardType, string callbackName) { PauseForAd(); #if UNITY_WEBGL && !UNITY_EDITOR try { ShowRewardedAd(rewardType, callbackName); } catch (System.Exception e) { Debug.LogError($"[RewardedAdsManager] .jslib call failed: {e.Message}"); ResumeAfterAd(); OnRewardedAdResult($"{callbackName}|closed"); } #else // Editor simulation: reward is granted immediately so you can test your reward logic OnRewardedAdResult($"{callbackName}|rewarded"); #endif } // ------------------------------------------------------------------------- // Callback — called by the platform via SendMessage // Payload format: "callbackName|result" // result = "rewarded" → player watched the full ad, grant the reward // result = "closed" → player skipped the ad, do not grant the reward // ------------------------------------------------------------------------- /// /// Called by the platform via SendMessage after the ad completes. /// Do not rename this method — the platform calls it by name. /// public void OnRewardedAdResult(string payload) { if (_instance == null) return; var parts = string.IsNullOrEmpty(payload) ? new[] { "OnRewardedAdResult", "closed" } : payload.Split('|'); var callbackName = parts.Length > 0 ? parts[0] : "OnRewardedAdResult"; var result = parts.Length > 1 ? parts[1] : "closed"; Debug.Log($"[RewardedAdsManager] Ad result — callback: {callbackName}, result: {result}"); switch (callbackName) { case "OnHintReward": OnHintReward(result); break; case "OnExtraLifeReward": OnExtraLifeReward(result); break; case "OnCoinsReward": OnCoinsReward(result); break; case "OnPowerupReward": OnPowerupReward(result); break; default: Debug.LogWarning($"[RewardedAdsManager] Unknown callback '{callbackName}' — resuming game."); ResumeAfterAd(); break; } } // ------------------------------------------------------------------------- // Reward handlers — add your grant logic in each "rewarded" block // ------------------------------------------------------------------------- private void OnHintReward(string result) { if (result == "rewarded") { // TODO: Give the player a hint // Example: HintSystem.GiveHint(); } ResumeAfterAd(); } private void OnExtraLifeReward(string result) { if (result == "rewarded") { // TODO: Give the player an extra life or continue // Example: LivesSystem.AddLife(); } ResumeAfterAd(); } private void OnCoinsReward(string result) { if (result == "rewarded") { // TODO: Give the player in-game currency // Example: CurrencySystem.AddCoins(100); } ResumeAfterAd(); } private void OnPowerupReward(string result) { if (result == "rewarded") { // TODO: Give the player a power-up // Example: PowerupSystem.UnlockPowerup(); } ResumeAfterAd(); } // ------------------------------------------------------------------------- // 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 } }