nccgs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/nccgs-accessibility-specialist.md +26 -0
- package/.claude/agents/nccgs-adversarial-reviewer.md +26 -0
- package/.claude/agents/nccgs-ai-programmer.md +26 -0
- package/.claude/agents/nccgs-analytics-engineer.md +26 -0
- package/.claude/agents/nccgs-art-direction-lead.md +26 -0
- package/.claude/agents/nccgs-audio-direction-lead.md +26 -0
- package/.claude/agents/nccgs-creative-director.md +26 -0
- package/.claude/agents/nccgs-documentation-manager.md +26 -0
- package/.claude/agents/nccgs-economy-designer.md +26 -0
- package/.claude/agents/nccgs-engine-programmer.md +26 -0
- package/.claude/agents/nccgs-game-design-lead.md +26 -0
- package/.claude/agents/nccgs-game-designer.md +26 -0
- package/.claude/agents/nccgs-gameplay-programmer.md +26 -0
- package/.claude/agents/nccgs-level-designer.md +26 -0
- package/.claude/agents/nccgs-live-ops-designer.md +26 -0
- package/.claude/agents/nccgs-localization-lead.md +26 -0
- package/.claude/agents/nccgs-narrative-lead.md +26 -0
- package/.claude/agents/nccgs-network-programmer.md +26 -0
- package/.claude/agents/nccgs-performance-analyst.md +26 -0
- package/.claude/agents/nccgs-producer.md +26 -0
- package/.claude/agents/nccgs-production-coordinator.md +23 -0
- package/.claude/agents/nccgs-programming-lead.md +26 -0
- package/.claude/agents/nccgs-prototyper.md +26 -0
- package/.claude/agents/nccgs-qa-engineer.md +26 -0
- package/.claude/agents/nccgs-qa-lead.md +26 -0
- package/.claude/agents/nccgs-release-engineer.md +26 -0
- package/.claude/agents/nccgs-release-lead.md +26 -0
- package/.claude/agents/nccgs-security-engineer.md +26 -0
- package/.claude/agents/nccgs-sound-designer.md +26 -0
- package/.claude/agents/nccgs-systems-designer.md +26 -0
- package/.claude/agents/nccgs-technical-architect.md +26 -0
- package/.claude/agents/nccgs-technical-artist.md +26 -0
- package/.claude/agents/nccgs-technical-director.md +26 -0
- package/.claude/agents/nccgs-tools-programmer.md +26 -0
- package/.claude/agents/nccgs-ui-programmer.md +26 -0
- package/.claude/agents/nccgs-unity-build-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-content-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-implementer.md +26 -0
- package/.claude/agents/nccgs-unity-rendering-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-systems-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-ui-specialist.md +26 -0
- package/.claude/agents/nccgs-ux-designer.md +26 -0
- package/.claude/agents/nccgs-verification-engineer.md +26 -0
- package/.claude/agents/nccgs-world-builder.md +26 -0
- package/.claude/agents/nccgs-writer.md +26 -0
- package/.claude/nccgs/THIRD_PARTY_NOTICES.md +13 -0
- package/.claude/nccgs/VERSION +1 -0
- package/.claude/nccgs/constitution.md +131 -0
- package/.claude/nccgs/hooks/agent-audit.mjs +10 -0
- package/.claude/nccgs/hooks/common.mjs +41 -0
- package/.claude/nccgs/hooks/post-compact.mjs +1 -0
- package/.claude/nccgs/hooks/pre-compact.mjs +8 -0
- package/.claude/nccgs/hooks/protect-git.mjs +22 -0
- package/.claude/nccgs/hooks/protect-write.mjs +17 -0
- package/.claude/nccgs/hooks/session-start.mjs +15 -0
- package/.claude/nccgs/hooks/session-stop.mjs +7 -0
- package/.claude/nccgs/protocols/agent-contract.md +34 -0
- package/.claude/nccgs/protocols/context-packets.md +13 -0
- package/.claude/nccgs/protocols/evidence.md +15 -0
- package/.claude/nccgs/protocols/model-routing.md +22 -0
- package/.claude/nccgs/protocols/orchestration.md +26 -0
- package/.claude/nccgs/protocols/unity-boundary.md +11 -0
- package/.claude/nccgs/settings.fragment.json +77 -0
- package/.claude/nccgs/studio.json +347 -0
- package/.claude/nccgs/tools/configure-models.mjs +39 -0
- package/.claude/nccgs/unity-skills-manifest.json +727 -0
- package/.claude/nccgs/workflow-catalog.json +317 -0
- package/.claude/rules/nccgs-canonical-docs.md +19 -0
- package/.claude/rules/nccgs-editor-tools.md +12 -0
- package/.claude/rules/nccgs-localization.md +12 -0
- package/.claude/rules/nccgs-networking.md +13 -0
- package/.claude/rules/nccgs-performance.md +14 -0
- package/.claude/rules/nccgs-rendering.md +16 -0
- package/.claude/rules/nccgs-security.md +13 -0
- package/.claude/rules/nccgs-tests.md +18 -0
- package/.claude/rules/nccgs-ui.md +14 -0
- package/.claude/rules/nccgs-unity-assets.md +21 -0
- package/.claude/rules/nccgs-unity-code.md +22 -0
- package/.claude/skills/accessibility-review/SKILL.md +14 -0
- package/.claude/skills/architecture-decision/SKILL.md +14 -0
- package/.claude/skills/asset-audit/SKILL.md +14 -0
- package/.claude/skills/audit/SKILL.md +16 -0
- package/.claude/skills/audit/references/dimensions.md +46 -0
- package/.claude/skills/balance-review/SKILL.md +14 -0
- package/.claude/skills/bug-triage/SKILL.md +14 -0
- package/.claude/skills/build-live-game/SKILL.md +317 -0
- package/.claude/skills/build-live-game/references/achievements.md +779 -0
- package/.claude/skills/build-live-game/references/apis.md +280 -0
- package/.claude/skills/build-live-game/references/authentication.md +437 -0
- package/.claude/skills/build-live-game/references/battlepass.md +860 -0
- package/.claude/skills/build-live-game/references/cloud-code.md +563 -0
- package/.claude/skills/build-live-game/references/cloud-save.md +474 -0
- package/.claude/skills/build-live-game/references/deployment.md +216 -0
- package/.claude/skills/build-live-game/references/player-account.md +813 -0
- package/.claude/skills/build-live-game/references/remote-config.md +96 -0
- package/.claude/skills/build-live-game/references/tooling.md +431 -0
- package/.claude/skills/closure/SKILL.md +14 -0
- package/.claude/skills/code-review/SKILL.md +14 -0
- package/.claude/skills/compatibility-review/SKILL.md +14 -0
- package/.claude/skills/context-pack/SKILL.md +14 -0
- package/.claude/skills/dependency-review/SKILL.md +14 -0
- package/.claude/skills/design/SKILL.md +20 -0
- package/.claude/skills/design-review/SKILL.md +14 -0
- package/.claude/skills/evidence-review/SKILL.md +14 -0
- package/.claude/skills/hotfix/SKILL.md +14 -0
- package/.claude/skills/implement-in-app-purchases/README.md +233 -0
- package/.claude/skills/implement-in-app-purchases/SKILL.md +158 -0
- package/.claude/skills/implement-in-app-purchases/references/api-notes.md +562 -0
- package/.claude/skills/implement-in-app-purchases/references/codeless-catalog.md +331 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-adapty.md +268 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-essentialkit.md +239 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-revenuecat.md +275 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-unipay.md +145 -0
- package/.claude/skills/implement-in-app-purchases/references/migration-v4-to-v5.md +204 -0
- package/.claude/skills/implement-in-app-purchases/references/path-add-iap-to-new-project.md +198 -0
- package/.claude/skills/implement-in-app-purchases/references/path-convert-native-google-billing.md +356 -0
- package/.claude/skills/implement-in-app-purchases/references/path-convert-native-storekit.md +446 -0
- package/.claude/skills/implement-in-app-purchases/references/path-implement-iap-d2c.md +680 -0
- package/.claude/skills/implement-in-app-purchases/references/platform-notes.md +204 -0
- package/.claude/skills/implement-in-app-purchases/references/pre-check.md +205 -0
- package/.claude/skills/incident-recovery/SKILL.md +14 -0
- package/.claude/skills/initialize-ai-navigation/SKILL.md +95 -0
- package/.claude/skills/initialize-ai-navigation/references/navigation-system.md +794 -0
- package/.claude/skills/levelplay-unity-integration/CHANGELOG.md +57 -0
- package/.claude/skills/levelplay-unity-integration/README.md +74 -0
- package/.claude/skills/levelplay-unity-integration/SKILL.md +1126 -0
- package/.claude/skills/levelplay-unity-integration/references/banner-api.md +920 -0
- package/.claude/skills/levelplay-unity-integration/references/best-practices.md +536 -0
- package/.claude/skills/levelplay-unity-integration/references/ilrd-api.md +337 -0
- package/.claude/skills/levelplay-unity-integration/references/initialization-api.md +630 -0
- package/.claude/skills/levelplay-unity-integration/references/interstitial-api.md +899 -0
- package/.claude/skills/levelplay-unity-integration/references/ios-setup.md +491 -0
- package/.claude/skills/levelplay-unity-integration/references/migration-sdk-9.md +666 -0
- package/.claude/skills/levelplay-unity-integration/references/privacy-settings.md +608 -0
- package/.claude/skills/levelplay-unity-integration/references/rewarded-api.md +902 -0
- package/.claude/skills/localization/SKILL.md +135 -0
- package/.claude/skills/localization/references/api-notes.md +76 -0
- package/.claude/skills/localization/resources/L10nBatchProcessor.cs +69 -0
- package/.claude/skills/localization/resources/LocalizedFontAsset.cs +18 -0
- package/.claude/skills/localize-game/SKILL.md +14 -0
- package/.claude/skills/migrate-project/SKILL.md +21 -0
- package/.claude/skills/migrate-project/references/procedure.md +63 -0
- package/.claude/skills/milestone-review/SKILL.md +14 -0
- package/.claude/skills/new-unity-project/SKILL.md +179 -0
- package/.claude/skills/optimize-audio/SKILL.md +199 -0
- package/.claude/skills/optimize-audio/resources/audio-import-api.md +146 -0
- package/.claude/skills/optimize-audio/resources/platform-settings.md +48 -0
- package/.claude/skills/optimize-text-mesh-pro/SKILL.md +182 -0
- package/.claude/skills/optimize-web/SKILL.md +393 -0
- package/.claude/skills/optimize-web/resources/WebOptimizer.cs +21 -0
- package/.claude/skills/optimize-web/resources/toktx-examples.sh +11 -0
- package/.claude/skills/performance-audit/SKILL.md +14 -0
- package/.claude/skills/physics-3d-collision/SKILL.md +442 -0
- package/.claude/skills/physics-3d-collision/references/troubleshooting.md +41 -0
- package/.claude/skills/physics-3d-collision/resources/CollisionDebugger.cs +33 -0
- package/.claude/skills/plan-feature/SKILL.md +14 -0
- package/.claude/skills/playtest/SKILL.md +14 -0
- package/.claude/skills/project-stage/SKILL.md +14 -0
- package/.claude/skills/prototype-feature/SKILL.md +14 -0
- package/.claude/skills/qa-plan/SKILL.md +14 -0
- package/.claude/skills/release/SKILL.md +18 -0
- package/.claude/skills/release-readiness/SKILL.md +14 -0
- package/.claude/skills/retrospective/SKILL.md +14 -0
- package/.claude/skills/review/SKILL.md +16 -0
- package/.claude/skills/security-audit/SKILL.md +14 -0
- package/.claude/skills/setup-multiplayer-services/SKILL.md +39 -0
- package/.claude/skills/setup-multiplayer-services/references/dgs-entrypoint.md +79 -0
- package/.claude/skills/setup-multiplayer-services/references/entrypoints.md +213 -0
- package/.claude/skills/setup-multiplayer-services/references/examples.md +33 -0
- package/.claude/skills/setup-multiplayer-services/references/implementation-fit.md +30 -0
- package/.claude/skills/setup-multiplayer-services/references/underlying-services.md +11 -0
- package/.claude/skills/setup-multiplayer-services/references/workflows-prerequisites.md +17 -0
- package/.claude/skills/setup-vivox-voice-chat/SKILL.md +118 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/.env.example +6 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/README.md +101 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/promptfooconfig.yaml +32 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/init-and-login.yaml +76 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/text-chat.yaml +65 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/voice-channels.yaml +74 -0
- package/.claude/skills/setup-vivox-voice-chat/references/events-and-participants.md +79 -0
- package/.claude/skills/setup-vivox-voice-chat/references/init-and-login.md +92 -0
- package/.claude/skills/setup-vivox-voice-chat/references/text-chat.md +93 -0
- package/.claude/skills/setup-vivox-voice-chat/references/troubleshooting.md +47 -0
- package/.claude/skills/setup-vivox-voice-chat/references/voice-channels.md +90 -0
- package/.claude/skills/shader-graph-create-custom-node/SKILL.md +25 -0
- package/.claude/skills/shader-graph-create-custom-node/resources/all_hints.hlsl +182 -0
- package/.claude/skills/sprint-plan/SKILL.md +14 -0
- package/.claude/skills/sprite-editor/SKILL.md +66 -0
- package/.claude/skills/sprite-editor/references/api_reference.md +151 -0
- package/.claude/skills/sprite-editor/references/background.md +112 -0
- package/.claude/skills/sprite-editor/references/templates.md +72 -0
- package/.claude/skills/sprite-editor/scripts/AutomaticSliceTexture.cs +40 -0
- package/.claude/skills/sprite-editor/scripts/GenerateNewSpriteRects.cs +200 -0
- package/.claude/skills/sprite-editor/scripts/GetTextureSourceImageSize.cs +32 -0
- package/.claude/skills/sprite-editor/scripts/GetTextureToSlice.cs +55 -0
- package/.claude/skills/sprite-editor/scripts/GridSliceTexture.cs +40 -0
- package/.claude/skills/sprite-editor/scripts/IsometricSliceTexture.cs +141 -0
- package/.claude/skills/sprite-editor/scripts/README.md +134 -0
- package/.claude/skills/sprite-editor/scripts/SetPivotExample.cs +58 -0
- package/.claude/skills/sprite-editor/scripts/SpriteToPng.cs +88 -0
- package/.claude/skills/status/SKILL.md +16 -0
- package/.claude/skills/story-readiness/SKILL.md +14 -0
- package/.claude/skills/test/SKILL.md +16 -0
- package/.claude/skills/ui/SKILL.md +142 -0
- package/.claude/skills/ui-imgui/SKILL.md +186 -0
- package/.claude/skills/ui-imgui/references/gui-elements.md +156 -0
- package/.claude/skills/ui-imgui/references/templates.md +141 -0
- package/.claude/skills/ui-review/SKILL.md +14 -0
- package/.claude/skills/ui-ugui/SKILL.md +282 -0
- package/.claude/skills/ui-ugui/references/scrollview-setup.md +29 -0
- package/.claude/skills/ui-uitk/SKILL.md +235 -0
- package/.claude/skills/ui-uitk/references/common-issues.md +74 -0
- package/.claude/skills/ui-uitk/references/custom-elements.md +241 -0
- package/.claude/skills/ui-uitk/references/painter2d.md +282 -0
- package/.claude/skills/ui-uitk/references/pointermanipulator-guide.md +94 -0
- package/.claude/skills/ui-uitk/references/svg-icons.md +136 -0
- package/.claude/skills/ui-uitk/references/ui-runtime-binding.md +234 -0
- package/.claude/skills/ui-uitk/references/uss-guide.md +138 -0
- package/.claude/skills/unity-cli/CHANGELOG.md +233 -0
- package/.claude/skills/unity-cli/SECURITY.md +22 -0
- package/.claude/skills/unity-cli/SKILL.md +414 -0
- package/.claude/skills/unity-cli/references/auth-license-cloud.md +146 -0
- package/.claude/skills/unity-cli/references/build-run-test.md +349 -0
- package/.claude/skills/unity-cli/references/collaboration.md +472 -0
- package/.claude/skills/unity-cli/references/config-hub.md +103 -0
- package/.claude/skills/unity-cli/references/diagnostics-maintenance.md +326 -0
- package/.claude/skills/unity-cli/references/editors-install.md +327 -0
- package/.claude/skills/unity-cli/references/integration-advanced.md +472 -0
- package/.claude/skills/unity-cli/references/projects-templates.md +574 -0
- package/.claude/skills/unity-package-management/SKILL.md +304 -0
- package/.claude/skills/unity-package-management/references/select-packages.md +108 -0
- package/.claude/skills/urp-postprocessing/SKILL.md +188 -0
- package/.claude/skills/urp-postprocessing/references/code-templates.md +119 -0
- package/.claude/skills/urp-postprocessing/references/effect-reference.md +86 -0
- package/.claude/skills/validate-urp-render-graph-renderer-feature/SKILL.md +269 -0
- package/.claude/skills/work/SKILL.md +36 -0
- package/.claude/skills/work/references/classification.md +41 -0
- package/.claude/skills/work/references/closure.md +50 -0
- package/.claude/skills/work/references/feature-contracts.md +32 -0
- package/.claude/skills/work/references/verification.md +26 -0
- package/CLAUDE.md +6 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/THIRD_PARTY_NOTICES.md +23 -0
- package/UPGRADING.md +32 -0
- package/VERSION +1 -0
- package/docs/ARCHITECTURE.md +73 -0
- package/docs/HUONG-DAN-MIGRATE-VA-SU-DUNG.md +324 -0
- package/docs/MIGRATION-MATRIX.md +23 -0
- package/docs/PROJECT-POLICY.md +67 -0
- package/docs/WORKFLOWS.md +61 -0
- package/package-assets/setup-vivox-voice-chat-evals.gitignore +7 -0
- package/package.json +41 -0
- package/scaffold/.nccgs/bugs/.gitkeep +1 -0
- package/scaffold/.nccgs/closures/.gitkeep +1 -0
- package/scaffold/.nccgs/context/.gitkeep +1 -0
- package/scaffold/.nccgs/decisions/.gitkeep +1 -0
- package/scaffold/.nccgs/evidence/.gitkeep +1 -0
- package/scaffold/.nccgs/features/.gitkeep +1 -0
- package/scaffold/.nccgs/migrations/.gitkeep +1 -0
- package/scaffold/.nccgs/playtests/.gitkeep +1 -0
- package/scaffold/.nccgs/project.yaml +103 -0
- package/scaffold/.nccgs/requirements.yaml +10 -0
- package/scaffold/.nccgs/reviews/.gitkeep +1 -0
- package/scaffold/.nccgs/state.md +40 -0
- package/scaffold/.nccgs/templates/agent-handoff.md +25 -0
- package/scaffold/.nccgs/templates/architecture-decision.md +27 -0
- package/scaffold/.nccgs/templates/closure-record.md +51 -0
- package/scaffold/.nccgs/templates/context-packet.yaml +17 -0
- package/scaffold/.nccgs/templates/evidence-record.md +23 -0
- package/scaffold/.nccgs/templates/feature-contract.md +35 -0
- package/scaffold/.nccgs/templates/migration-plan.md +40 -0
- package/scaffold/.nccgs/templates/waiver.md +11 -0
- package/scripts/cli.mjs +56 -0
- package/scripts/install.mjs +267 -0
- package/scripts/sync-unity-skills.mjs +126 -0
- package/scripts/validate.mjs +205 -0
- package/tests/framework.test.mjs +121 -0
|
@@ -0,0 +1,899 @@
|
|
|
1
|
+
# Interstitial Ads API Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- [Overview](#overview)
|
|
5
|
+
- [Key Characteristics](#key-characteristics)
|
|
6
|
+
- [Implementation Pattern](#implementation-pattern)
|
|
7
|
+
- [API Reference](#api-reference)
|
|
8
|
+
- [Data Types](#data-types)
|
|
9
|
+
- [Best Practices](#best-practices)
|
|
10
|
+
- [Common Issues](#common-issues)
|
|
11
|
+
- [Testing Checklist](#testing-checklist)
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Interstitial ads are full-screen video or static ads shown at natural transition points in your app. They provide good revenue while maintaining acceptable user experience when placed thoughtfully.
|
|
16
|
+
|
|
17
|
+
## Key Characteristics
|
|
18
|
+
|
|
19
|
+
- **Full-screen**: Takes over the entire screen
|
|
20
|
+
- **Skippable**: User can close after viewing
|
|
21
|
+
- **Best for**: Level transitions, game over, menu navigation, session breaks
|
|
22
|
+
|
|
23
|
+
## Implementation Pattern
|
|
24
|
+
|
|
25
|
+
### Basic Interstitial Implementation
|
|
26
|
+
|
|
27
|
+
```csharp
|
|
28
|
+
using UnityEngine;
|
|
29
|
+
using Unity.Services.LevelPlay;
|
|
30
|
+
|
|
31
|
+
public class InterstitialAdManager : MonoBehaviour
|
|
32
|
+
{
|
|
33
|
+
private LevelPlayInterstitialAd interstitialAd;
|
|
34
|
+
private string adUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID";
|
|
35
|
+
|
|
36
|
+
void Start()
|
|
37
|
+
{
|
|
38
|
+
// Create the interstitial ad object using constructor
|
|
39
|
+
interstitialAd = new LevelPlayInterstitialAd(adUnitId);
|
|
40
|
+
|
|
41
|
+
// Register event listeners
|
|
42
|
+
interstitialAd.OnAdLoaded += OnAdLoaded;
|
|
43
|
+
interstitialAd.OnAdLoadFailed += OnAdLoadFailed;
|
|
44
|
+
interstitialAd.OnAdDisplayed += OnAdDisplayed;
|
|
45
|
+
interstitialAd.OnAdDisplayFailed += OnAdDisplayFailed;
|
|
46
|
+
interstitialAd.OnAdClicked += OnAdClicked;
|
|
47
|
+
interstitialAd.OnAdClosed += OnAdClosed;
|
|
48
|
+
interstitialAd.OnAdInfoChanged += OnAdInfoChanged; // Fires when the loaded ad updates after a new auction result
|
|
49
|
+
|
|
50
|
+
// Load the ad
|
|
51
|
+
LoadAd();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void OnDestroy()
|
|
55
|
+
{
|
|
56
|
+
// Unregister event listeners
|
|
57
|
+
if (interstitialAd != null)
|
|
58
|
+
{
|
|
59
|
+
interstitialAd.OnAdLoaded -= OnAdLoaded;
|
|
60
|
+
interstitialAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
61
|
+
interstitialAd.OnAdDisplayed -= OnAdDisplayed;
|
|
62
|
+
interstitialAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
63
|
+
interstitialAd.OnAdClicked -= OnAdClicked;
|
|
64
|
+
interstitialAd.OnAdClosed -= OnAdClosed;
|
|
65
|
+
interstitialAd.OnAdInfoChanged -= OnAdInfoChanged;
|
|
66
|
+
|
|
67
|
+
// Destroy the ad to free its native resources
|
|
68
|
+
interstitialAd.DestroyAd();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public void LoadAd()
|
|
73
|
+
{
|
|
74
|
+
Debug.Log("Loading interstitial ad...");
|
|
75
|
+
interstitialAd.LoadAd();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public void ShowAd()
|
|
79
|
+
{
|
|
80
|
+
if (interstitialAd.IsAdReady())
|
|
81
|
+
{
|
|
82
|
+
Debug.Log("Showing interstitial ad");
|
|
83
|
+
interstitialAd.ShowAd();
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
{
|
|
87
|
+
Debug.LogWarning("Interstitial ad is not ready yet");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Event Callbacks
|
|
92
|
+
private void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
93
|
+
{
|
|
94
|
+
Debug.Log("Interstitial ad loaded successfully");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
98
|
+
{
|
|
99
|
+
Debug.LogWarning($"Interstitial ad failed to load: {error.ErrorMessage}");
|
|
100
|
+
// Retry loading after a delay
|
|
101
|
+
Invoke(nameof(LoadAd), 30f);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private void OnAdDisplayed(LevelPlayAdInfo adInfo)
|
|
105
|
+
{
|
|
106
|
+
Debug.Log("Interstitial ad displayed");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private void OnAdDisplayFailed(LevelPlayAdInfo adInfo, LevelPlayAdError error)
|
|
110
|
+
{
|
|
111
|
+
Debug.LogError($"Interstitial ad failed to display: {error.ErrorMessage}");
|
|
112
|
+
// Load a new ad
|
|
113
|
+
LoadAd();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private void OnAdClicked(LevelPlayAdInfo adInfo)
|
|
117
|
+
{
|
|
118
|
+
Debug.Log("Interstitial ad clicked");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
122
|
+
{
|
|
123
|
+
Debug.Log("Interstitial ad closed");
|
|
124
|
+
// Load the next ad
|
|
125
|
+
LoadAd();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private void OnAdInfoChanged(LevelPlayAdInfo adInfo)
|
|
129
|
+
{
|
|
130
|
+
// Optional: log or update analytics with the latest revenue estimate
|
|
131
|
+
Debug.Log($"Interstitial ad info changed - network: {adInfo.AdNetwork}, revenue: ${adInfo.Revenue}");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Advanced: Frequency Capping
|
|
137
|
+
|
|
138
|
+
Implement time-based frequency capping to avoid showing ads too frequently:
|
|
139
|
+
|
|
140
|
+
```csharp
|
|
141
|
+
using UnityEngine;
|
|
142
|
+
using Unity.Services.LevelPlay;
|
|
143
|
+
|
|
144
|
+
public class FrequencyCappedInterstitialManager : MonoBehaviour
|
|
145
|
+
{
|
|
146
|
+
private LevelPlayInterstitialAd interstitialAd;
|
|
147
|
+
private string adUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID";
|
|
148
|
+
|
|
149
|
+
// Frequency capping settings
|
|
150
|
+
private float minTimeBetweenAds = 300f; // 5 minutes in seconds
|
|
151
|
+
private float lastAdShownTime = -999f; // Time when last ad was shown
|
|
152
|
+
|
|
153
|
+
void Start()
|
|
154
|
+
{
|
|
155
|
+
// Create interstitial ad object
|
|
156
|
+
interstitialAd = new LevelPlayInterstitialAd(adUnitId);
|
|
157
|
+
|
|
158
|
+
// Register callbacks
|
|
159
|
+
interstitialAd.OnAdLoaded += OnAdLoaded;
|
|
160
|
+
interstitialAd.OnAdLoadFailed += OnAdLoadFailed;
|
|
161
|
+
interstitialAd.OnAdDisplayed += OnAdDisplayed;
|
|
162
|
+
interstitialAd.OnAdClosed += OnAdClosed;
|
|
163
|
+
interstitialAd.OnAdDisplayFailed += OnAdDisplayFailed;
|
|
164
|
+
|
|
165
|
+
// Load first ad
|
|
166
|
+
interstitialAd.LoadAd();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
void OnDestroy()
|
|
170
|
+
{
|
|
171
|
+
if (interstitialAd != null)
|
|
172
|
+
{
|
|
173
|
+
interstitialAd.OnAdLoaded -= OnAdLoaded;
|
|
174
|
+
interstitialAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
175
|
+
interstitialAd.OnAdDisplayed -= OnAdDisplayed;
|
|
176
|
+
interstitialAd.OnAdClosed -= OnAdClosed;
|
|
177
|
+
interstitialAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
178
|
+
|
|
179
|
+
// Destroy the ad to free its native resources
|
|
180
|
+
interstitialAd.DestroyAd();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public void TryShowInterstitial()
|
|
185
|
+
{
|
|
186
|
+
// Check if enough time has passed since last ad
|
|
187
|
+
float timeSinceLastAd = Time.time - lastAdShownTime;
|
|
188
|
+
|
|
189
|
+
if (timeSinceLastAd < minTimeBetweenAds)
|
|
190
|
+
{
|
|
191
|
+
Debug.Log($"Frequency cap: {minTimeBetweenAds - timeSinceLastAd:F0}s until next ad");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Check if ad is ready
|
|
196
|
+
if (interstitialAd.IsAdReady())
|
|
197
|
+
{
|
|
198
|
+
interstitialAd.ShowAd();
|
|
199
|
+
}
|
|
200
|
+
else
|
|
201
|
+
{
|
|
202
|
+
Debug.LogWarning("Interstitial not ready, loading...");
|
|
203
|
+
interstitialAd.LoadAd();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
208
|
+
{
|
|
209
|
+
Debug.Log("Interstitial loaded");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
213
|
+
{
|
|
214
|
+
Debug.LogWarning($"Interstitial load failed: {error.ErrorMessage}");
|
|
215
|
+
Invoke(nameof(LoadAd), 30f);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private void OnAdDisplayed(LevelPlayAdInfo adInfo)
|
|
219
|
+
{
|
|
220
|
+
Debug.Log("Interstitial displayed");
|
|
221
|
+
lastAdShownTime = Time.time; // Record when ad was shown
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
225
|
+
{
|
|
226
|
+
Debug.Log("Interstitial closed");
|
|
227
|
+
// Load next ad
|
|
228
|
+
interstitialAd.LoadAd();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private void OnAdDisplayFailed(LevelPlayAdInfo adInfo, LevelPlayAdError error)
|
|
232
|
+
{
|
|
233
|
+
Debug.LogError($"Interstitial display failed: {error.ErrorMessage}");
|
|
234
|
+
interstitialAd.LoadAd();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private void LoadAd()
|
|
238
|
+
{
|
|
239
|
+
if (interstitialAd != null)
|
|
240
|
+
{
|
|
241
|
+
interstitialAd.LoadAd();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Advanced: Multiple Placements
|
|
248
|
+
|
|
249
|
+
Track different interstitial placements for analytics:
|
|
250
|
+
|
|
251
|
+
```csharp
|
|
252
|
+
using UnityEngine;
|
|
253
|
+
using Unity.Services.LevelPlay;
|
|
254
|
+
|
|
255
|
+
public class MultiPlacementInterstitialManager : MonoBehaviour
|
|
256
|
+
{
|
|
257
|
+
private LevelPlayInterstitialAd interstitialAd;
|
|
258
|
+
private string adUnitId = "YOUR_INTERSTITIAL_AD_UNIT_ID";
|
|
259
|
+
|
|
260
|
+
// Placement names
|
|
261
|
+
private const string PLACEMENT_LEVEL_COMPLETE = "level_complete";
|
|
262
|
+
private const string PLACEMENT_GAME_OVER = "game_over";
|
|
263
|
+
private const string PLACEMENT_MAIN_MENU = "main_menu";
|
|
264
|
+
|
|
265
|
+
// Frequency capping per placement
|
|
266
|
+
private float minTimeBetweenAds = 300f;
|
|
267
|
+
private float lastAdTime = -999f;
|
|
268
|
+
|
|
269
|
+
void Start()
|
|
270
|
+
{
|
|
271
|
+
interstitialAd = new LevelPlayInterstitialAd(adUnitId);
|
|
272
|
+
|
|
273
|
+
interstitialAd.OnAdLoaded += OnAdLoaded;
|
|
274
|
+
interstitialAd.OnAdLoadFailed += OnAdLoadFailed;
|
|
275
|
+
interstitialAd.OnAdDisplayed += OnAdDisplayed;
|
|
276
|
+
interstitialAd.OnAdClosed += OnAdClosed;
|
|
277
|
+
interstitialAd.OnAdDisplayFailed += OnAdDisplayFailed;
|
|
278
|
+
|
|
279
|
+
interstitialAd.LoadAd();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
void OnDestroy()
|
|
283
|
+
{
|
|
284
|
+
if (interstitialAd != null)
|
|
285
|
+
{
|
|
286
|
+
interstitialAd.OnAdLoaded -= OnAdLoaded;
|
|
287
|
+
interstitialAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
288
|
+
interstitialAd.OnAdDisplayed -= OnAdDisplayed;
|
|
289
|
+
interstitialAd.OnAdClosed -= OnAdClosed;
|
|
290
|
+
interstitialAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
291
|
+
|
|
292
|
+
// Destroy the ad to free its native resources
|
|
293
|
+
interstitialAd.DestroyAd();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Public methods for different placements
|
|
298
|
+
public void ShowOnLevelComplete()
|
|
299
|
+
{
|
|
300
|
+
TryShowWithPlacement(PLACEMENT_LEVEL_COMPLETE);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public void ShowOnGameOver()
|
|
304
|
+
{
|
|
305
|
+
TryShowWithPlacement(PLACEMENT_GAME_OVER);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
public void ShowOnMainMenu()
|
|
309
|
+
{
|
|
310
|
+
TryShowWithPlacement(PLACEMENT_MAIN_MENU);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private void TryShowWithPlacement(string placementName)
|
|
314
|
+
{
|
|
315
|
+
// Check frequency cap
|
|
316
|
+
if (Time.time - lastAdTime < minTimeBetweenAds)
|
|
317
|
+
{
|
|
318
|
+
Debug.Log($"Frequency cap active for {placementName}");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Check placement capping
|
|
323
|
+
if (LevelPlayInterstitialAd.IsPlacementCapped(placementName))
|
|
324
|
+
{
|
|
325
|
+
Debug.Log($"Placement {placementName} is capped");
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Check if ad ready
|
|
330
|
+
if (interstitialAd.IsAdReady())
|
|
331
|
+
{
|
|
332
|
+
Debug.Log($"Showing interstitial with placement: {placementName}");
|
|
333
|
+
interstitialAd.ShowAd(placementName: placementName);
|
|
334
|
+
}
|
|
335
|
+
else
|
|
336
|
+
{
|
|
337
|
+
Debug.LogWarning("Interstitial not ready");
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
342
|
+
{
|
|
343
|
+
Debug.Log("Interstitial loaded");
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
347
|
+
{
|
|
348
|
+
Debug.LogWarning($"Interstitial load failed: {error.ErrorMessage}");
|
|
349
|
+
Invoke(nameof(LoadAd), 30f);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private void OnAdDisplayed(LevelPlayAdInfo adInfo)
|
|
353
|
+
{
|
|
354
|
+
Debug.Log("Interstitial displayed");
|
|
355
|
+
lastAdTime = Time.time;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
359
|
+
{
|
|
360
|
+
Debug.Log("Interstitial closed");
|
|
361
|
+
interstitialAd.LoadAd();
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private void OnAdDisplayFailed(LevelPlayAdInfo adInfo, LevelPlayAdError error)
|
|
365
|
+
{
|
|
366
|
+
Debug.LogError($"Interstitial display failed: {error.ErrorMessage}");
|
|
367
|
+
interstitialAd.LoadAd();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
private void LoadAd()
|
|
371
|
+
{
|
|
372
|
+
if (interstitialAd != null)
|
|
373
|
+
{
|
|
374
|
+
interstitialAd.LoadAd();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## API Reference
|
|
381
|
+
|
|
382
|
+
### Constructor
|
|
383
|
+
|
|
384
|
+
#### `new LevelPlayInterstitialAd(string adUnitId)`
|
|
385
|
+
Create an interstitial ad object.
|
|
386
|
+
|
|
387
|
+
**Parameters:**
|
|
388
|
+
- `adUnitId`: The ad unit identifier from your LevelPlay dashboard
|
|
389
|
+
|
|
390
|
+
**Returns:** `LevelPlayInterstitialAd` object
|
|
391
|
+
|
|
392
|
+
**Usage:**
|
|
393
|
+
```csharp
|
|
394
|
+
LevelPlayInterstitialAd interstitialAd = new LevelPlayInterstitialAd("your_ad_unit_id");
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Important:** Call this only after `LevelPlay.Init()` has completed successfully (in the `OnInitSuccess` callback).
|
|
398
|
+
|
|
399
|
+
#### `new LevelPlayInterstitialAd(string adUnitId, Config config)`
|
|
400
|
+
Create an interstitial ad object with custom configuration.
|
|
401
|
+
|
|
402
|
+
**Parameters:**
|
|
403
|
+
- `adUnitId`: The ad unit identifier
|
|
404
|
+
- `config`: Optional configuration object
|
|
405
|
+
|
|
406
|
+
**Usage:**
|
|
407
|
+
```csharp
|
|
408
|
+
var configBuilder = new LevelPlayInterstitialAd.Config.Builder();
|
|
409
|
+
configBuilder.SetBidFloor(1.0); // Minimum bid price in USD
|
|
410
|
+
var config = configBuilder.Build();
|
|
411
|
+
LevelPlayInterstitialAd interstitialAd = new LevelPlayInterstitialAd("your_ad_unit_id", config);
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Configuration Builder
|
|
415
|
+
|
|
416
|
+
#### `LevelPlayInterstitialAd.Config.Builder()`
|
|
417
|
+
Create a configuration builder for interstitial ads.
|
|
418
|
+
|
|
419
|
+
**Returns:** `LevelPlayInterstitialAd.Config.Builder` object
|
|
420
|
+
|
|
421
|
+
**Usage:**
|
|
422
|
+
```csharp
|
|
423
|
+
var configBuilder = new LevelPlayInterstitialAd.Config.Builder();
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Set minimum bid price:**
|
|
427
|
+
```csharp
|
|
428
|
+
configBuilder.SetBidFloor(1.0); // Minimum bid price in USD ($1.00 CPM)
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**When to use:** Set a minimum bid price in USD for ad requests.
|
|
432
|
+
|
|
433
|
+
#### `Build()`
|
|
434
|
+
Build the configuration object.
|
|
435
|
+
|
|
436
|
+
**Returns:** `LevelPlayInterstitialAd.Config` object
|
|
437
|
+
|
|
438
|
+
**Usage:**
|
|
439
|
+
```csharp
|
|
440
|
+
var config = configBuilder.Build();
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Core Methods
|
|
444
|
+
|
|
445
|
+
#### `LoadAd()`
|
|
446
|
+
Load an interstitial ad.
|
|
447
|
+
|
|
448
|
+
**Usage:**
|
|
449
|
+
```csharp
|
|
450
|
+
interstitialAd.LoadAd();
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**When to call:**
|
|
454
|
+
- After SDK initialization completes
|
|
455
|
+
- After showing an ad (to load the next one)
|
|
456
|
+
- After a load or display failure
|
|
457
|
+
|
|
458
|
+
#### `ShowAd()`
|
|
459
|
+
Show the interstitial ad without a placement name.
|
|
460
|
+
|
|
461
|
+
**Usage:**
|
|
462
|
+
```csharp
|
|
463
|
+
if (interstitialAd.IsAdReady())
|
|
464
|
+
{
|
|
465
|
+
interstitialAd.ShowAd();
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**Important:** Always check `IsAdReady()` before calling `ShowAd()`.
|
|
470
|
+
|
|
471
|
+
#### `ShowAd(placementName: string)`
|
|
472
|
+
Show the interstitial ad with a named placement for analytics tracking.
|
|
473
|
+
|
|
474
|
+
**Parameters:**
|
|
475
|
+
- `placementName`: Placement name configured in LevelPlay dashboard
|
|
476
|
+
|
|
477
|
+
**Usage:**
|
|
478
|
+
```csharp
|
|
479
|
+
interstitialAd.ShowAd(placementName: "level_complete");
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**When to use:** When tracking multiple placements within the same ad unit for analytics.
|
|
483
|
+
|
|
484
|
+
#### `IsAdReady()`
|
|
485
|
+
Check if an interstitial ad is loaded and ready to show.
|
|
486
|
+
|
|
487
|
+
**Returns:** `bool` - true if ready, false otherwise
|
|
488
|
+
|
|
489
|
+
**Usage:**
|
|
490
|
+
```csharp
|
|
491
|
+
if (interstitialAd.IsAdReady())
|
|
492
|
+
{
|
|
493
|
+
// Ad is ready to show
|
|
494
|
+
interstitialAd.ShowAd();
|
|
495
|
+
}
|
|
496
|
+
else
|
|
497
|
+
{
|
|
498
|
+
// Ad not ready, load it
|
|
499
|
+
interstitialAd.LoadAd();
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
#### `LevelPlayInterstitialAd.IsPlacementCapped(string placementName)` (Static)
|
|
504
|
+
Check if a placement has reached its capping limit.
|
|
505
|
+
|
|
506
|
+
**Parameters:**
|
|
507
|
+
- `placementName`: The placement name to check
|
|
508
|
+
|
|
509
|
+
**Returns:** `bool` - true if capped, false otherwise
|
|
510
|
+
|
|
511
|
+
**Usage:**
|
|
512
|
+
```csharp
|
|
513
|
+
if (LevelPlayInterstitialAd.IsPlacementCapped("level_complete"))
|
|
514
|
+
{
|
|
515
|
+
Debug.Log("Level complete placement is capped");
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**When to use:** Before showing an ad to check if the placement frequency cap is reached.
|
|
520
|
+
|
|
521
|
+
### Events
|
|
522
|
+
|
|
523
|
+
All events are properties of the `LevelPlayInterstitialAd` object.
|
|
524
|
+
|
|
525
|
+
**Threading:** All ad callbacks run on the Unity main thread, so you can safely call Unity APIs (update UI, access GameObjects, etc.) directly in these callbacks. This is different from the ILRD impression callback (see `references/ilrd-api.md`), which runs on a background thread.
|
|
526
|
+
|
|
527
|
+
#### `OnAdLoaded`
|
|
528
|
+
Fired when an interstitial ad is successfully loaded.
|
|
529
|
+
|
|
530
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
531
|
+
|
|
532
|
+
**Usage:**
|
|
533
|
+
```csharp
|
|
534
|
+
interstitialAd.OnAdLoaded += (adInfo) =>
|
|
535
|
+
{
|
|
536
|
+
Debug.Log("Interstitial ad loaded");
|
|
537
|
+
};
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
#### `OnAdLoadFailed`
|
|
541
|
+
Fired when an interstitial ad fails to load.
|
|
542
|
+
|
|
543
|
+
**Signature:** `event Action<LevelPlayAdError>`
|
|
544
|
+
|
|
545
|
+
**Usage:**
|
|
546
|
+
```csharp
|
|
547
|
+
interstitialAd.OnAdLoadFailed += (error) =>
|
|
548
|
+
{
|
|
549
|
+
Debug.LogWarning($"Load failed: {error.ErrorMessage}");
|
|
550
|
+
};
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**Best practice:** Implement retry logic with exponential backoff.
|
|
554
|
+
|
|
555
|
+
#### `OnAdDisplayed`
|
|
556
|
+
Fired when an interstitial ad is displayed on screen.
|
|
557
|
+
|
|
558
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
559
|
+
|
|
560
|
+
**Usage:**
|
|
561
|
+
```csharp
|
|
562
|
+
interstitialAd.OnAdDisplayed += (adInfo) =>
|
|
563
|
+
{
|
|
564
|
+
Debug.Log("Interstitial ad displayed");
|
|
565
|
+
// Optional: Track analytics
|
|
566
|
+
};
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
#### `OnAdDisplayFailed`
|
|
570
|
+
Fired when an interstitial ad fails to display.
|
|
571
|
+
|
|
572
|
+
**Signature:** `event Action<LevelPlayAdInfo, LevelPlayAdError>`
|
|
573
|
+
|
|
574
|
+
**Usage:**
|
|
575
|
+
```csharp
|
|
576
|
+
interstitialAd.OnAdDisplayFailed += (adInfo, error) =>
|
|
577
|
+
{
|
|
578
|
+
Debug.LogError($"Display failed: {error.ErrorMessage}");
|
|
579
|
+
// Load a new ad
|
|
580
|
+
interstitialAd.LoadAd();
|
|
581
|
+
};
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
#### `OnAdClicked`
|
|
585
|
+
Fired when the user clicks on the interstitial ad.
|
|
586
|
+
|
|
587
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
588
|
+
|
|
589
|
+
**Usage:**
|
|
590
|
+
```csharp
|
|
591
|
+
interstitialAd.OnAdClicked += (adInfo) =>
|
|
592
|
+
{
|
|
593
|
+
Debug.Log("Interstitial ad clicked");
|
|
594
|
+
// Optional analytics tracking
|
|
595
|
+
};
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
#### `OnAdClosed`
|
|
599
|
+
Fired when the interstitial ad is closed.
|
|
600
|
+
|
|
601
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
602
|
+
|
|
603
|
+
**Usage:**
|
|
604
|
+
```csharp
|
|
605
|
+
interstitialAd.OnAdClosed += (adInfo) =>
|
|
606
|
+
{
|
|
607
|
+
Debug.Log("Interstitial ad closed");
|
|
608
|
+
// Resume game, load next ad
|
|
609
|
+
interstitialAd.LoadAd();
|
|
610
|
+
};
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
**Best practice:** Load the next ad immediately in this callback.
|
|
614
|
+
|
|
615
|
+
#### `OnAdInfoChanged`
|
|
616
|
+
Fired when ad information changes, such as when a new winning ad becomes available after auction.
|
|
617
|
+
|
|
618
|
+
**Signature:** `event Action<LevelPlayAdInfo>`
|
|
619
|
+
|
|
620
|
+
**Usage:**
|
|
621
|
+
```csharp
|
|
622
|
+
interstitialAd.OnAdInfoChanged += (adInfo) =>
|
|
623
|
+
{
|
|
624
|
+
Debug.Log($"Ad info changed - New ad from: {adInfo.AdNetwork}");
|
|
625
|
+
Debug.Log($"Estimated revenue: ${adInfo.Revenue}");
|
|
626
|
+
};
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
**Important:** This event indicates that a new ad with potentially different revenue has become available. The SDK automatically selects the winning ad from the auction when you call `ShowAd()`, but this event lets you know when the ad info has been updated. This is particularly important for revenue optimization as it signals when a new auction winner has loaded.
|
|
630
|
+
|
|
631
|
+
**When it fires:**
|
|
632
|
+
- After a new ad loads with different properties than the previous one
|
|
633
|
+
- When the waterfall selects a different ad network
|
|
634
|
+
- When ad auction results change
|
|
635
|
+
|
|
636
|
+
**Why it matters:** The updated `LevelPlayAdInfo` contains the latest revenue estimates and network information, which directly impacts your monetization. Always use the most recent `adInfo` when logging or analyzing ad performance.
|
|
637
|
+
|
|
638
|
+
**If you're using ILRD** (`references/ilrd-api.md`): the `LevelPlayImpressionData` you receive in the ILRD impression callback already contains the final revenue value, so `OnAdInfoChanged` is mostly useful for in-Editor debugging of the waterfall. Most publishers can leave it as a logging hook.
|
|
639
|
+
|
|
640
|
+
## Data Types
|
|
641
|
+
|
|
642
|
+
### LevelPlayAdInfo
|
|
643
|
+
|
|
644
|
+
Contains information about the ad.
|
|
645
|
+
|
|
646
|
+
**Properties:**
|
|
647
|
+
- `AdId` (string): Unique identifier for this specific ad instance
|
|
648
|
+
- `AdUnitId` (string): The ad unit identifier
|
|
649
|
+
- `AdUnitName` (string): The ad unit name
|
|
650
|
+
- `AdSize` (LevelPlayAdSize): The ad size (may be null; banner-relevant)
|
|
651
|
+
- `AdFormat` (string): The ad format (e.g., "INTERSTITIAL")
|
|
652
|
+
- `PlacementName` (string): Placement name where ad was shown
|
|
653
|
+
- `AuctionId` (string): Unique auction identifier
|
|
654
|
+
- `CreativeId` (string): Creative identifier
|
|
655
|
+
- `Country` (string): User's country code (ISO 3166-1)
|
|
656
|
+
- `Ab` (string): A/B test segment identifier
|
|
657
|
+
- `SegmentName` (string): User segment name
|
|
658
|
+
- `AdNetwork` (string): Ad network that served the ad
|
|
659
|
+
- `InstanceName` (string): Ad network instance name
|
|
660
|
+
- `InstanceId` (string): Ad network instance identifier
|
|
661
|
+
- `Revenue` (double?): Estimated revenue in USD (nullable - check for null)
|
|
662
|
+
- `Precision` (string): Revenue precision level
|
|
663
|
+
- `EncryptedCPM` (string): Encrypted CPM value
|
|
664
|
+
|
|
665
|
+
### LevelPlayAdError
|
|
666
|
+
|
|
667
|
+
Contains error information when ad operations fail.
|
|
668
|
+
|
|
669
|
+
**Properties:**
|
|
670
|
+
- `ErrorCode` (int): Numeric error code
|
|
671
|
+
- `ErrorMessage` (string): Human-readable error description
|
|
672
|
+
- `AdUnitId` (string): The ad unit identifier where the error occurred
|
|
673
|
+
- `AdId` (string): Unique identifier for the specific ad instance
|
|
674
|
+
|
|
675
|
+
## Best Practices
|
|
676
|
+
|
|
677
|
+
### Loading Strategy
|
|
678
|
+
|
|
679
|
+
**Keep an interstitial ready for opportunistic moments:**
|
|
680
|
+
```csharp
|
|
681
|
+
// Load after init
|
|
682
|
+
void OnInitSuccess(LevelPlayConfiguration config)
|
|
683
|
+
{
|
|
684
|
+
interstitialAd = new LevelPlayInterstitialAd(adUnitId);
|
|
685
|
+
interstitialAd.OnAdLoaded += OnAdLoaded;
|
|
686
|
+
interstitialAd.OnAdClosed += OnAdClosed;
|
|
687
|
+
interstitialAd.LoadAd();
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Reload after showing
|
|
691
|
+
void OnAdClosed(LevelPlayAdInfo adInfo)
|
|
692
|
+
{
|
|
693
|
+
interstitialAd.LoadAd();
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Placement Strategy
|
|
698
|
+
|
|
699
|
+
**Show at natural transition points:**
|
|
700
|
+
- ✅ Level complete screen
|
|
701
|
+
- ✅ Game over screen
|
|
702
|
+
- ✅ Returning to main menu
|
|
703
|
+
- ✅ Between sessions
|
|
704
|
+
- ❌ During active gameplay
|
|
705
|
+
- ❌ Mid-level or mid-action
|
|
706
|
+
|
|
707
|
+
### Frequency Capping
|
|
708
|
+
|
|
709
|
+
**Implement time-based capping to avoid annoying users:**
|
|
710
|
+
```csharp
|
|
711
|
+
private float minTimeBetweenAds = 300f; // 5 minutes
|
|
712
|
+
private float lastAdTime = -999f;
|
|
713
|
+
|
|
714
|
+
public void TryShowInterstitial()
|
|
715
|
+
{
|
|
716
|
+
if (Time.time - lastAdTime < minTimeBetweenAds)
|
|
717
|
+
{
|
|
718
|
+
Debug.Log("Too soon to show another ad");
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (interstitialAd.IsAdReady())
|
|
723
|
+
{
|
|
724
|
+
interstitialAd.ShowAd();
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
private void OnAdDisplayed(LevelPlayAdInfo adInfo)
|
|
729
|
+
{
|
|
730
|
+
lastAdTime = Time.time;
|
|
731
|
+
}
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
**Recommended frequencies:**
|
|
735
|
+
- **Revenue-focused**: 3-5 minutes
|
|
736
|
+
- **Balanced**: 5-7 minutes
|
|
737
|
+
- **UX-focused**: 7-10 minutes or never
|
|
738
|
+
|
|
739
|
+
### User Flow
|
|
740
|
+
|
|
741
|
+
**Never block user progress waiting for ads:**
|
|
742
|
+
```csharp
|
|
743
|
+
// ✅ CORRECT - Don't block flow
|
|
744
|
+
public void OnLevelComplete()
|
|
745
|
+
{
|
|
746
|
+
// Continue to next level regardless of ad
|
|
747
|
+
LoadNextLevel();
|
|
748
|
+
|
|
749
|
+
// Try to show ad, but don't wait for it
|
|
750
|
+
TryShowInterstitial();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// ❌ WRONG - Blocking user
|
|
754
|
+
public void OnLevelComplete()
|
|
755
|
+
{
|
|
756
|
+
if (interstitialAd.IsAdReady())
|
|
757
|
+
{
|
|
758
|
+
interstitialAd.ShowAd();
|
|
759
|
+
// Don't wait here to load next level!
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Error Handling
|
|
765
|
+
|
|
766
|
+
**Handle ad load failures:**
|
|
767
|
+
```csharp
|
|
768
|
+
private void OnAdLoadFailed(LevelPlayAdError error)
|
|
769
|
+
{
|
|
770
|
+
Debug.LogWarning($"Ad load failed: {error.ErrorMessage}");
|
|
771
|
+
|
|
772
|
+
// Retry loading after a delay
|
|
773
|
+
Invoke(nameof(RetryLoad), 30f);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
private void RetryLoad()
|
|
777
|
+
{
|
|
778
|
+
interstitialAd.LoadAd();
|
|
779
|
+
}
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
### Memory Management
|
|
783
|
+
|
|
784
|
+
**Always unsubscribe from events:**
|
|
785
|
+
```csharp
|
|
786
|
+
void OnDestroy()
|
|
787
|
+
{
|
|
788
|
+
if (interstitialAd != null)
|
|
789
|
+
{
|
|
790
|
+
interstitialAd.OnAdLoaded -= OnAdLoaded;
|
|
791
|
+
interstitialAd.OnAdLoadFailed -= OnAdLoadFailed;
|
|
792
|
+
interstitialAd.OnAdDisplayed -= OnAdDisplayed;
|
|
793
|
+
interstitialAd.OnAdDisplayFailed -= OnAdDisplayFailed;
|
|
794
|
+
interstitialAd.OnAdClicked -= OnAdClicked;
|
|
795
|
+
interstitialAd.OnAdClosed -= OnAdClosed;
|
|
796
|
+
interstitialAd.OnAdInfoChanged -= OnAdInfoChanged;
|
|
797
|
+
|
|
798
|
+
// Destroy the ad to free its native resources
|
|
799
|
+
interstitialAd.DestroyAd();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
## Common Issues
|
|
805
|
+
|
|
806
|
+
### Issue: Error 1037 (Load during load)
|
|
807
|
+
|
|
808
|
+
**Cause:** Calling `LoadAd()` repeatedly in `Update()` or other high-frequency loops before the previous load completes.
|
|
809
|
+
|
|
810
|
+
**Common mistake:**
|
|
811
|
+
```csharp
|
|
812
|
+
void Update()
|
|
813
|
+
{
|
|
814
|
+
// WRONG - This will cause error 1037!
|
|
815
|
+
if (!interstitialAd.IsAdReady())
|
|
816
|
+
{
|
|
817
|
+
interstitialAd.LoadAd();
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
**Why this fails:** If the ad is still loading, calling `LoadAd()` again triggers error 1037: "Cannot load an interstitial while another interstitial is loading."
|
|
823
|
+
|
|
824
|
+
**Solution:** Track load state manually and only call `LoadAd()` once:
|
|
825
|
+
```csharp
|
|
826
|
+
private bool isLoadingAd = false;
|
|
827
|
+
|
|
828
|
+
void Start()
|
|
829
|
+
{
|
|
830
|
+
LoadInterstitialAd();
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
void LoadInterstitialAd()
|
|
834
|
+
{
|
|
835
|
+
if (isLoadingAd) return; // Prevent duplicate loads
|
|
836
|
+
|
|
837
|
+
isLoadingAd = true;
|
|
838
|
+
interstitialAd.LoadAd();
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
void OnAdLoaded(LevelPlayAdInfo adInfo)
|
|
842
|
+
{
|
|
843
|
+
isLoadingAd = false;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
void OnAdLoadFailed(LevelPlayAdError error)
|
|
847
|
+
{
|
|
848
|
+
isLoadingAd = false;
|
|
849
|
+
// Optionally retry after delay
|
|
850
|
+
}
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
### Issue: Interstitial showing too frequently
|
|
854
|
+
|
|
855
|
+
**Solution:** Implement frequency capping based on time or session count. Track when the last ad was shown and enforce a minimum interval.
|
|
856
|
+
|
|
857
|
+
### Issue: User flow blocked by ad loading
|
|
858
|
+
|
|
859
|
+
**Solution:** Never wait for ads to load or show before progressing the user. Load ads proactively and show them opportunistically.
|
|
860
|
+
|
|
861
|
+
### Issue: Ad not loading
|
|
862
|
+
|
|
863
|
+
**Possible causes:**
|
|
864
|
+
- SDK not initialized before creating ad object
|
|
865
|
+
- No internet connection
|
|
866
|
+
- Ad inventory not available
|
|
867
|
+
- Incorrect ad unit ID
|
|
868
|
+
|
|
869
|
+
**Solutions:**
|
|
870
|
+
- Create ad object only after `OnInitSuccess` callback
|
|
871
|
+
- Check network connectivity
|
|
872
|
+
- Verify ad unit ID in LevelPlay dashboard
|
|
873
|
+
- Test on real device with good connection
|
|
874
|
+
|
|
875
|
+
### Issue: Ad loading but not showing
|
|
876
|
+
|
|
877
|
+
**Possible causes:**
|
|
878
|
+
- Not checking `IsAdReady()` before calling `ShowAd()`
|
|
879
|
+
- Ad expired (loaded too long ago)
|
|
880
|
+
|
|
881
|
+
**Solutions:**
|
|
882
|
+
- Always check `IsAdReady()` before showing
|
|
883
|
+
- Load ads close to when they'll be shown (within a few minutes)
|
|
884
|
+
|
|
885
|
+
## Testing Checklist
|
|
886
|
+
|
|
887
|
+
- [ ] Ad loads successfully after SDK initialization
|
|
888
|
+
- [ ] `IsAdReady()` returns true when ad is loaded
|
|
889
|
+
- [ ] Ad displays correctly when `ShowAd()` is called
|
|
890
|
+
- [ ] Ad shows at appropriate transition points only
|
|
891
|
+
- [ ] Frequency capping works as expected
|
|
892
|
+
- [ ] User can progress regardless of ad status
|
|
893
|
+
- [ ] Ad reloads automatically after being shown
|
|
894
|
+
- [ ] Retry logic works when ad fails to load
|
|
895
|
+
- [ ] Multiple placements track correctly (if using)
|
|
896
|
+
- [ ] Placement capping works (if configured)
|
|
897
|
+
- [ ] Memory leaks prevented (events unsubscribed)
|
|
898
|
+
- [ ] Tested on multiple devices and network conditions
|
|
899
|
+
- [ ] Ad doesn't interrupt active gameplay
|