HyperCasual
Essentials
Drop-in Unity toolkit for hyper-casual games. Audio, economy, IAP, ads, haptics, daily rewards, reward wheel, skin shop, toon shaders, and more — all wired up and ready to ship.
Overview
Everything you need for a hyper-casual game, nothing you don't.
🔊 Audio
Pooled SFX, crossfading music, per-category mixer
💰 Economy
Multi-currency wallet with overflow protection
🛒 Shop & Skins
Item catalog, material & mesh skin system
💳 IAP
Unity IAP wrapper with dummy testing backend
📺 Ads
AdMob rewarded, interstitial & banner ads
📳 Haptics
Pattern-based vibration for Android & iOS
🎁 Daily Rewards
Streak tracking, welcome gifts, ad-boosted claims
🎱 Reward Wheel
Weighted spinner with tick audio cues
🎲 Minigames
Chest loot drops & slot machine
🗨 Popups & Toasts
Modal popup stack & FIFO toast queue
🔒 Feature Gating
Level, currency, cooldown & flag unlock gates
🌈 Toon Shaders
Cel-shaded rendering for all pipelines
📊 Analytics
Pluggable bus with Firebase & Unity sinks
🔔 Notifications
Local push notifications on mobile
⭐ Rate Us
Gated review prompts with soft-prompt option
💾 Save System
Versioned blobs with schema migration
🎬 Scene Flow
Async scene loading with fade transitions
🎮 Cheats
Debug console with hotkeys & 3-finger gesture
🔧 Editor Tools
Setup wizard, toolset window, CSV importers
📚 Scripting Defines
Feature flags for optional SDK integrations
Quick Start
Get up and running in under 2 minutes.
Import HyperCasual Essentials into your Unity project via the Asset Store or by copying the
HyperCasualEssentials/ folder into Assets/.Open
Tools → HCE → Setup Wizard. Toggle both options (create default configs + enable cheats) and click Run.Open
Tools → HCE → Toolset to see the status of all modules. Green = ready, yellow = warning, red = action needed.Import the sample from
Samples~/Demo/ and open DemoScene.unity. Press Play to see every module in action.Open
Resources/HCE/HCESettings.asset and fill in your ad unit IDs, IAP product IDs, and notification settings. Switch modes from Dummy to Production when ready.Packages/manifest.json, opens URLs, or downloads anything without your explicit consent.Automatic Bootstrap
At runtime, two bootstrappers fire automatically — no scene setup required:
GameBootstrapper applies your HCESettings: target frame rate (default 60), screen sleep prevention, time scale restoration, and multi-touch.
Sample Prefabs
| Prefab | Purpose |
|---|---|
HCE_Bootstrap | Initializes services, loads save data |
HCE_ToastCanvas | FIFO toast notification queue |
HCE_PopupCanvas | Modal popup stack with backdrop |
HCE_FadeCanvas | Black overlay for scene transitions |
HCE_WheelPrefab | Spinning prize wheel UI |
HCE_ShopItemPrefab | Single shop item row template |
HCE_CoinBurstPrefab | Coin gather particle animation |
HCE_BannerAnchor | Banner ad positioning container |
HCE_HudPrefab | Live currency balance display |
Architecture
How everything connects under the hood.
Service Locator Pattern
All modules register and resolve dependencies through the static HCE.Core.Services class. This keeps systems decoupled — Audio doesn't know about Economy, Economy doesn't know about Shop.
Factory Pattern
Platform-specific backends (Ads, Haptics, IAP, Notifications, Rate Us) are created by factory classes that read HCESettings and select the right implementation. Missing SDKs gracefully fall back to dummy/mock backends.
ScriptableObject Configuration
Every system is configured through Inspector-editable ScriptableObject assets. No hardcoded values, no code changes needed for designers to tune behavior.
Event-Driven Updates
Services emit C# events (BalanceChanged, Purchased, SpinCompleted, etc.) so UI automatically reacts to state changes without polling.
Folder Structure
HyperCasualEssentials/
Config/ // Default ScriptableObject configs
Demo/ // Feature dashboard
Documentation~/ // This documentation
Editor/ // Editor windows, inspectors, importers
Plugins/ // Native iOS/Android code
Resources/HCE/ // HCESettings singleton + icons
Runtime/ // All game systems (148 C# files)
Ads/ Analytics/ Audio/ Cheats/ Core/
DailyReward/ Economy/ Flow/ Gating/
Haptics/ IAP/ Minigames/ Notifications/
RateUs/ Save/ Shaders/ Shop/ UI/ Wheel/
Samples~/ // Optional importable demo
Service Locator
Minimal static registry for dependency injection.
// Register a service (once, during bootstrap)
Services.Register<AudioService>(new AudioService());
// Resolve anywhere
var audio = Services.Resolve<IAudioService>();
audio.Play(new SoundId("click"));
// Safe resolve (no exception if missing)
if (Services.TryResolve<IWalletService>(out var wallet))
wallet.Credit(CurrencyId.Coins, 100, "bonus");C#
| Method | Description |
|---|---|
Register<T>(T instance) | Bind a singleton by type. Throws if already registered. |
Resolve<T>() | Get a registered service. Throws if missing. |
TryResolve<T>(out T) | Non-throwing resolve. Returns false if missing. |
IsRegistered<T>() | Check existence without throwing. |
Unregister<T>() | Remove a binding. No-op if absent. |
HCE Settings
Single ScriptableObject configuring every module.
Located at Resources/HCE/HCESettings.asset. Access at runtime via HCESettings.Instance. Falls back to safe defaults if the asset is missing.
General Settings
| Field | Default | Description |
|---|---|---|
TargetFrameRate | 60 | Application.targetFrameRate (set if currently ≤ 0) |
NeverSleep | true | Prevent screen sleep on mobile |
VerboseLogging | false | Enable detailed HCE log output |
All Sub-Settings
HCESettings contains nested settings objects for each module:
| Property | Type | Section |
|---|---|---|
Ads | AdMobSettings | Ads |
Analytics | AnalyticsSettings | Analytics |
IAP | IAPSettings | IAP |
Audio | AudioSettings | Audio |
Haptics | HapticsSettings | Haptics |
Notifications | NotificationsSettings | Notifications |
RateUs | RateUsSettings | Rate Us |
WelcomeGifts | WelcomeGiftsSettings | Daily Rewards |
Minigames | MinigamesSettings | Minigames |
General | GeneralSettings | Above |
Save System
Versioned JSON blobs with schema migration and debounced writes.
How It Works
All game state is serialized into a SaveBlobV1 and stored in a single PlayerPrefs key (HCE_SAVE_V1). Writes are debounced to at most once per second to avoid I/O spam.
// Save
var blob = new SaveBlobV1();
walletService.SaveToBlob(blob);
shopService.SaveToBlob(blob);
backend.WriteBlob(blob);
// Load
var loaded = backend.ReadBlob();
if (loaded != null) {
loaded = SaveMigrator.Upgrade(loaded, loaded.SchemaVersion, SaveMigrator.CurrentVersion);
walletService.LoadFromBlob(loaded);
shopService.LoadFromBlob(loaded);
}C#
SaveBlobV1 Structure
| Field | Type | Purpose |
|---|---|---|
SchemaVersion | int | Current schema version (1) |
Balances | List<BalanceRecord> | Currency ID + amount pairs |
Strings | List<StringKvp> | Generic key-value pairs |
Owned | List<OwnedEntry> | Shop item ownership + equipped flag |
LastDailyStamp | string | Last daily reward claim timestamp |
StreakCount | int | Current daily reward streak |
Schema Migration
When adding new fields, create a new schema version and register an upgrader in SaveMigrator.Upgrade(). The migrator chains upgrades: V0 → V1 → V2 → etc.
HCE_ to avoid collisions with your project's data.Scene Flow
Async scene loading with fade transitions and cooldown timers.
SceneFadeService
Load scenes with a smooth fade-out / load / fade-in sequence. Uses unscaled delta time so it works even when the game is paused.
var fadeService = new SceneFadeService(fadeConfig, overlayImage);
await fadeService.LoadAsync(sceneRef);C#
CooldownTimer
Invariant-culture cooldown gate. Serializes to tick strings that are safe across locales and devices.
var timer = new CooldownTimer(timeSource, TimeSpan.FromHours(24), "daily_reward", savedStamp);
if (timer.IsReady) {
// Grant reward
timer.Stamp();
PlayerPrefs.SetString("stamp", timer.ToSave());
} else {
Debug.Log($"Ready in {timer.Remaining.TotalHours:F1}h");
}C#
Time Sources
| Source | Use Case | Anti-Cheat |
|---|---|---|
LocalTimeSource | Default wall-clock time | No — user can change device clock |
ServerTimeSource | HTTP HEAD probe for UTC time | Yes — reads server Date header |
Tweening
Lightweight static tween driver via TweenRunner. Supports Move, Rotate, Scale, and Fade with easing and cancellation.
TweenRunner.Scale(transform, Vector3.zero, Vector3.one, 0.4f, Easing.OutBack);
TweenRunner.Fade(canvasGroup, 0f, 1f, 0.3f, Easing.InOutSine);C#
Available easing functions: Linear, InOutQuart, InOutSine, OutCubic, OutBack.
Audio
Pooled SFX playback, crossfading music, and a per-category mixer.
Setup
Right-click in Project →
Create → HCE → Audio → Sound Bank. Add entries with ID, AudioClip, volume, pitch, and category.Drag your SoundBank into
HCESettings → Audio → DefaultSoundBank.Resolve the service and call
Play() with a SoundId.// Play SFX
var audio = Services.Resolve<IAudioService>();
audio.Play(new SoundId("click"));
audio.Play(new SoundId("explosion"), 0.5f); // 50% volume
// Play music with crossfade
audio.PlayMusic(new SoundId("menu_loop"), 2f);
// Mixer control
audio.SetVolume(AudioCategory.Sfx, 0.8f);
audio.SetMute(AudioCategory.Music, true);C#
SoundBank Entry Fields
| Field | Range | Description |
|---|---|---|
Id | — | Unique string identifier |
Clip | — | AudioClip reference |
Volume | 0–1 | Entry volume (multiplied by master × category) |
Pitch | 0.1–3 | Playback pitch |
PitchJitter | 0–0.5 | Random pitch variance (±jitter) |
Category | — | Sfx, Music, UI, Voice, or Ambient |
Loop | — | Continuous playback for music/ambient |
CSV Import
Bulk-populate a SoundBank: select it in the Project window, then Tools → HCE → Import SoundBank CSV.
# id, clipName, volume, pitch, pitchJitter
click, UI_Click, 0.8, 1.0, 0.05
footstep, Footstep_Concrete, 1.0, 1.2, 0.1
ambient_wind, , 1.0, 1.0, 0CSV
Play() on an entry tagged as AudioCategory.Music, it automatically routes to PlayMusic() with crossfade.Audio Mix Formula
Final Volume = Entry.Volume × Master × Category
(0 if MasterMuted OR CategoryMuted)
Final Pitch = Entry.Pitch ± Random(PitchJitter)text
Haptics
Pattern-based vibration with platform-specific backends.
Setup
var haptics = new HapticService();
haptics.Initialize();
var pattern = Resources.Load<HapticPattern>("Light");
haptics.Play(pattern);
haptics.Cancel(); // Stop vibrationC#
HapticPattern Fields
| Field | Type | Description |
|---|---|---|
DurationsMs | long[] | Duration of each pulse in ms |
Amplitudes | int[] | Intensity per pulse (0–255) |
PredefinedId | int | Platform effect ID (-1 = use custom waveform) |
Platform Backends
| Platform | Backend | Features |
|---|---|---|
| Android 26+ | AndroidHapticsBackend | VibrationEffect waveforms, predefined effects (29+) |
| Android <26 | AndroidHapticsBackend | Legacy vibrate (no amplitudes) |
| iOS | IOSHapticsBackend | CoreHaptics via native plugin |
| Editor | EditorHapticsBackend | Log-only (no vibration) |
Mode Configuration
In HCESettings → Haptics:
- Disabled: All calls dropped silently
- Dummy: Logs to console, no vibration
- Production: Real platform vibration
Plugins folder. To enable Android haptics, open Tools → HCE → Toolset → Haptics and click "Add VIBRATE permission to project" — the Toolset writes a single <uses-permission> entry into your Assets/Plugins/Android/AndroidManifest.xml (creating the file if it doesn't exist).Economy
Multi-currency wallet with overflow protection and transaction logging.
Wallet Service
// Credit
wallet.Credit(CurrencyId.Coins, 500, "level_complete");
// Debit (returns false if insufficient)
if (wallet.TryDebit(CurrencyId.Gems, 10, "shop_purchase")) {
// Purchase succeeded
}
// Read balance
long coins = wallet.Get(CurrencyId.Coins);
// Listen for changes
wallet.BalanceChanged += (id, newBalance) => UpdateHud(id, newBalance);C#
Built-in Currencies
CurrencyId.Coins and CurrencyId.Gems are predefined. Create custom currencies with new CurrencyId("keys").
Overflow Protection
Balances are capped at long.MaxValue / 2 instead of crashing on overflow. Safe for long-term play sessions.
Transaction Log
Every credit/debit is recorded in a ring buffer (default 50 entries) with timestamp, currency, delta, and reason string. Use transactionLog.GetRecent(10) for analytics or debugging.
Coin Burst Animation
Spawn a stream of coins flying from a world position to your HUD:
var request = new CoinBurstRequest {
CoinCount = 15,
TotalReward = 100,
OriginWorld = transform.position,
HudPositionProvider = () => hudCoinIcon.position,
StaggerSeconds = 0.02f
};
coinBurstRunner.PlayAsync(request, onCompleted: () => Debug.Log("done"));C#
Shop & Skins
Item catalog with material and mesh skin payloads.
Setup
Create → HCE → Shop → CatalogCreate → HCE → Shop → Item. Set ID, price, currency, icon, and skin payload.Create → HCE → Shop → Material Skin Payload or Mesh Skin Payload.Add
SkinApplier to the target GameObject. It auto-applies skins when items are equipped.// Purchase
if (shopService.TryPurchase(item)) {
Debug.Log("Bought!");
}
// Equip
shopService.Equip(item); // Fires Equipped event → SkinApplier applies it
// Events
shopService.Purchased += (item) => ShowToast("Purchased!");
shopService.Equipped += (item) => RefreshUI();C#
CSV Import
Select a ShopCatalog, then Tools → HCE → Import Shop CSV:
# id, price, currency, englishName
blue_skin, 100, coins, Blue Skin
fire_sword, 50, gems, Fire SwordCSV
Skin Payload Types
| Type | What It Does |
|---|---|
MaterialSkinPayload | Swaps the first Renderer's sharedMaterial |
MeshSkinPayload | Swaps the first MeshFilter's sharedMesh |
In-App Purchases
Unified purchase flow with real and dummy store backends.
Product Setup
Create → HCE → IAP → CatalogCreate → HCE → IAP → Product. Set store ID (lowercase a-z0-9_), kind, and reward hook.Use
CoinsPurchaseReward for consumables or FlagPurchaseReward for non-consumables.Set IAP mode: Dummy (testing), Test (real SDK, test environment), or Production.
Purchase Flow
var result = await iapBridge.PurchaseAsync("com.game.1000coins");
if (result.Success) {
// Reward already granted via RewardHook
ShowToast("Thank you!");
}C#
Reward Hook Types
| Type | Use Case | Action |
|---|---|---|
CoinsPurchaseReward | Consumable (coins, gems) | Credits wallet |
FlagPurchaseReward | Non-consumable (no-ads, skin pack) | Sets PlayerPrefs flag |
Failure Reasons (PurchaseResult.Reason)
The Unity IAP backend pre-validates every purchase request before calling the store, so failures surface as a clean PurchaseResult { Success = false, Reason = "..." } instead of throwing. Show Reason in toasts/logs to diagnose live issues.
| Reason | Meaning | Common cause |
|---|---|---|
not_initialized | Backend hasn't finished InitializeAsync. | Buy tapped before init resolved — gate the button on IsInitialized. |
invalid_product_id | Empty or null product id passed in. | Caller bug, e.g. missing IapProductId on a shop entry. |
product_not_in_catalog | The id isn't in the controller's product list. | Product not registered in Play Console / App Store Connect for this package, or the id was misspelled. |
product_not_available | Store fetched the product but flagged it unavailable. | Product inactive on the store, region not supported, or test track config issue. |
purchase_threw: <message> | Synchronous exception from controller.InitiatePurchase. | Last-line guard against any future Unity Purchasing change. Inspect the wrapped message. |
UserCancelled · NetworkError · PaymentDeclined … | Forwarded from Unity Purchasing's PurchaseFailureReason. | Standard live-purchase failure modes — show a generic error toast. |
product_not_in_catalog guard prevents the deep InvalidCartItemException that Unity Purchasing v5 throws when an unregistered id reaches InitiatePurchase. Surface it as "Product unavailable" to the user and check Play Console / App Store Connect first.Dummy Backend
The dummy backend simulates purchases with configurable behavior:
- AlwaysSucceed: Returns success with dummy receipt
- AlwaysFail: Returns "simulated_failure"
- AlwaysCancel: Returns "user_cancelled"
Latency is configurable (default 250ms) to test loading spinners.
Ads
AdMob integration with rewarded, interstitial, and banner support.
Showing Ads
var adService = Services.Resolve<AdService>();
// Rewarded video
var result = await adService.ShowRewardedAsync(rewardedPlacement);
if (result.Completed) GrantReward();
// Interstitial
bool shown = await adService.ShowInterstitialAsync(interstitialPlacement);
// Banner
adService.LoadBanner(bannerPlacement);
adService.HideBanner(bannerPlacement);C#
RewardedResult
| Field | Meaning |
|---|---|
Completed | User watched the full video |
Skipped | User dismissed before completion |
Failed | Load or show error (check Reason) |
Mode Configuration
| Mode | Backend | Use When |
|---|---|---|
| Dummy | MockAdBackend | Development — no SDK needed |
| Test | AdMobBackend | Testing — uses Google's test ad unit IDs |
| Production | AdMobBackend | Release — uses your production ad unit IDs |
Production Setup
The
HCE_ADMOB define is auto-set when the SDK is detected.In
HCESettings → Ads, fill in all Android and iOS production ad unit IDs.The Toolset window will show green status when all IDs are configured.
RequestNonPersonalizedAdsOnly is true by default, adding "npa"="1" to all ad requests for EU consent compliance.Daily Rewards
Streak-based welcome gifts with ad-boosted claiming.
How It Works
Streak Logic
- Same day: No-op (already claimed)
- Next day: Streak increments
- Skipped days: Streak resets to 1 (unless grace days configured)
Default Schedule
| Day | Reward | Amount |
|---|---|---|
| 1 | Coins | 50 |
| 2 | Coins | 100 |
| 3 | Gems | 5 |
| 4 | Coins | 250 |
| 5 | Coins | 500 |
| 6 | Gems | 20 |
| 7 | Coins (Jackpot) | 1000 |
Ad-Boosted Claiming
// 2x reward via rewarded ad
if (service.TryClaimWithMultiplier(2, out var gift)) {
ShowCelebration(gift);
}C#
The WelcomeGiftPanel UI has built-in "x2 via Ad" button support. Wire an AdPlacement in settings and the panel handles the ad flow automatically.
Welcome Gift Configuration
| Setting | Default | Description |
|---|---|---|
Schedule | — | WelcomeGiftSchedule ScriptableObject |
LoopAfterLastDay | false | Re-grant last day's gift on day 8+ |
GraceDays | 0 | Missed days that don't break the streak |
UseServerTime | false | Anti-cheat: use server UTC time |
DoubleAdPlacement | — | AdPlacement for 2x via Ad button |
Tile States
The WelcomeGiftPanel renders each day as a tile with one of four states:
- Claimed: Dimmed (already collected)
- Today: Highlighted green (claimable now)
- Locked: Dark overlay (future day)
- Missed: Faded (grace days feature)
Reward Wheel
Weighted prize spinner with visual building and tick audio cues.
Setup
Create → HCE → Wheel → Slice Database. Define slices with icon, label, amount, and weight.Add
WheelSpinner to your wheel UI. Assign the database and the RectTransform to rotate.Call
Spin() and listen for SpinCompleted.wheelSpinner.Spin();
wheelSpinner.SpinCompleted += (result) => {
Debug.Log($"Won {result.Slice.Amount} coins!");
wallet.Credit(CurrencyId.Coins, result.Slice.Amount, "wheel_reward");
};C#
WheelSlice Fields
| Field | Description |
|---|---|
Icon | Sprite displayed on the wheel |
Label | LocalizedText name |
Amount | Reward amount |
Weight | Probability weight (higher = more likely) |
RewardId | Identifier for the reward type |
Spin Animation
The spinner performs _extraSpins full rotations (default 5) before landing on the selected slice, using InOutQuart easing over _spinDuration seconds (default 4s).
The WheelTickEmitter fires a Tick event for every slice boundary crossed — perfect for driving a click sound.
Weighted Selection
Uses prefix-sum binary search for O(log N) selection. Zero-weight slices are never selected. The inspector warns if total weight is 0 or slice count is outside 2–12.
Minigames
Chest loot drops and slot machine.
Chests
var result = chestService.TryOpen("rare_chest");
if (result.Success)
Debug.Log($"Got {result.Drop.Amount} {result.Drop.CurrencyId}!");C#
Each ChestTier has a key cost (debited from wallet), an icon, a tint color, and a weighted loot table of ChestRewardDrop entries. Drops can grant currency or set item flags.
Slot Machine
if (slotMachine.TrySpin(out var result)) {
if (result.HitJackpot)
Debug.Log($"JACKPOT! Won {result.RewardAmount}!");
}C#
Configure reels, symbols (with weights), and payout rules. The default setup: 3 reels, symbols Cherry/Lemon/Bell/Bar/Seven with payouts from 30 to 2500.
| Config Field | Default | Description |
|---|---|---|
ReelCount | 3 | Number of spinning reels |
SpinDurationSeconds | 2.5 | Animation duration |
StopStaggerSeconds | 0.3 | Delay between reel stops |
SpinCost | 10 | Currency cost per spin |
Feature Gating
Lock features behind level, currency, cooldown, or flag conditions.
UnlockGate Component
Add an UnlockGate to any Button. Assign an UnlockCondition asset. The gate automatically disables the button, shows a lock reason, and toggles a lock overlay.
Condition Types
| Type | Unlocks When | Lock Message Example |
|---|---|---|
LevelUnlockCondition | Player level ≥ required | "Unlocks at level 4" |
CurrencyUnlockCondition | Currency balance ≥ required | "Need 100 coins (have 42)" |
CooldownUnlockCondition | Time elapsed since last use | "Ready in 14:32" |
FlagUnlockCondition | PlayerPrefs flag is set (or NOT set) | "Locked" (customizable) |
CompositeUnlockCondition | All children (AND) or Any child (OR) | First locked child's message |
Usage
// Listen for gate status changes
unlockGate.StatusChanged += (status) => {
if (status.Unlocked)
Debug.Log("Feature unlocked!");
else
Debug.Log(status.LockReason);
};C#
CompositeUnlockCondition to combine conditions. Example: "Level 5 AND 100 coins AND 24h cooldown" using All mode.Popups & Toasts
Modal popup stack and FIFO toast notifications.
Popups
// Show a popup
popupService.Open(new PopupRequest(myPopupPrefab, dimBackdrop: true, payload: someData));
// Close from inside the popup
public class MyPopup : PopupView {
public override void OnOpened(object payload) { /* setup UI */ }
public void OnCloseClicked() => Close();
}C#
Popups stack. The backdrop uses reference counting — it stays visible until all popups are closed. Set IgnoreTimeScale = true for pause-proof animations.
Toasts
toastService.Show(new ToastRequest("Level complete!", ToastKind.Success, 2f));
toastService.Show(new ToastRequest("Not enough coins", ToastKind.Warning));C#
Toast Kinds
| Kind | Visual |
|---|---|
Info | Default neutral style |
Success | Green accent |
Warning | Yellow accent |
Error | Red accent |
Toasts queue in FIFO order with 0.1s pause between each. Duration defaults to 2 seconds.
UI Helpers
Ready-made components for common UI patterns.
| Component | What It Does |
|---|---|
NumberTicker | Animates a TMP label from one number to another with OutCubic easing (0.6s default) |
PressFeedback | Scales a button down to 94% on press, bounces back with OutBack on release (0.06s) |
SafeAreaFitter | Adjusts RectTransform anchors to match Screen.safeArea, handling notches and rounded corners |
ModalBlocker | Full-screen transparent raycast target that swallows all pointer events |
RewardButton | Plays an Animator dismiss animation then self-destructs |
SceneFadeTrigger | Inspector-wired button that loads a scene via SceneFadeService |
WalletHud | Auto-updates a TMP label when the bound currency balance changes |
// NumberTicker usage
numberTicker.SetImmediate(0);
numberTicker.TweenTo(1500); // Animates 0 → 1500 over 0.6sC#
Toon Shaders
Cel-shaded rendering for BiRP, URP, and HDRP.
Shader Variants
| Shader | Pipeline | Feature |
|---|---|---|
HCE/Toon/BiRP-Lit | Built-in RP | Banded toon lighting + rim highlight |
HCE/Toon/BiRP-Outline | Built-in RP | Inverted hull outline pass |
HCE/Toon/BiRP-Transparent | Built-in RP | Alpha blended toon (no rim) |
HCE/Toon/URP-Lit | Universal RP | Self-contained toon + rim |
HCE/Toon/URP-Outline | Universal RP | Clip-space outline pass |
HCE/Toon/URP-Transparent | Universal RP | Alpha blended toon |
HCE/Toon/HDRP-Lit | HD RP | Minimal toon (linear blend) |
Material Properties
| Property | Range | Default | Description |
|---|---|---|---|
_BaseMap | — | white | Albedo texture |
_BaseColor | — | white | Tint color |
_ShadowTint | — | (0.4, 0.4, 0.55) | Shadow color (blue-ish) |
_RimColor | — | white | Rim highlight color |
_RimPower | 0.1–16 | 4 | Rim falloff exponent |
_BandCount | 1–8 | 3 | Number of discrete light bands |
_BandSmoothness | 0–1 | 0.15 | Edge softness between bands |
_ToonFloor | 0–1 | 0.25 | Minimum brightness |
_ToonCeiling | 0–1 | 1.0 | Maximum brightness |
_OutlineColor | — | black | Outline color (outline shader only) |
_OutlineWidthPixels | 0–16 | 2.0 | Screen-space outline width in pixels |
Pipeline Detection
// Auto-select the right shader for the active pipeline
string shaderName = RenderPipelineUtil.GetPreferredToonShader();
var shader = Shader.Find(shaderName);C#
Analytics
Pluggable event bus with multiple sink backends.
var bus = Services.Resolve<AnalyticsBus>();
bus.Emit("level_complete", new Dictionary<string, object> {
{ "level", 5 },
{ "score", 1200 },
{ "time_seconds", 42.5 }
});C#
Available Sinks
| Sink | Requires | Output |
|---|---|---|
DebugLogSink | Nothing | Unity Console: [HCE.Analytics] event_name { key=value } |
UnityAnalyticsSink | com.unity.services.analytics | Unity Services dashboard |
FirebaseAnalyticsSink | Firebase SDK | Firebase console |
Sinks are isolated — if one throws, others still receive the event. Configure in HCESettings → Analytics.
Notifications
Schedule local push notifications on mobile.
var svc = NotificationService.CreateFromSettings();
await svc.InitializeAsync();
await svc.RequestPermissionAsync();
// Schedule a notification 4 hours from now
string id = svc.Schedule("Come back!", "Your energy is full.", TimeSpan.FromHours(4));
// Cancel it
svc.Cancel(id);
svc.CancelAll();C#
Platform Behavior
| Platform | Backend | Permission |
|---|---|---|
| Android 13+ | UnityMobileNotificationBackend | POST_NOTIFICATIONS runtime permission |
| Android <13 | UnityMobileNotificationBackend | No permission needed |
| iOS | UnityMobileNotificationBackend | UNUserNotificationCenter authorization |
| Editor | DummyNotificationBackend | Logs to console |
com.unity.mobile.notifications package. The HCE_MOBILE_NOTIFICATIONS define is auto-set when detected.Rate Us
Gated review prompts with platform-native dialogs.
// Register each app launch
rateUsService.RegisterSession();
// Gated prompt (checks all conditions first)
var result = await rateUsService.MaybeRequestReviewAsync();
// Force prompt (for explicit "Rate Us" button in settings)
var result = await rateUsService.ForceRequestReviewAsync();C#
Gate Conditions
| Gate | Default | Description |
|---|---|---|
| Min sessions | 3 | Minimum app launches before first prompt |
| Min seconds since first launch | 600 (10 min) | Minimum time since first app launch |
| Min days between asks | 30 | Cooldown between prompts |
| Max lifetime asks | 3 | Apple caps at 3 per 365 days |
| Skip if rated | true | Don't prompt again after user rated |
Soft Prompt
Enable UseSoftPrompt to show a custom dialog ("Enjoying the game?") before the native review UI. If the user declines, the attempt is counted but the native dialog is skipped.
Production Setup — Native Popup Wiring
HCE ships a fully self-contained wiring for the Android native popup — no project-level Gradle edits required. iOS needs nothing at all.
HCE itself ships zero third-party content. To enable the native popup, open
Tools → HCE → Toolset → Rate Us and click "Add Play Review dep to mainTemplate.gradle". The Toolset writes the line implementation 'com.google.android.play:review:2.0.1' into your project's Assets/Plugins/Android/mainTemplate.gradle (creating the file if it doesn't exist). At YOUR build time, Gradle resolves the artifact from Google's Maven repository and links it into your APK. Without this dep, the backend silently opens the Play Store listing instead.SKStoreReviewController ships with iOS StoreKit. The included Plugins/iOS/HCERateUs.mm calls requestReviewInScene: on iOS 14+ and requestReview on 10.3+. Set RateUs → IOSAppId for the deep-link fallback when the soft cap kicks in.Sideloaded debug APKs and direct downloads will not display the Android native popup — Google requires the app to be installed via the Play Store (Internal/Closed/Open testing tracks all qualify). On iOS, the native popup is rate-limited to 3 prompts per 365 days per app and can no-op silently.
HCE_PLAY_REVIEW scripting define is optional (build-time hint only; the runtime backend uses reflection).MaybeRequestReviewAsync with no visible UI — that's normal, not a bug. Don't show "thanks for rating!" toasts pre-emptively.Editor Tools
Setup wizard, toolset window, custom inspectors, and CSV importers.
Tools Menu
| Menu Path | Purpose |
|---|---|
Tools → HCE → Toolset | Main editor window with 11 tabs for all modules |
Tools → HCE → Setup Wizard | First-run project setup |
Tools → HCE → Create Default Config Assets | Generate all default configs |
Tools → HCE → Import SoundBank CSV | Bulk import audio entries |
Tools → HCE → Import Shop CSV | Bulk import shop items |
Toolset Window
The main HCE editor window (11 tabs) shows the health status of every module:
- ● Green: Module ready
- ● Yellow: Warning (e.g., SDK missing but not required)
- ● Red: Action needed (e.g., production IDs missing)
Tabs: Overview, Ads, Analytics, IAP, Audio, Haptics, Notifications, Rate Us, Welcome Gifts, Minigames, General.
Custom Inspectors
| Inspector | Asset Type | Extra Feature |
|---|---|---|
| SoundBankInspector | SoundBank | Reorderable drag list |
| WheelSliceDatabaseInspector | WheelSliceDatabase | Total weight display + warnings |
| ShopCatalogInspector | ShopCatalog | Duplicate ID detection + auto-fix |
| IAPCatalogInspector | IAPCatalog | Product ID format validation |
| HapticPatternInspector | HapticPattern | Visual waveform preview |
Property Drawers
Smart dropdown pickers are provided for SoundId, CurrencyId, ShopItemId, and SceneReference fields. They auto-scan all relevant assets in the project.
Build Validator
Runs automatically before every build (IPreprocessBuildWithReport). Warns if a SoundBank or ShopCatalog is missing — never blocks the build.
Cheat Console
Debug console with hotkeys and 3-finger mobile gesture.
HCE_CHEATS is defined. It compiles to empty stubs in release builds.Activation
- Keyboard: Press ` (backtick) to toggle the console
- Mobile: 3-finger long-press for 1+ second
Built-in Cheats
| Cheat | Hotkey | Action |
|---|---|---|
| Grant Coins | F1 | Credit 1000 coins (configurable) |
| Wipe Save | F2 | Delete all persisted data |
| Reload Scene | F3 | Reload the active scene |
CheatBindings Config
Create via Create → HCE → Cheats → Bindings. Customize hotkeys and grant amounts in the Inspector.
Scripting Defines
Feature flags for optional SDK integrations.
| Define | Required Package | What It Enables | Auto-Set |
|---|---|---|---|
HCE_ADMOB | Google Mobile Ads SDK | AdMob backend | Yes (asmdef) |
HCE_UNITY_ANALYTICS | com.unity.services.analytics | Unity Analytics sink | Yes (asmdef) |
HCE_FIREBASE | Firebase SDK | Firebase Analytics sink | No (manual) |
HCE_MOBILE_NOTIFICATIONS | com.unity.mobile.notifications | OS push notifications | Yes (asmdef) |
HCE_CHEATS | None | Debug cheat console | Setup Wizard |
HCE_LOG_VERBOSE | None | Detailed HCE log output | No (manual) |
asmdef version defines when you install the corresponding package. No manual setup needed.Troubleshooting
Common issues and their solutions.
"HCESettings asset not found" warning at runtime
The singleton asset must exist at Assets/HyperCasualEssentials/Resources/HCE/HCESettings.asset. Run Tools → HCE → Setup Wizard to create it, or verify the path hasn't been moved.
Ads always show as mock/dummy
Check three things: (1) Google Mobile Ads SDK is installed, (2) HCE_ADMOB define is present in Player Settings, (3) HCESettings → Ads → Mode is set to Test or Production.
IAP purchases fail with "not_initialized"
Ensure await iapBridge.InitializeAsync(catalog) is called and awaited before any purchase. Check Unity Console for initialization errors.
Haptics don't work on device
Verify: (1) HCESettings → Haptics → Mode is Production, (2) Platform toggles (EnableOnAndroid/EnableOnIOS) are on, (3) you've clicked Tools → HCE → Toolset → Haptics → "Add VIBRATE permission to project" so your Android manifest declares the permission.
Daily reward resets unexpectedly
The streak tracker uses UTC dates. If you're testing across midnight UTC, the streak will advance. For forgiving behavior, increase GraceDays in WelcomeGiftsSettings. Enable UseServerTime to prevent clock manipulation.
Toon shaders are pink / not rendering
Make sure you're using the shader that matches your render pipeline. Use RenderPipelineUtil.GetPreferredToonShader() to auto-detect, or manually assign: BiRP-Lit for Built-in, URP-Lit for Universal, HDRP-Lit for HD.
Build validator warns about missing SoundBank
Run Tools → HCE → Create Default Config Assets to generate all default configs. Then assign your SoundBank in HCESettings → Audio → DefaultSoundBank.
Notifications don't appear on device
Ensure com.unity.mobile.notifications is installed, HCE_MOBILE_NOTIFICATIONS define is set, Mode is Production, and RequestPermissionAsync() was called and returned true.
Threading Rules
UnityEngine.* calls, PlayerPrefs, MonoBehaviour callbacks, Mathf.Background safe:
System.Math, CultureInfo.InvariantCulture, pure C# collections.Use
MonoHost.Post(action) to marshal work back to the main thread from native callbacks.
Support
Need help? We're here for you.
Get in Touch
If you run into any issues, have feature requests, or need help integrating HyperCasual Essentials into your project, don't hesitate to reach out.
✉ ragendom@gmail.comWe typically respond within 24–48 hours.
- Check the Troubleshooting section
- Verify your Scripting Defines are set
- Open
Tools → HCE → Toolsetto check module status - Include your Unity version and target platform
- Unity version & render pipeline (BiRP/URP/HDRP)
- HCE version (currently 1.0.1)
- Target platform (Android/iOS/both)
- Console error logs or screenshots
HyperCasual Essentials v1.0.1 · Built for Unity 2021.3+
Support: ragendom@gmail.com