From 9be31b16455f57b9a3011d35d44d38f2b55eade4 Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 20:05:06 -0700 Subject: [PATCH 01/33] Add tower Sell action with refund + coin VFX/SFX Owner-validated sell RPC refunds SellRefundPercent of invested gold (Wall refunds 100% while un-upgraded), despawns the tower, and broadcasts a coin-burst VFX + rustle SFX. Refunds do not count as per-wave income. Investment/upgrade tracking added as the seam for the future upgrade system. Co-Authored-By: Claude Opus 4.8 --- .../Scripts/Gameplay/PlayerGoldManager.cs | 16 ++- .../Scripts/Gameplay/TowerInstance.cs | 107 ++++++++++++++++++ .../Scripts/Gameplay/TowerPlacementManager.cs | 21 ++++ .../Scripts/Towers/TowerDefinition.cs | 16 +++ Assets/_Project/Scripts/UI/HUDController.cs | 29 +++-- Assets/_Project/Scripts/VFX/CoinBurstVfx.cs | 101 +++++++++++++++++ .../_Project/Scripts/VFX/SellEffectSpawner.cs | 83 ++++++++++++++ 7 files changed, 361 insertions(+), 12 deletions(-) create mode 100644 Assets/_Project/Scripts/VFX/CoinBurstVfx.cs create mode 100644 Assets/_Project/Scripts/VFX/SellEffectSpawner.cs diff --git a/Assets/_Project/Scripts/Gameplay/PlayerGoldManager.cs b/Assets/_Project/Scripts/Gameplay/PlayerGoldManager.cs index 1cb3170..4cbd3a4 100644 --- a/Assets/_Project/Scripts/Gameplay/PlayerGoldManager.cs +++ b/Assets/_Project/Scripts/Gameplay/PlayerGoldManager.cs @@ -143,11 +143,17 @@ namespace TD.Gameplay /// /// Server-side entry point for awarding gold (wave clear, enemy kill). /// Direct call — not Rpc-wrapped — because awards always originate - /// from server-authoritative game events. Also increments - /// so the HUD's per-wave counter reflects - /// it; spending does not decrement that counter (it tracks earnings, not balance). + /// from server-authoritative game events. When + /// is true (the default) it also increments so the + /// HUD's per-wave counter reflects it; spending does not decrement that counter (it + /// tracks earnings, not balance). /// - public void AwardGold(int amount) + /// + /// Pass false for gold returned to the player that isn't income — e.g. a tower-sell + /// refund. The player's balance still rises, but the per-wave "earned" counter does not, + /// so refunds don't inflate round-income stats. + /// + public void AwardGold(int amount, bool countAsEarned = true) { if (!IsServer) { @@ -158,7 +164,7 @@ namespace TD.Gameplay if (amount <= 0) return; currentGold.Value += amount; - goldEarnedThisWave.Value += amount; + if (countAsEarned) goldEarnedThisWave.Value += amount; } /// diff --git a/Assets/_Project/Scripts/Gameplay/TowerInstance.cs b/Assets/_Project/Scripts/Gameplay/TowerInstance.cs index 519ff04..1b01a4a 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerInstance.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerInstance.cs @@ -105,6 +105,24 @@ namespace TD.Gameplay readPerm: NetworkVariableReadPermission.Everyone, writePerm: NetworkVariableWritePermission.Server); + // Total gold sunk into this tower: its placement cost plus any gold later spent + // upgrading it. Set on the server at spawn (= placement cost) and grown by the + // (future) upgrade system via ServerAddUpgradeInvestment. Replicated so the HUD's + // Sell button can preview the exact refund without a server round-trip. + private readonly NetworkVariable goldInvested = + new NetworkVariable( + 0, + readPerm: NetworkVariableReadPermission.Everyone, + writePerm: NetworkVariableWritePermission.Server); + + // Number of upgrades applied to this tower. 0 = never upgraded. Drives the Wall's + // "full refund only while un-upgraded" rule and will back tier display later. + private readonly NetworkVariable upgradeCount = + new NetworkVariable( + 0, + readPerm: NetworkVariableReadPermission.Everyone, + writePerm: NetworkVariableWritePermission.Server); + // ----- Local resolved state ------------------------------------------- // Resolved on every client in OnNetworkSpawn from definitionTypeId via the catalog. @@ -144,6 +162,12 @@ namespace TD.Gameplay /// The footprint anchor tile (SW corner, world-tile coords). public Vector2Int AnchorTile => anchorTile.Value; + /// Total gold sunk into this tower so far (placement + upgrades). + public int GoldInvested => goldInvested.Value; + + /// How many upgrades have been applied to this tower (0 = never upgraded). + public int UpgradeCount => upgradeCount.Value; + /// World-unit height the post-construction drop animation falls from. public float DropHeight => dropHeight; @@ -254,6 +278,11 @@ namespace TD.Gameplay anchorTile.Value = pendingAnchor; ownerSlot.Value = pendingOwner; + // Seed invested gold with the placement cost — the same amount + // TowerPlacementManager deducted to build this tower. The upgrade system + // grows this later via ServerAddUpgradeInvestment. + goldInvested.Value = pendingDefinition != null ? pendingDefinition.GoldCost : 0; + // Clear the pending data — it's now committed to NetworkVariables. hasPendingInit = false; } @@ -345,6 +374,84 @@ namespace TD.Gameplay // Re-tint on every client (and the server) when the replicated paint color changes. private void HandlePaintColorChanged(PaintColor previous, PaintColor current) => ApplyTint(); + // ----- Selling -------------------------------------------------------- + + // Server-only guard: a fast double-click could deliver two sell RPCs before the + // despawn propagates. Mirrors BuildSiteVisual.serverCancelled. + private bool serverSold; + + /// + /// Gold returned if this tower is sold right now. Single source of truth for both + /// the server (which awards it) and the HUD (which labels the Sell button). By + /// default this is of everything + /// invested; a tower flagged + /// (the Wall) returns the full amount while it has never been upgraded. + /// + public int ComputeSellRefund() + { + int invested = goldInvested.Value; + if (resolvedDefinition == null) + return Mathf.RoundToInt(invested * 0.75f); + + if (resolvedDefinition.FullRefundIfUnupgraded && upgradeCount.Value == 0) + return invested; + + return Mathf.RoundToInt(invested * resolvedDefinition.SellRefundPercent); + } + + /// + /// Server-only: records gold spent upgrading this tower (so a later sell refunds a + /// share of it) and marks the tower upgraded — which forfeits any + /// full-refund-while-unupgraded rule. The upgrade system calls this when it lands. + /// + public void ServerAddUpgradeInvestment(int cost) + { + if (!IsServer) return; + if (cost > 0) goldInvested.Value += cost; + upgradeCount.Value += 1; + } + + /// + /// Client → server request to sell this tower. Accepted only from the tower's owner + /// (same ownership rule as placement and paint). The server refunds gold, broadcasts + /// the sell VFX/SFX from a persistent object, then despawns the tower — + /// restores the footprint's grid state and clears + /// selection on every peer. + /// + [Rpc(SendTo.Server)] + public void RequestSellServerRpc(RpcParams rpcParams = default) + { + if (!IsServer) return; + if (serverSold) return; // idempotent guard against a double-click + + ulong senderClientId = rpcParams.Receive.SenderClientId; + PlayerSlot senderSlot = PlayerMatchState.SlotForClient(senderClientId); + if (senderSlot == PlayerSlot.None || senderSlot != ownerSlot.Value) + { + Debug.Log($"[TowerInstance] Sell rejected: client {senderClientId} " + + $"({senderSlot}) does not own tower owned by {ownerSlot.Value}."); + return; + } + + serverSold = true; + + int refund = ComputeSellRefund(); + var goldManager = PlayerGoldManager.GetForClient(senderClientId); + if (goldManager != null && refund > 0) + // countAsEarned: false — a sell refund returns spent gold, it is not round + // income, so it must not inflate the per-wave "earned" counter. + goldManager.AwardGold(refund, countAsEarned: false); + + // Broadcast VFX/SFX from the persistent placement manager, capturing the world + // position NOW — this NetworkObject despawns below, so it can't carry the RPC to + // remote peers itself (same reason WaveManager routes kill/leak popups). + var pm = TowerPlacementManager.Instance; + if (pm != null) pm.BroadcastSellEffect(transform.position); + + if (NetworkObject != null && NetworkObject.IsSpawned) + NetworkObject.Despawn(destroy: true); + } + // ----- IMinimapEntity ------------------------------------------------- // // Towers are static, so WorldPosition is cheap (no movement to track). Color reflects diff --git a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs index 7c4662d..92b349d 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs @@ -5,6 +5,7 @@ using UnityEngine; using TD.Core; using TD.Levels; using TD.Towers; +using TD.VFX; namespace TD.Gameplay { @@ -350,6 +351,26 @@ namespace TD.Gameplay $"client {req.SenderClientId} ({placingSlot}) at anchor {req.Anchor}."); } + // ----- Sell effects (persistent broadcaster) ---------------------- + + /// + /// Server-only: tells every peer to play the tower-sold VFX/SFX at + /// . Called by as it sells, + /// because the tower's own NetworkObject despawns the same frame — a persistent + /// object must carry the broadcast so it isn't dropped. + /// + public void BroadcastSellEffect(Vector3 worldPos) + { + if (!IsServer) return; + PlaySellEffectRpc(worldPos); + } + + [Rpc(SendTo.Everyone)] + private void PlaySellEffectRpc(Vector3 worldPos) + { + SellEffectSpawner.Instance?.Play(worldPos); + } + // ----- Server-side commit hooks called by Builder ------------------ /// diff --git a/Assets/_Project/Scripts/Towers/TowerDefinition.cs b/Assets/_Project/Scripts/Towers/TowerDefinition.cs index 3ce1632..8163490 100644 --- a/Assets/_Project/Scripts/Towers/TowerDefinition.cs +++ b/Assets/_Project/Scripts/Towers/TowerDefinition.cs @@ -47,6 +47,22 @@ namespace TD.Towers "successful server-side placement validation.")] public int GoldCost; + // ------------------------------------------------------------------- + // Selling + // ------------------------------------------------------------------- + + [Header("Selling")] + [Tooltip("Portion of the gold INVESTED in this tower (placement cost plus any gold " + + "later spent upgrading it) that is refunded when it is sold, as a 0–1 factor. " + + "Default 0.75 = 75%.")] + [Range(0f, 1f)] + public float SellRefundPercent = 0.75f; + + [Tooltip("When true, this tower refunds 100% of its invested gold while it has never " + + "been upgraded (upgradeCount == 0); once upgraded it falls back to " + + "SellRefundPercent. Set on the Wall so a fresh wall can be re-mazed for free.")] + public bool FullRefundIfUnupgraded = false; + // ------------------------------------------------------------------- // Construction // ------------------------------------------------------------------- diff --git a/Assets/_Project/Scripts/UI/HUDController.cs b/Assets/_Project/Scripts/UI/HUDController.cs index 96f50ec..f581be9 100644 --- a/Assets/_Project/Scripts/UI/HUDController.cs +++ b/Assets/_Project/Scripts/UI/HUDController.cs @@ -1178,19 +1178,30 @@ namespace TD.UI return btn; } + // Sell action for a completed tower. Refund is computed on the TowerInstance (single + // source of truth shared with the server) so the badge shows exactly what the player + // gets back. Hotkey is Key.None: the bottom-right slot's letter (B) is already the + // global buff-menu toggle — see CreateBuffMenuButton — so binding it here would fire + // both. The button stays click-only. private VisualElement CreateSellButton(TowerInstance tower, Key hotkey) { - int sellValue = tower.Definition != null - ? Mathf.RoundToInt(tower.Definition.GoldCost * 0.7f) - : 0; + // Only the tower's owner can sell it (the server enforces this too). A non-owner + // may have this tower view-selected — show the slot disabled with no refund badge + // so the action reads as unavailable rather than misleading. + bool ownedByLocal = tower != null + && PlayerMatchState.Local != null + && tower.Owner == PlayerMatchState.Local.Slot; + + int sellValue = ownedByLocal ? tower.ComputeSellRefund() : 0; var btn = CreateActionButton( costText: sellValue > 0 ? $"+{sellValue}g" : "", - hotkey: hotkey, + hotkey: Key.None, onClick: () => { - /* TODO: sell flow */ + if (tower != null) + tower.RequestSellServerRpc(); }); - btn.SetEnabled(false); + btn.SetEnabled(ownedByLocal); return btn; } @@ -1437,7 +1448,11 @@ namespace TD.UI ttStats.text = "(stats pending)"; } - int sellValue = Mathf.RoundToInt(def.GoldCost * 0.7f); + // Sell preview for a freshly placed (un-upgraded) tower: mirrors + // TowerInstance.ComputeSellRefund for invested == GoldCost, upgradeCount == 0. + int sellValue = def.FullRefundIfUnupgraded + ? def.GoldCost + : Mathf.RoundToInt(def.GoldCost * def.SellRefundPercent); ttCost.text = $"Cost: {def.GoldCost}g · Sell: {sellValue}g"; } diff --git a/Assets/_Project/Scripts/VFX/CoinBurstVfx.cs b/Assets/_Project/Scripts/VFX/CoinBurstVfx.cs new file mode 100644 index 0000000..e9d71eb --- /dev/null +++ b/Assets/_Project/Scripts/VFX/CoinBurstVfx.cs @@ -0,0 +1,101 @@ +// Assets/_Project/Scripts/VFX/CoinBurstVfx.cs +using UnityEngine; + +namespace TD.VFX +{ + /// + /// Self-contained, code-configured gold-coin burst used as the zero-art placeholder for the + /// tower-sell effect. Configures its own for a short radial + /// spray of gold specks thrown up in random arcs under gravity, then destroys itself. + /// + /// + /// Instantiated at runtime by when no authored VFX prefab is + /// assigned. It can also be dropped on a prefab in the editor and tuned. Replace with an + /// authored particle / VFX-graph prefab (assigned on the spawner) when art is ready — nothing + /// else needs to change. + /// + [RequireComponent(typeof(ParticleSystem))] + public class CoinBurstVfx : MonoBehaviour + { + [Tooltip("How many coin specks to throw.")] + [SerializeField] private int coinCount = 14; + + [Tooltip("Longest a speck lives (seconds). The whole effect self-destructs shortly after.")] + [SerializeField] private float lifetime = 0.6f; + + [Tooltip("Gold tint applied to the specks.")] + [SerializeField] private Color coinColor = new Color(1f, 0.84f, 0.2f, 1f); + + private void Awake() + { + var ps = GetComponent(); + if (ps == null) ps = gameObject.AddComponent(); + Configure(ps); + } + + private void Configure(ParticleSystem ps) + { + // Reconfiguring modules requires the system to be stopped first. + ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); + + var main = ps.main; + main.duration = 0.1f; + main.loop = false; + main.playOnAwake = false; + main.startLifetime = new ParticleSystem.MinMaxCurve(lifetime * 0.6f, lifetime); + main.startSpeed = new ParticleSystem.MinMaxCurve(2.5f, 5f); + main.startSize = new ParticleSystem.MinMaxCurve(0.07f, 0.16f); + main.startRotation = new ParticleSystem.MinMaxCurve(0f, Mathf.PI * 2f); + main.startColor = coinColor; + main.gravityModifier = 2.5f; // arc up then fall back down quickly + main.simulationSpace = ParticleSystemSimulationSpace.World; + main.maxParticles = 64; + main.stopAction = ParticleSystemStopAction.None; + + var emission = ps.emission; + emission.enabled = true; + emission.rateOverTime = 0f; // burst only, no continuous stream + emission.SetBursts(new[] { new ParticleSystem.Burst(0f, (short)coinCount) }); + + // Hemisphere pointing up → specks spray outward and upward in random directions. + var shape = ps.shape; + shape.enabled = true; + shape.shapeType = ParticleSystemShapeType.Hemisphere; + shape.radius = 0.12f; + + // Fade the specks out over the back half of their life so they "decay quickly". + var col = ps.colorOverLifetime; + col.enabled = true; + var grad = new Gradient(); + grad.SetKeys( + new[] { new GradientColorKey(coinColor, 0f), new GradientColorKey(coinColor, 1f) }, + new[] + { + new GradientAlphaKey(1f, 0f), + new GradientAlphaKey(1f, 0.55f), + new GradientAlphaKey(0f, 1f), + }); + col.color = new ParticleSystem.MinMaxGradient(grad); + + // Give the specks a visible, transparent-capable material even with no assigned art. + var renderer = GetComponent(); + if (renderer != null) + { + renderer.renderMode = ParticleSystemRenderMode.Billboard; + if (renderer.sharedMaterial == null) + { + Shader shader = Shader.Find("Universal Render Pipeline/Particles/Unlit") + ?? Shader.Find("Sprites/Default") + ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended Premultiply"); + if (shader != null) + renderer.material = new Material(shader) { color = coinColor }; + } + } + + ps.Play(); + + // Tear down after the last speck has died (plus a small margin). + Destroy(gameObject, lifetime + 0.25f); + } + } +} diff --git a/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs b/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs new file mode 100644 index 0000000..0b67fc3 --- /dev/null +++ b/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs @@ -0,0 +1,83 @@ +// Assets/_Project/Scripts/VFX/SellEffectSpawner.cs +using UnityEngine; +using TD.Audio; + +namespace TD.VFX +{ + /// + /// Scene singleton that plays the "tower sold" feedback — a burst of gold coins plus a + /// coin-rustle sound — at a world position. Mirrors : + /// visual-only, plain MonoBehaviour, invoked on every peer via a ClientRpc so all + /// players see and hear a sale locally. + /// + /// + /// Who calls this: + /// routes a ClientRpc here when a tower is sold. + /// + /// Inspector setup: drop this on a SellEffectSpawner GameObject in each Match + /// scene. The VFX prefab is OPTIONAL — leave it empty to use the built-in + /// placeholder, or assign an authored particle/VFX-graph prefab. + /// Assign the coin-rustle clip on . + /// + public class SellEffectSpawner : MonoBehaviour + { + // ----- Singleton -------------------------------------------------- + + public static SellEffectSpawner Instance { get; private set; } + + // ----- Inspector -------------------------------------------------- + + [Tooltip("Optional authored VFX prefab spawned at the sale position. Leave empty to " + + "fall back to the built-in code-generated CoinBurstVfx placeholder.")] + [SerializeField] private GameObject coinBurstPrefab; + + [Tooltip("Coin-rustle sound played (2D, via AudioManager) when a tower is sold.")] + [SerializeField] private SoundConfig sellSound; + + [Tooltip("Vertical offset above the sale position where the coin burst originates, so " + + "it reads as coming from the tower body rather than the ground.")] + [SerializeField] private float verticalOffset = 0.75f; + + // ----- Lifecycle -------------------------------------------------- + + private void Awake() + { + if (Instance != null && Instance != this) + { + Debug.LogWarning("[SellEffectSpawner] Duplicate instance detected. " + + "Only one should exist per scene."); + return; + } + Instance = this; + } + + private void OnDestroy() + { + if (Instance == this) Instance = null; + } + + // ----- Public API ------------------------------------------------- + + /// Plays the coin burst + rustle sound at . + public void Play(Vector3 worldPos) + { + Vector3 spawnPos = worldPos + Vector3.up * verticalOffset; + + if (coinBurstPrefab != null) + { + Instantiate(coinBurstPrefab, spawnPos, Quaternion.identity); + } + else + { + // Zero-art fallback: a self-configuring, self-destroying particle burst. + var go = new GameObject("CoinBurst"); + go.transform.position = spawnPos; + go.AddComponent(); + } + + if (sellSound.clip != null) + AudioManager.Instance?.Play(sellSound.clip, AudioCategory.UI, + sellSound.RandomPitch(), sellSound.volume); + } + } +} From 86bc916c4936d8cbd463fab842cda3629967cc4a Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 20:22:00 -0700 Subject: [PATCH 02/33] Fix NGO RequireOwnership deprecation warnings; add VFX script metas Replace deprecated [Rpc(..., RequireOwnership = true)] with InvokePermission = RpcInvokePermission.Owner on the owner-submitted draft/buff RPCs (PlayerDraft, PlayerBuffManager), matching the pattern already used elsewhere. Also commits the .meta files Unity generated for the new sell-VFX scripts so their GUIDs are stable across machines. Co-Authored-By: Claude Opus 4.8 --- Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs | 4 ++-- Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs | 2 +- Assets/_Project/Scripts/VFX/CoinBurstVfx.cs.meta | 2 ++ Assets/_Project/Scripts/VFX/SellEffectSpawner.cs.meta | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 Assets/_Project/Scripts/VFX/CoinBurstVfx.cs.meta create mode 100644 Assets/_Project/Scripts/VFX/SellEffectSpawner.cs.meta diff --git a/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs b/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs index 3fd7350..41a7c04 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/PlayerDraft.cs @@ -137,7 +137,7 @@ namespace TD.Gameplay.Draft // ----- Owner → server RPCs ---------------------------------------- /// Owning client: pick one of the offered options by id. - [Rpc(SendTo.Server, RequireOwnership = true)] + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] public void RequestPickRpc(int optionId) { ServerResolve(optionId); @@ -148,7 +148,7 @@ namespace TD.Gameplay.Draft /// afford it or already has an unresolved draft (resolve the current one first so a /// free pick is never silently overwritten). /// - [Rpc(SendTo.Server, RequireOwnership = true)] + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] public void RequestBuyRerollRpc() { if (HasActiveDraft) return; // resolve the pending draft before buying another diff --git a/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs b/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs index 506791e..52efbdc 100644 --- a/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs +++ b/Assets/_Project/Scripts/Gameplay/PlayerBuffManager.cs @@ -146,7 +146,7 @@ namespace TD.Gameplay /// a random buff from the category at . /// The server validates gold and adds the buff if the purchase succeeds. /// - [Rpc(SendTo.Server, RequireOwnership = true)] + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] public void RequestPurchaseBuffRpc(int categoryIndex) { if (categories == null || categoryIndex < 0 || categoryIndex >= categories.Length) diff --git a/Assets/_Project/Scripts/VFX/CoinBurstVfx.cs.meta b/Assets/_Project/Scripts/VFX/CoinBurstVfx.cs.meta new file mode 100644 index 0000000..58bc699 --- /dev/null +++ b/Assets/_Project/Scripts/VFX/CoinBurstVfx.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bdff685029f23004796671150c7cf39b \ No newline at end of file diff --git a/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs.meta b/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs.meta new file mode 100644 index 0000000..7ae5f2a --- /dev/null +++ b/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e2708c6bac8136f45b48c899d3d40630 \ No newline at end of file From 1794f65b19d7a9df31683b473e8e6427b65699a9 Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 20:44:11 -0700 Subject: [PATCH 03/33] Fix sell hitch: batch footprint un-stamp; warn on missing SellEffectSpawner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TowerInstance.StampFootprint now writes walkability via SetWalkableBatch instead of per-tile SetWalkable, so despawning (selling) a 2x2 tower fires one OnWalkabilityChanged / enemy re-path instead of four — matching placement and removing the frame hitch on sell. PlaySellEffectRpc now logs a one-time warning when no SellEffectSpawner is in the scene, since a missing spawner silently suppressed the coin VFX and sound. Co-Authored-By: Claude Opus 4.8 --- .../Scripts/Gameplay/TowerInstance.cs | 12 +++++++++++- .../Scripts/Gameplay/TowerPlacementManager.cs | 19 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Assets/_Project/Scripts/Gameplay/TowerInstance.cs b/Assets/_Project/Scripts/Gameplay/TowerInstance.cs index 1b01a4a..dfd73a8 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerInstance.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerInstance.cs @@ -1,4 +1,5 @@ // Assets/_Project/Scripts/Gameplay/TowerInstance.cs +using System.Collections.Generic; using Unity.Netcode; using UnityEngine; using TD.Core; @@ -511,11 +512,20 @@ namespace TD.Gameplay ? resolvedDefinition.FootprintSize : new Vector2Int(2, 2); + // Collect the footprint, then stamp walkability as a BATCH so a single + // OnWalkabilityChanged fires for the whole footprint. Per-tile SetWalkable fires + // that event once PER TILE — on despawn (sell) that meant up to 4 full enemy A* + // re-paths for a 2×2 tower in one frame, which was the sell hitch. Placement + // batches for the same reason (TowerPlacementManager.StampWalkable). Occupancy + // doesn't fire walkability events, so it stays per-tile. + var footprint = new List(footprintSize.x * footprintSize.y); foreach (var tile in GridCoordinates.GetFootprintTiles(anchorTile.Value, footprintSize)) { - loader.SetWalkable(tile, walkable); + footprint.Add(tile); loader.SetOccupied(tile, occupied); } + + loader.SetWalkableBatch(footprint, walkable); } // Reused per-instance across color updates to avoid per-call GC allocation. diff --git a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs index 92b349d..9943dc5 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerPlacementManager.cs @@ -365,10 +365,27 @@ namespace TD.Gameplay PlaySellEffectRpc(worldPos); } + // One-time guard so a missing spawner warns once per peer instead of on every sale. + private static bool s_warnedNoSellSpawner; + [Rpc(SendTo.Everyone)] private void PlaySellEffectRpc(Vector3 worldPos) { - SellEffectSpawner.Instance?.Play(worldPos); + var spawner = SellEffectSpawner.Instance; + if (spawner == null) + { + if (!s_warnedNoSellSpawner) + { + Debug.LogWarning("[TowerPlacementManager] A tower was sold, but there is no " + + "SellEffectSpawner in the scene — no coin VFX or sell sound " + + "will play. Add a SellEffectSpawner GameObject to each Match " + + "scene (assign its Sell Sound clip; the coin burst works even " + + "with no VFX prefab)."); + s_warnedNoSellSpawner = true; + } + return; + } + spawner.Play(worldPos); } // ----- Server-side commit hooks called by Builder ------------------ From 0b4cde4590a223ede9795aaf535bd0237c795ec6 Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 23:15:34 -0700 Subject: [PATCH 04/33] Adding the feature to sell towers with VFX and audio included --- Assets/_Project/Art/Materials/M_Gold.mat | 138 + Assets/_Project/Art/Materials/M_Gold.mat.meta | 8 + Assets/_Project/Art/Models/Blend Files.meta | 8 + Assets/_Project/Art/Models/Coin.fbx | 3 + Assets/_Project/Art/Models/Coin.fbx.meta | 110 + Assets/_Project/Art/VFX/FX_SellTower.prefab | 4896 +++++++++++++++++ .../_Project/Art/VFX/FX_SellTower.prefab.meta | 7 + Assets/_Project/Audio/Sound Effects.meta | 8 + .../Audio/Sound Effects/SellSoundEffect.ogg | 3 + .../Sound Effects/SellSoundEffect.ogg.meta | 23 + Assets/_Project/Scenes/Levels/9Player.unity | 53 + .../Scripts/Gameplay/EnemyMovement.cs | 20 +- .../Scripts/Gameplay/PathfindingService.cs | 88 +- .../_Project/Scripts/VFX/SellEffectSpawner.cs | 10 +- .../_Project/Scripts/VFX/TransientEffect.cs | 30 + .../Scripts/VFX/TransientEffect.cs.meta | 2 + 16 files changed, 5394 insertions(+), 13 deletions(-) create mode 100644 Assets/_Project/Art/Materials/M_Gold.mat create mode 100644 Assets/_Project/Art/Materials/M_Gold.mat.meta create mode 100644 Assets/_Project/Art/Models/Blend Files.meta create mode 100644 Assets/_Project/Art/Models/Coin.fbx create mode 100644 Assets/_Project/Art/Models/Coin.fbx.meta create mode 100644 Assets/_Project/Art/VFX/FX_SellTower.prefab create mode 100644 Assets/_Project/Art/VFX/FX_SellTower.prefab.meta create mode 100644 Assets/_Project/Audio/Sound Effects.meta create mode 100644 Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg create mode 100644 Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg.meta create mode 100644 Assets/_Project/Scripts/VFX/TransientEffect.cs create mode 100644 Assets/_Project/Scripts/VFX/TransientEffect.cs.meta diff --git a/Assets/_Project/Art/Materials/M_Gold.mat b/Assets/_Project/Art/Materials/M_Gold.mat new file mode 100644 index 0000000..3eb0ce0 --- /dev/null +++ b/Assets/_Project/Art/Materials/M_Gold.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: M_Gold + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _EMISSION + m_InvalidKeywords: [] + m_LightmapFlags: 2 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0.3 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.85 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _XRMotionVectorsPass: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.83137256, g: 0.6862745, b: 0.21568628, a: 1} + - _Color: {r: 0.83137256, g: 0.68627447, b: 0.2156862, a: 1} + - _EmissionColor: {r: 2, g: 0.6755797, b: 0.031372547, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &1062544154538963945 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 diff --git a/Assets/_Project/Art/Materials/M_Gold.mat.meta b/Assets/_Project/Art/Materials/M_Gold.mat.meta new file mode 100644 index 0000000..1caa033 --- /dev/null +++ b/Assets/_Project/Art/Materials/M_Gold.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 915f376be23f20941837c0809626fa5f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Art/Models/Blend Files.meta b/Assets/_Project/Art/Models/Blend Files.meta new file mode 100644 index 0000000..14a4fae --- /dev/null +++ b/Assets/_Project/Art/Models/Blend Files.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d70d84aef04e61749a232234c80f08ce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Art/Models/Coin.fbx b/Assets/_Project/Art/Models/Coin.fbx new file mode 100644 index 0000000..c732270 --- /dev/null +++ b/Assets/_Project/Art/Models/Coin.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5d924ce92dd6ea66125dea9941f965fb5da7eb4431f76ec9b4dd3b2091f19c1 +size 22476 diff --git a/Assets/_Project/Art/Models/Coin.fbx.meta b/Assets/_Project/Art/Models/Coin.fbx.meta new file mode 100644 index 0000000..674a119 --- /dev/null +++ b/Assets/_Project/Art/Models/Coin.fbx.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 280a727da941fc544b9aab7df7fe9f2d +ModelImporter: + serializedVersion: 24200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + generateMeshLods: 0 + meshLodGenerationFlags: 0 + maximumMeshLod: -1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/FX_SellTower.prefab b/Assets/_Project/Art/VFX/FX_SellTower.prefab new file mode 100644 index 0000000..56bd027 --- /dev/null +++ b/Assets/_Project/Art/VFX/FX_SellTower.prefab @@ -0,0 +1,4896 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2313150535691989867 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5508247059194889267} + - component: {fileID: 6710887781589457797} + - component: {fileID: 7520636153999768792} + m_Layer: 0 + m_Name: FX_SellTower + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5508247059194889267 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2313150535691989867} + serializedVersion: 2 + m_LocalRotation: {x: -0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: -90, y: 0, z: 0} +--- !u!198 &6710887781589457797 +ParticleSystem: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2313150535691989867} + serializedVersion: 8 + lengthInSec: 1.5 + simulationSpeed: 1 + stopAction: 2 + cullingMode: 0 + ringBufferMode: 0 + ringBufferLoopRange: {x: 0, y: 1} + emitterVelocityMode: 1 + looping: 0 + prewarm: 0 + playOnAwake: 1 + useUnscaledTime: 0 + autoRandomSeed: 1 + startDelay: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + moveWithTransform: 0 + moveWithCustomTransform: {fileID: 0} + scalingMode: 1 + randomSeed: 0 + InitialModule: + serializedVersion: 3 + enabled: 1 + startLifetime: + serializedVersion: 2 + minMaxState: 3 + scalar: 0.9 + minScalar: 0.6 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startSpeed: + serializedVersion: 2 + minMaxState: 3 + scalar: 6 + minScalar: 2 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startColor: + serializedVersion: 2 + minMaxState: 0 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + startSize: + serializedVersion: 2 + minMaxState: 0 + scalar: 30 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startSizeY: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startSizeZ: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startRotationX: + serializedVersion: 2 + minMaxState: 3 + scalar: 3.1415925 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startRotationY: + serializedVersion: 2 + minMaxState: 3 + scalar: 3.1415927 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startRotation: + serializedVersion: 2 + minMaxState: 3 + scalar: 3.1415927 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + randomizeRotationDirection: 0 + gravitySource: 0 + maxNumParticles: 1000 + customEmitterVelocity: {x: 0, y: 0, z: 0} + size3D: 0 + rotation3D: 1 + gravityModifier: + serializedVersion: 2 + minMaxState: 3 + scalar: 4 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + ShapeModule: + serializedVersion: 6 + enabled: 1 + type: 2 + angle: 25 + length: 5 + boxThickness: {x: 0, y: 0, z: 0} + radiusThickness: 1 + donutRadius: 0.2 + m_Position: {x: 0, y: 0, z: 0} + m_Rotation: {x: 0, y: 0, z: 0} + m_Scale: {x: 1, y: 1, z: 1} + placementMode: 0 + m_MeshMaterialIndex: 0 + m_MeshNormalOffset: 0 + m_MeshSpawn: + mode: 0 + spread: 0 + speed: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Mesh: {fileID: 0} + m_MeshRenderer: {fileID: 0} + m_SkinnedMeshRenderer: {fileID: 0} + m_Sprite: {fileID: 0} + m_SpriteRenderer: {fileID: 0} + m_UseMeshMaterialIndex: 0 + m_UseMeshColors: 1 + alignToDirection: 0 + m_Texture: {fileID: 0} + m_TextureClipChannel: 3 + m_TextureClipThreshold: 0 + m_TextureUVChannel: 0 + m_TextureColorAffectsParticles: 1 + m_TextureAlphaAffectsParticles: 1 + m_TextureBilinearFiltering: 0 + randomDirectionAmount: 0 + sphericalDirectionAmount: 0 + randomPositionAmount: 0 + radius: + value: 2 + mode: 0 + spread: 0 + speed: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + arc: + value: 360 + mode: 0 + spread: 0 + speed: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + EmissionModule: + enabled: 1 + serializedVersion: 4 + rateOverTime: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 10 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + rateOverDistance: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_BurstCount: 1 + m_Bursts: + - serializedVersion: 2 + time: 0 + countCurve: + serializedVersion: 2 + minMaxState: 3 + scalar: 50 + minScalar: 20 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + cycleCount: 1 + repeatInterval: 0.01 + probability: 1 + SizeModule: + enabled: 1 + curve: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: -2 + outSlope: -2 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + z: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + separateAxes: 0 + RotationModule: + enabled: 1 + x: + serializedVersion: 2 + minMaxState: 3 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 3 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curve: + serializedVersion: 2 + minMaxState: 3 + scalar: 0.7853982 + minScalar: 0.2617994 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + separateAxes: 0 + ColorModule: + enabled: 0 + gradient: + serializedVersion: 2 + minMaxState: 1 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + UVModule: + serializedVersion: 2 + enabled: 0 + mode: 0 + timeMode: 0 + fps: 30 + frameOverTime: + serializedVersion: 2 + minMaxState: 1 + scalar: 0.9999 + minScalar: 0.9999 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + startFrame: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + speedRange: {x: 0, y: 1} + tilesX: 1 + tilesY: 1 + animationType: 0 + rowIndex: 0 + cycles: 1 + uvChannelMask: -1 + rowMode: 1 + sprites: + - sprite: {fileID: 0} + flipU: 0 + flipV: 0 + VelocityModule: + enabled: 0 + x: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + z: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + orbitalX: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + orbitalY: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + orbitalZ: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + orbitalOffsetX: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + orbitalOffsetY: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + orbitalOffsetZ: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + radial: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + speedModifier: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + inWorldSpace: 0 + InheritVelocityModule: + enabled: 0 + m_Mode: 0 + m_Curve: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + LifetimeByEmitterSpeedModule: + enabled: 0 + m_Curve: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: -0.8 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0.2 + inSlope: -0.8 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Range: {x: 0, y: 1} + ForceModule: + enabled: 0 + x: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + z: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + inWorldSpace: 0 + randomizePerFrame: 0 + ExternalForcesModule: + serializedVersion: 2 + enabled: 0 + multiplierCurve: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + influenceFilter: 0 + influenceMask: + serializedVersion: 2 + m_Bits: 4294967295 + influenceList: [] + ClampVelocityModule: + enabled: 0 + x: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + z: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + magnitude: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + separateAxis: 0 + inWorldSpace: 0 + multiplyDragByParticleSize: 1 + multiplyDragByParticleVelocity: 1 + dampen: 0 + drag: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + NoiseModule: + enabled: 0 + strength: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + strengthY: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + strengthZ: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + separateAxes: 0 + frequency: 0.5 + damping: 1 + octaves: 1 + octaveMultiplier: 0.5 + octaveScale: 2 + quality: 1 + scrollSpeed: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + remap: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -1 + inSlope: 0 + outSlope: 2 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 2 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + remapY: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -1 + inSlope: 0 + outSlope: 2 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 2 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + remapZ: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: -1 + inSlope: 0 + outSlope: 2 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 2 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + remapEnabled: 0 + positionAmount: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + rotationAmount: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + sizeAmount: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + SizeBySpeedModule: + enabled: 0 + curve: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + z: + serializedVersion: 2 + minMaxState: 1 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + range: {x: 0, y: 1} + separateAxes: 0 + RotationBySpeedModule: + enabled: 0 + x: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + y: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + curve: + serializedVersion: 2 + minMaxState: 0 + scalar: 0.7853982 + minScalar: 0.7853982 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + separateAxes: 0 + range: {x: 0, y: 1} + ColorBySpeedModule: + enabled: 0 + gradient: + serializedVersion: 2 + minMaxState: 1 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + range: {x: 0, y: 1} + CollisionModule: + enabled: 0 + serializedVersion: 4 + type: 0 + collisionMode: 0 + colliderForce: 0 + multiplyColliderForceByParticleSize: 0 + multiplyColliderForceByParticleSpeed: 0 + multiplyColliderForceByCollisionAngle: 1 + m_Planes: [] + m_Dampen: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Bounce: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_EnergyLossOnCollision: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minKillSpeed: 0 + maxKillSpeed: 10000 + radiusScale: 1 + collidesWith: + serializedVersion: 2 + m_Bits: 4294967295 + maxCollisionShapes: 256 + quality: 0 + voxelSize: 0.5 + collisionMessages: 0 + collidesWithDynamic: 1 + interiorCollisions: 0 + TriggerModule: + enabled: 0 + serializedVersion: 2 + inside: 1 + outside: 0 + enter: 0 + exit: 0 + colliderQueryMode: 0 + radiusScale: 1 + primitives: [] + SubModule: + serializedVersion: 2 + enabled: 0 + subEmitters: + - serializedVersion: 3 + emitter: {fileID: 0} + type: 0 + properties: 0 + emitProbability: 1 + LightsModule: + enabled: 0 + ratio: 0 + light: {fileID: 0} + randomDistribution: 1 + color: 1 + range: 1 + intensity: 1 + rangeCurve: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + intensityCurve: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + maxLights: 20 + TrailModule: + enabled: 0 + mode: 0 + ratio: 1 + lifetime: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minVertexDistance: 0.2 + textureMode: 0 + textureScale: {x: 1, y: 1} + ribbonCount: 1 + shadowBias: 0.5 + worldSpace: 0 + dieWithParticles: 1 + sizeAffectsWidth: 1 + sizeAffectsLifetime: 0 + inheritParticleColor: 1 + generateLightingData: 0 + splitSubEmitterRibbons: 0 + attachRibbonsToTransform: 0 + colorOverLifetime: + serializedVersion: 2 + minMaxState: 0 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + widthOverTrail: + serializedVersion: 2 + minMaxState: 0 + scalar: 1 + minScalar: 1 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + colorOverTrail: + serializedVersion: 2 + minMaxState: 0 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + CustomDataModule: + enabled: 0 + mode0: 0 + vectorComponentCount0: 4 + color0: + serializedVersion: 2 + minMaxState: 0 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + colorLabel0: Color + vector0_0: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel0_0: X + vector0_1: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel0_1: Y + vector0_2: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel0_2: Z + vector0_3: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel0_3: W + mode1: 0 + vectorComponentCount1: 4 + color1: + serializedVersion: 2 + minMaxState: 0 + minColor: {r: 1, g: 1, b: 1, a: 1} + maxColor: {r: 1, g: 1, b: 1, a: 1} + maxGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + minGradient: + serializedVersion: 2 + key0: {r: 1, g: 1, b: 1, a: 1} + key1: {r: 1, g: 1, b: 1, a: 1} + key2: {r: 0, g: 0, b: 0, a: 0} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 0 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 0 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 0 + m_ColorSpace: -1 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 + colorLabel1: Color + vector1_0: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel1_0: X + vector1_1: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel1_1: Y + vector1_2: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel1_2: Z + vector1_3: + serializedVersion: 2 + minMaxState: 0 + scalar: 0 + minScalar: 0 + maxCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + minCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + vectorLabel1_3: W +--- !u!199 &7520636153999768792 +ParticleSystemRenderer: + serializedVersion: 7 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2313150535691989867} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 915f376be23f20941837c0809626fa5f, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_RenderMode: 4 + m_MeshDistribution: 0 + m_SortMode: 0 + m_MinParticleSize: 0 + m_MaxParticleSize: 0.5 + m_CameraVelocityScale: 0 + m_VelocityScale: 0 + m_LengthScale: 2 + m_SortingFudge: 0 + m_NormalDirection: 1 + m_ShadowBias: 0 + m_RenderAlignment: 0 + m_Pivot: {x: 0, y: 0, z: 0} + m_Flip: {x: 0, y: 0, z: 0} + m_EnableGPUInstancing: 1 + m_ApplyActiveColorSpace: 1 + m_AllowRoll: 1 + m_FreeformStretching: 0 + m_RotateWithStretchDirection: 1 + m_UseCustomVertexStreams: 0 + m_VertexStreams: 00010304 + m_UseCustomTrailVertexStreams: 0 + m_TrailVertexStreams: 00010304 + m_Mesh: {fileID: 8211022507781654652, guid: 280a727da941fc544b9aab7df7fe9f2d, type: 3} + m_Mesh1: {fileID: 0} + m_Mesh2: {fileID: 0} + m_Mesh3: {fileID: 0} + m_MeshWeighting: 1 + m_MeshWeighting1: 1 + m_MeshWeighting2: 1 + m_MeshWeighting3: 1 diff --git a/Assets/_Project/Art/VFX/FX_SellTower.prefab.meta b/Assets/_Project/Art/VFX/FX_SellTower.prefab.meta new file mode 100644 index 0000000..2755a51 --- /dev/null +++ b/Assets/_Project/Art/VFX/FX_SellTower.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 31f8d8c320b42c54d886d610fb13a1e7 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Audio/Sound Effects.meta b/Assets/_Project/Audio/Sound Effects.meta new file mode 100644 index 0000000..f7e97b8 --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1508e070d3666a4282a219e30ffdbf6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg b/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg new file mode 100644 index 0000000..437bd8c --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6047efab82ffe96cf15c078196b289076daae1875220b99f77596a06e7823808 +size 21467 diff --git a/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg.meta b/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg.meta new file mode 100644 index 0000000..f4b28da --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects/SellSoundEffect.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 778b3d5981f4c3045a475794435f43cc +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity index 3264d21..7ed2edb 100644 --- a/Assets/_Project/Scenes/Levels/9Player.unity +++ b/Assets/_Project/Scenes/Levels/9Player.unity @@ -12918,6 +12918,57 @@ BoxCollider: serializedVersion: 3 m_Size: {x: 24, y: 1, z: 30} m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &877074910 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 877074912} + - component: {fileID: 877074911} + m_Layer: 0 + m_Name: SellEffectSpawner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &877074911 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 877074910} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e2708c6bac8136f45b48c899d3d40630, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::TD.VFX.SellEffectSpawner + coinBurstPrefab: {fileID: 2313150535691989867, guid: 31f8d8c320b42c54d886d610fb13a1e7, type: 3} + sellSound: + clip: {fileID: 8300000, guid: 778b3d5981f4c3045a475794435f43cc, type: 3} + volume: 1 + minPitch: 0.95 + maxPitch: 1.05 + verticalOffset: 0.75 +--- !u!4 &877074912 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 877074910} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 38.13543, y: 0.5, z: 166.56534} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &902199259 GameObject: m_ObjectHideFlags: 0 @@ -15394,6 +15445,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: de7d013503af0f74c950f215f8dae1c0, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.PathfindingService + recomputeBudgetMs: 1.5 --- !u!4 &1149980841 Transform: m_ObjectHideFlags: 0 @@ -28962,3 +29014,4 @@ SceneRoots: - {fileID: 176580462} - {fileID: 516125087} - {fileID: 2079088113} + - {fileID: 877074912} diff --git a/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs b/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs index 86195c6..96a6e30 100644 --- a/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs +++ b/Assets/_Project/Scripts/Gameplay/EnemyMovement.cs @@ -21,8 +21,10 @@ namespace TD.Gameplay /// and stores the tile waypoint list. /// Each frame: moves toward the world center of remainingPath[0]. /// When within snap distance, pops the waypoint and checks for zone transitions. - /// When fires (tower placed / - /// sold), reruns A* from the current tile. + /// When the maze changes (tower placed / sold), 's + /// budgeted scheduler calls (registered via + /// ), rerunning A* from the current + /// tile — spread across frames so a full wave never spikes. /// When remainingPath is empty after a pop, the enemy has reached the /// goal — fires and the enemy is despawned. /// @@ -168,15 +170,18 @@ namespace TD.Gameplay // Recompute when a tower is placed or sold — grounded enemies only. // Flyers path on the static baked grid, so tower changes can never affect - // their route; subscribing would just trigger needless recomputes. + // their route; registering would just trigger needless recomputes. + // Registration (not a direct event subscription) lets PathfindingService + // spread the recomputes across frames under a per-frame budget, so a maze + // change with a full wave present never spikes a single frame. if (!isFlying && PathfindingService.Instance != null) - PathfindingService.Instance.OnPathsInvalidated += RecomputePath; + PathfindingService.Instance.RegisterMover(this); } public override void OnNetworkDespawn() { if (PathfindingService.Instance != null) - PathfindingService.Instance.OnPathsInvalidated -= RecomputePath; + PathfindingService.Instance.UnregisterMover(this); } // ----- Server update -------------------------------------------------- @@ -274,8 +279,9 @@ namespace TD.Gameplay // ----- Path invalidation ---------------------------------------------- - // Called on server when LevelLoader.OnWalkabilityChanged fires (tower placed/sold). - private void RecomputePath() + // Called by PathfindingService's budgeted scheduler after a walkability change + // (tower placed/sold). Public so the scheduler can drive it across frames. + public void RecomputePath() { if (!IsServer) return; diff --git a/Assets/_Project/Scripts/Gameplay/PathfindingService.cs b/Assets/_Project/Scripts/Gameplay/PathfindingService.cs index d6c99df..f9a98a8 100644 --- a/Assets/_Project/Scripts/Gameplay/PathfindingService.cs +++ b/Assets/_Project/Scripts/Gameplay/PathfindingService.cs @@ -26,13 +26,15 @@ namespace TD.Gameplay /// Who calls this: /// /// calls once on - /// spawn and again whenever fires. + /// spawn, then registers via to be re-pathed when + /// the maze changes. /// /// /// Invalidation: Subscribes to . - /// When a tower is placed or sold, LevelLoader.SetWalkable fires that event - /// and is relayed to all active enemies, which - /// each recompute their own path from their current tile. + /// When a tower is placed or sold, LevelLoader.SetWalkable fires that event; the + /// service then enqueues every registered grounded enemy and recomputes them under a + /// per-frame time budget (recomputeBudgetMs), draining across frames so a maze + /// change with a full wave present never spikes a single frame. /// /// Goal tile set: Built once on Start from /// LevelLoader.LevelData.Goals[].TileArea. Goal tiles never change at @@ -52,7 +54,10 @@ namespace TD.Gameplay /// /// Fired on every peer when the walkability grid changes (tower placed/sold). - /// subscribes per-instance to recompute its path. + /// Enemies no longer subscribe here — they register with the budgeted re-path + /// scheduler () so recomputes spread across frames. + /// This event remains as an extension point for any non-enemy listener that wants + /// immediate notification of a maze change. /// public event System.Action OnPathsInvalidated; @@ -79,6 +84,28 @@ namespace TD.Gameplay private readonly Dictionary gScore = new Dictionary(); private readonly SimplePriorityQueue openSet = new SimplePriorityQueue(); + // ----- Deferred re-path scheduler --------------------------------- + // + // Grounded enemies register here (flyers never re-path — baked grid). On a + // walkability change we enqueue every registered enemy and recompute a + // TIME-BUDGETED number of them per frame, draining the backlog over subsequent + // frames. Recomputing them all synchronously on the change frame spiked to ~0.5s + // with a full wave on this large grid whenever a tower was sold/placed — this + // caps the per-frame cost so no single frame ever hitches. The maze can only be + // opened (sell) or narrowed with a guaranteed remaining route (placement, BFS- + // validated), so an enemy briefly following its slightly-stale path for a few + // frames until its turn comes up is safe and visually negligible. + + [Tooltip("Max wall-clock milliseconds spent recomputing enemy paths per frame " + + "after a maze change. The backlog drains over following frames; at least " + + "one enemy is always processed per frame so it converges. Lower = smoother " + + "but slower to fully update; higher = faster to update but larger frame cost.")] + [SerializeField] private float recomputeBudgetMs = 1.5f; + + private readonly HashSet movers = new HashSet(); + private readonly Queue recomputeQueue = new Queue(); + private readonly HashSet queued = new HashSet(); + // ----- Lifecycle -------------------------------------------------- private void Awake() @@ -115,6 +142,48 @@ namespace TD.Gameplay loader.OnWalkabilityChanged -= HandleWalkabilityChanged; } + // Drains the deferred re-path backlog under a per-frame time budget. Runs on all + // peers, but the queue is only ever populated on the server (clients never register + // movers), so this is a no-op cost on clients. At least one enemy is processed per + // frame whenever the queue is non-empty, so it always converges. + private void Update() + { + if (recomputeQueue.Count == 0) return; + + double startMs = Time.realtimeSinceStartupAsDouble * 1000.0; + do + { + var mover = recomputeQueue.Dequeue(); + if (!queued.Remove(mover)) continue; // unregistered/cancelled after enqueue + if (mover != null) mover.RecomputePath(); // reads the CURRENT grid state + } + while (recomputeQueue.Count > 0 + && Time.realtimeSinceStartupAsDouble * 1000.0 - startMs < recomputeBudgetMs); + } + + // ----- Deferred re-path scheduler API ----------------------------- + + /// + /// Registers a grounded enemy to be re-pathed (budgeted, over following frames) + /// whenever the maze changes. Flyers must NOT register — their baked-grid route + /// never changes. Called on the server from . + /// + public void RegisterMover(EnemyMovement mover) + { + if (mover != null) movers.Add(mover); + } + + /// + /// Removes an enemy from the scheduler (on despawn). Any stale entry still sitting + /// in the pending queue is skipped when dequeued (the queued membership check). + /// + public void UnregisterMover(EnemyMovement mover) + { + if (mover == null) return; + movers.Remove(mover); + queued.Remove(mover); + } + // ----- Public API ------------------------------------------------- /// @@ -471,7 +540,16 @@ namespace TD.Gameplay private void HandleWalkabilityChanged() { + // Notify any non-enemy listeners immediately (kept for API compatibility). OnPathsInvalidated?.Invoke(); + + // Enqueue every registered grounded enemy for a budgeted, deferred recompute + // instead of recomputing them all on this frame. Already-queued enemies are + // deduped, so rapid successive maze changes just lengthen the drain rather + // than compounding into a spike. + foreach (var mover in movers) + if (queued.Add(mover)) + recomputeQueue.Enqueue(mover); } } diff --git a/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs b/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs index 0b67fc3..cbb8205 100644 --- a/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs +++ b/Assets/_Project/Scripts/VFX/SellEffectSpawner.cs @@ -65,7 +65,15 @@ namespace TD.VFX if (coinBurstPrefab != null) { - Instantiate(coinBurstPrefab, spawnPos, Quaternion.identity); + var instance = Instantiate(coinBurstPrefab, spawnPos, Quaternion.identity); + + // Force the burst to play. The spawner's whole job is to play this effect, so + // it shouldn't depend on the prefab's ParticleSystem having "Play On Awake" + // ticked — if that's off, the effect would silently never appear. Harmless when + // Play On Awake is already on (a freshly instantiated one-shot just restarts at + // t=0). VFX Graph effects play from their own settings, so a null PS is fine. + var ps = instance.GetComponentInChildren(); + if (ps != null) ps.Play(withChildren: true); } else { diff --git a/Assets/_Project/Scripts/VFX/TransientEffect.cs b/Assets/_Project/Scripts/VFX/TransientEffect.cs new file mode 100644 index 0000000..a258ceb --- /dev/null +++ b/Assets/_Project/Scripts/VFX/TransientEffect.cs @@ -0,0 +1,30 @@ +// Assets/_Project/Scripts/VFX/TransientEffect.cs +using UnityEngine; + +namespace TD.VFX +{ + /// + /// Destroys its GameObject a fixed time after it spawns. Drop this onto any one-shot + /// effect prefab — a particle burst, a VFX Graph effect, a sound-only object — so it + /// cleans itself up without any bespoke code. Designed for prefabs spawned by + /// (and any future effect spawner) that fire once and + /// should disappear. + /// + /// + /// Shuriken shortcut: a plain can instead self-destroy + /// with no component at all — set Main → Stop Action → Destroy and make sure Looping + /// is off. Use this component for VFX Graph effects (which have no Stop Action) or for + /// prefabs that combine several systems and need one predictable lifetime. + /// + /// Set to comfortably exceed the effect's visible duration so it + /// isn't cut off mid-play. + /// + public class TransientEffect : MonoBehaviour + { + [Tooltip("Seconds after spawn before this GameObject destroys itself. Set it a little " + + "longer than the effect's visible length so nothing is cut off.")] + [SerializeField, Min(0f)] private float lifetime = 1.5f; + + private void Start() => Destroy(gameObject, lifetime); + } +} diff --git a/Assets/_Project/Scripts/VFX/TransientEffect.cs.meta b/Assets/_Project/Scripts/VFX/TransientEffect.cs.meta new file mode 100644 index 0000000..2eb9598 --- /dev/null +++ b/Assets/_Project/Scripts/VFX/TransientEffect.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 739f3145f66002d47850b603164d07b8 \ No newline at end of file From 6c03a2f25079d9745f638663b4f8c0c15af35685 Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 23:21:32 -0700 Subject: [PATCH 05/33] Docs: mark Tower Sell done; note budgeted pathfinding re-path scheduler Updates Project_Context.md + Project_Roadmap.md for the tower-sell work (refund rules, coin VFX/SFX, refund excluded from income) and the PathfindingService budgeted re-path scheduler that removed the sell/placement frame hitch. Follows commit 0b4cde4 which landed the code + art. Co-Authored-By: Claude Opus 4.8 --- Project_Context.md | 7 ++++--- Project_Roadmap.md | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Project_Context.md b/Project_Context.md index 3e2c6d5..fd56cfd 100644 --- a/Project_Context.md +++ b/Project_Context.md @@ -4,7 +4,7 @@ A snapshot of **where the project is and how it works** — the authoritative reference for current architecture, implemented systems, conventions, and known debt. It pairs with [`Project_Roadmap.md`](Project_Roadmap.md), which is the forward-looking plan. When the two disagree, this document describes *what exists today*; the roadmap describes *what's planned next*. -Last substantial update: 2026-06-24. +Last substantial update: 2026-07-14. --- @@ -56,10 +56,11 @@ Unity **6.4 (6000.4.4f1)**, URP, IL2CPP, .NET Standard 2.1, Linear color space, - `TowerPlacementManager` (server-validated placement queue) — `SpawnTower` now **seats towers flush on the ground from their mesh bounds** (`SeatOnGround`), so any pivot works (replaced the old hard-coded y=0.5). `Builder` build queue with staged construction/pause/cancel/refund, RTS selection, owner tinting. - **Construction-phase build visuals:** `BuildSiteVisual` swaps between an ordered set of phase prefabs as a tower builds — `ConstructionPhaseSet` SO + optional per-tower `TowerDefinition.ConstructionPhases`, with a project-default set and a legacy cube Y-scale fallback. `BuildSiteVisual` resolves its def via `TowerTypeId` (catalog), like `TowerInstance`. - **Tesla Coil tower:** Electric, `AllInRange` (zaps every enemy in range each 0.5s tick). `TeslaArcVisual` draws arced, crackling, HDR `LineRenderer` bolts that flicker, plus **real point lights** (emitter flash + per-impact lights at struck enemies, capped) so the electricity actually illuminates the scene — emission/bloom alone don't cast light. +- **Tower Sell** (branch `tower-sell`, verified in-engine 2026-07-14): selecting an owned, completed tower shows a **Sell** action in the command grid's **bottom-right** slot (owner-gated; a non-owner sees it disabled). `TowerInstance.RequestSellServerRpc` (owner-validated, like paint) refunds `TowerDefinition.SellRefundPercent` (default 0.75) of the tower's replicated `goldInvested` (placement + any future upgrade spend), except a `FullRefundIfUnupgraded` tower (the **Wall**) refunds 100% while `upgradeCount == 0`. The refund is **not** counted as round income — `PlayerGoldManager.AwardGold(amount, countAsEarned:false)`. Selling despawns the tower (`OnNetworkDespawn` un-stamps the footprint as a **batch** and clears selection) and broadcasts a coin **VFX + rustle SFX** through `SellEffectSpawner` (scene singleton mirroring `FloatingTextSpawner`) via `TowerPlacementManager.PlaySellEffectRpc` (routed off a persistent object because the tower despawns the same frame). `TowerInstance.ServerAddUpgradeInvestment` is the seam the future upgrade system writes to. The coin VFX is an **artist-authored** prefab (`FX_SellTower`: a Shuriken **mesh-particle** burst of the Blender `Coin` model with an **emissive** gold material — emissive so it survives the grimdark grade); `CoinBurstVfx` is the zero-art code-gen fallback, and new reusable `TransientEffect` self-destructs one-shot effect prefabs (for VFX-Graph effects that lack a Stop Action). ### Enemies & pathfinding - `EnemyHealth` (replicated HP, damage types, `IsFlying`, held state), `EnemyStatus` (lingering effects: slow/DoT), `EnemyMovement` (A* path following, zone-leak attribution, death/sink sequence). -- `PathfindingService` (A* on the runtime walkability grid, octile heuristic, corner-cut prevention, line-of-sight path smoothing; re-paths on tower placement/removal). +- `PathfindingService` (A* on the runtime walkability grid, octile heuristic, corner-cut prevention, line-of-sight path smoothing). **Re-paths via a budgeted scheduler:** grounded enemies `RegisterMover`/`UnregisterMover`; on a maze change the service enqueues them and recomputes under a per-frame `recomputeBudgetMs` (default 1.5 ms) drain, spreading the work across frames so a placement/sell with a full wave present no longer spikes a frame (was ~0.5 s). Safe because selling only opens the maze and placement is BFS-guaranteed to leave a route, so a few frames of slightly-stale path is invisible. - **Flying enemies:** path on the **baked terrain grid** (`LevelLoader.IsBaseWalkable`) so they soar over towers; compute once, never re-path; spawn elevated by `EnemyDefinition.FlightHeight`. - Content: ~10 enemy definitions/prefabs (Crystal Golem / Cyclops / Ent variants, Undead Drake = the flying test enemy), 10 wave definitions. @@ -102,4 +103,4 @@ Unity **6.4 (6000.4.4f1)**, URP, IL2CPP, .NET Standard 2.1, Linear color space, - **Catalog index 0 is a reserved sentinel** (valid `TowerTypeId`s start at 1) — easy to forget when wiring the catalog in the inspector. - **Catalog-index identifiers aren't session-stable** — blocks cross-match persistence until a stable ID is added. - **Paint system frozen**; **Race vs Builder** naming unresolved; the gold **"Buy Roll available any time"** rule is provisional and may change. -- **Stubbed/unbuilt:** tower Upgrade/Sell actions (HUD buttons disabled), enemy resistances/weaknesses, in-match race-pick countdown. +- **Stubbed/unbuilt:** tower **Upgrade** action (HUD button still disabled; the `TowerInstance.ServerAddUpgradeInvestment` seam is ready for it), enemy resistances/weaknesses, in-match race-pick countdown. *(Tower **Sell** is now done — see Combat & towers.)* diff --git a/Project_Roadmap.md b/Project_Roadmap.md index a41edbf..aa95f7f 100644 --- a/Project_Roadmap.md +++ b/Project_Roadmap.md @@ -4,7 +4,7 @@ The **forward-looking plan**: what's done, what's next, and the sequencing. Current-state architecture and the full list of implemented systems live in [`Project_Context.md`](Project_Context.md) — read that first for "how things work today." This document focuses on direction and remaining work. -Last substantial update: 2026-06-24. +Last substantial update: 2026-07-14. --- @@ -36,6 +36,8 @@ All players start with the **same three towers** — **Basic Arrow** (ground+air **Done & merged:** functional match loop end-to-end, HUD, lobby + race selection, economy, enemies + A* pathfinding, **flying enemies + air-targeting**, **per-player tower deck** (keystone #1), **draft Slice 1** (spine + "new tower"), **TowerRegistry removal** (towers replicate by `TowerTypeId`), **per-tower construction-phase build visuals**, **ground-seating from mesh bounds**, **Tesla Coil tower** (Electric + AllInRange + arc VFX with real flash/impact lights). +**Done, on branch `tower-sell` (pushed to origin; NOT yet merged to `main`):** **Tower Sell** — owner-gated Sell action, refunds `SellRefundPercent` (default 75%) of invested gold, the **Wall refunds 100% while un-upgraded**, refund excluded from round income, coin **VFX** (artist-authored emissive mesh-particle `FX_SellTower`, with a `CoinBurstVfx` code-gen fallback) + rustle **SFX**. Also a **budgeted enemy re-path scheduler** in `PathfindingService` that removes the ~0.5 s frame hitch on any maze change (sell/placement) with a full wave present, plus a batched footprint un-stamp and the NGO `RequireOwnership`→`InvokePermission` deprecation cleanup. Verified in-engine 2026-07-14. + **In progress (branch `feature/post-processing`):** project-wide **grimdark post-processing** grade + HDR; Tesla arc lighting polish. *(This branch was fast-forwarded onto the Tesla work; commit the post-processing assets + the `TeslaArcVisual` light additions.)* **Paused:** in-match Paint system (overlaps with systemic upgrades). @@ -80,7 +82,8 @@ Player profile saving owned content; **win/loss reward pools** drawn server-side ## Part B — Functional gameplay remainder (not roguelike-specific) -- **Tower Upgrade / Sell actions** — HUD buttons exist but are disabled. Sell first (refund + despawn), then per-tower upgrade if the systemic model leaves room for it. +- **Tower Sell — ✅ DONE** (branch `tower-sell`): refund + despawn + coin VFX/SFX; 75% of invested gold, Wall 100% while un-upgraded, refund not counted as income; `TowerInstance.ServerAddUpgradeInvestment` records upgrade spend for the refund and is the seam the Upgrade system will write to. +- **Tower Upgrade action** — HUD button still disabled. Build it once the systemic-upgrade model (A3) settles whether per-tower upgrade trees are wanted on top of the systemic modifiers. - **Enemy resistances / weaknesses** — `EnemyHealth.TakeDamage` has the stub slot; info panel has the placeholder. - **Terrain architecture decision** — Unity Terrain vs mesh vs ProBuilder. Builder code is terrain-agnostic; decide before heavy art. - **Camera polish** — cursor-anchored zoom near map edges, center-on-builder hotkey, race/phase-aware initial position. From 9f87c04b4c7a30e50ed2b79e5ee5265ab819cc1f Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 23:28:12 -0700 Subject: [PATCH 06/33] reverting 9player changes --- Assets/_Project/Scenes/Levels/9Player.unity | 52 --------------------- 1 file changed, 52 deletions(-) diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity index 7ed2edb..a8d0238 100644 --- a/Assets/_Project/Scenes/Levels/9Player.unity +++ b/Assets/_Project/Scenes/Levels/9Player.unity @@ -12918,57 +12918,6 @@ BoxCollider: serializedVersion: 3 m_Size: {x: 24, y: 1, z: 30} m_Center: {x: 0, y: 0, z: 0} ---- !u!1 &877074910 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 877074912} - - component: {fileID: 877074911} - m_Layer: 0 - m_Name: SellEffectSpawner - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &877074911 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 877074910} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e2708c6bac8136f45b48c899d3d40630, type: 3} - m_Name: - m_EditorClassIdentifier: Assembly-CSharp::TD.VFX.SellEffectSpawner - coinBurstPrefab: {fileID: 2313150535691989867, guid: 31f8d8c320b42c54d886d610fb13a1e7, type: 3} - sellSound: - clip: {fileID: 8300000, guid: 778b3d5981f4c3045a475794435f43cc, type: 3} - volume: 1 - minPitch: 0.95 - maxPitch: 1.05 - verticalOffset: 0.75 ---- !u!4 &877074912 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 877074910} - serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 38.13543, y: 0.5, z: 166.56534} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &902199259 GameObject: m_ObjectHideFlags: 0 @@ -29014,4 +28963,3 @@ SceneRoots: - {fileID: 176580462} - {fileID: 516125087} - {fileID: 2079088113} - - {fileID: 877074912} From c38d6737681de27773a9787ac49269b470c69341 Mon Sep 17 00:00:00 2001 From: Matt F Date: Tue, 14 Jul 2026 23:57:13 -0700 Subject: [PATCH 07/33] adding sound effect game object to main branch --- Assets/_Project/Scenes/Levels/9Player.unity | 52 +++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity index 458828c..90db615 100644 --- a/Assets/_Project/Scenes/Levels/9Player.unity +++ b/Assets/_Project/Scenes/Levels/9Player.unity @@ -11534,6 +11534,57 @@ Mesh: - serializedVersion: 1 m_IndexStart: 0 m_IndexCount: 0 +--- !u!1 &759470733 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 759470735} + - component: {fileID: 759470734} + m_Layer: 0 + m_Name: SellEffectSpawner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &759470734 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 759470733} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e2708c6bac8136f45b48c899d3d40630, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::TD.VFX.SellEffectSpawner + coinBurstPrefab: {fileID: 2313150535691989867, guid: 31f8d8c320b42c54d886d610fb13a1e7, type: 3} + sellSound: + clip: {fileID: 8300000, guid: 778b3d5981f4c3045a475794435f43cc, type: 3} + volume: 1 + minPitch: 0.95 + maxPitch: 1.05 + verticalOffset: 0.75 +--- !u!4 &759470735 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 759470733} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 35.63582, y: 0.5, z: 163.67152} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &759520883 GameObject: m_ObjectHideFlags: 0 @@ -29066,3 +29117,4 @@ SceneRoots: - {fileID: 2079088113} - {fileID: 914832726} - {fileID: 993870445} + - {fileID: 759470735} From fe2c59d326d1497f29266ec2ee10c6cd42e638e6 Mon Sep 17 00:00:00 2001 From: Ian Woods Date: Thu, 16 Jul 2026 20:49:13 -0700 Subject: [PATCH 08/33] tab once selects builder, tab twice focuses builder --- Assets/_Project/Scenes/Levels/9Player.unity | 2 +- Assets/_Project/Scripts/Audio/AudioCategory.cs | 2 +- .../Scripts/Combat/TeslaTowerFireSound.cs | 2 +- .../Scripts/Gameplay/BuilderInputController.cs | 17 ++++++++++++++++- .../BuilderSpells/FireballSpellDefinition.cs | 2 +- Assets/_Project/Scripts/UI/HUDController.cs | 9 ++++++++- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Assets/_Project/Scenes/Levels/9Player.unity b/Assets/_Project/Scenes/Levels/9Player.unity index 90db615..0fcac59 100644 --- a/Assets/_Project/Scenes/Levels/9Player.unity +++ b/Assets/_Project/Scenes/Levels/9Player.unity @@ -2253,7 +2253,7 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::TD.Audio.AudioManager categories: - category: 0 - maxVoices: 4 + maxVoices: 6 volume: 0.5 - category: 1 maxVoices: 4 diff --git a/Assets/_Project/Scripts/Audio/AudioCategory.cs b/Assets/_Project/Scripts/Audio/AudioCategory.cs index 9a446aa..539e9ba 100644 --- a/Assets/_Project/Scripts/Audio/AudioCategory.cs +++ b/Assets/_Project/Scripts/Audio/AudioCategory.cs @@ -1,5 +1,5 @@ // Assets/_Project/Scripts/Audio/AudioCategory.cs namespace TD.Audio { - public enum AudioCategory { TowerFire, EnemyHitDeath, UI } + public enum AudioCategory { Combat, EnemyHitDeath, UI } } diff --git a/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs b/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs index 3334523..eddc323 100644 --- a/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs +++ b/Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs @@ -38,7 +38,7 @@ namespace TD.Combat private void HandleAreaFired(Vector3[] positions) { - AudioManager.Instance?.Play(fireSound.clip, AudioCategory.TowerFire, fireSound.RandomPitch(), fireSound.volume); + AudioManager.Instance?.Play(fireSound.clip, AudioCategory.Combat, fireSound.RandomPitch(), fireSound.volume); } } } diff --git a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs index ce1e258..72bd7c3 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs @@ -156,7 +156,22 @@ namespace TD.Gameplay { HUDController.Instance?.ToggleBuffMenu(); } - + + // Tab: select the builder, or (if already selected) recenter the camera on it. + if (keyboard != null && keyboard.tabKey.wasPressedThisFrame + && !HUDController.IsTextInputActive) + { + var selection = SelectionState.Instance; + if (selection != null && selection.IsSelected(builder)) + { + HUDController.Instance?.CenterCameraOnSelection(); + } + else + { + selection?.Select(builder); + } + } + if (pointerOverHud) return; if (!mouse.rightButton.wasPressedThisFrame) return; diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs index b5dae1f..5f34a1c 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs @@ -65,7 +65,7 @@ namespace TD.Gameplay.BuilderSpells Destroy(Instantiate(impactVfxPrefab, targetPoint, Quaternion.identity), impactVfxLifetime); if (impactSound.clip != null) - AudioManager.Instance?.Play(impactSound.clip, AudioCategory.TowerFire, + AudioManager.Instance?.Play(impactSound.clip, AudioCategory.Combat, impactSound.RandomPitch(), impactSound.volume); } } diff --git a/Assets/_Project/Scripts/UI/HUDController.cs b/Assets/_Project/Scripts/UI/HUDController.cs index e63a097..7d17387 100644 --- a/Assets/_Project/Scripts/UI/HUDController.cs +++ b/Assets/_Project/Scripts/UI/HUDController.cs @@ -1642,7 +1642,14 @@ namespace TD.UI // WC3 / SC2 convention: clicking the portrait recenters the camera on // whoever is selected. Zoom is preserved (CameraController.JumpTo only // moves the pivot). No-op when nothing is selected or the camera isn't wired. - private void OnPortraitClicked(ClickEvent evt) + private void OnPortraitClicked(ClickEvent evt) => CenterCameraOnSelection(); + + /// + /// Recenters the camera on the current selection (same behavior as clicking the + /// portrait). No-op when nothing is selected or the camera isn't wired. Also used + /// by the Tab hotkey (select-builder-then-focus) in BuilderInputController. + /// + public void CenterCameraOnSelection() { var sel = SelectionState.Instance?.SelectedObject; if (sel == null) return; From 689fe7be885ae5f6357ebe47444d6c4993e25dd6 Mon Sep 17 00:00:00 2001 From: Ian Woods Date: Fri, 17 Jul 2026 00:03:36 -0700 Subject: [PATCH 09/33] shitty looking AOE effect for slow area --- .../_Project/Art/VFX/spells/Fireball.prefab | 6 +- .../Art/VFX/spells/VFX_slowarea.prefab | 120 + .../Art/VFX/spells/VFX_slowarea.prefab.meta | 7 + .../_Project/Art/VFX/spells/VFX_slowarea.vfx | 2601 +++++++++++++++++ .../Art/VFX/spells/VFX_slowarea.vfx.meta | 15 + .../BuilderSpells/FireballSpell.asset | 2 +- .../BuilderSpells/SlowAreaSpell.asset | 8 +- .../BuilderSpells/SlowAreaSpellDefinition.cs | 24 + 8 files changed, 2778 insertions(+), 5 deletions(-) create mode 100644 Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab create mode 100644 Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta create mode 100644 Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx create mode 100644 Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta diff --git a/Assets/_Project/Art/VFX/spells/Fireball.prefab b/Assets/_Project/Art/VFX/spells/Fireball.prefab index b51070f..b7e0984 100644 --- a/Assets/_Project/Art/VFX/spells/Fireball.prefab +++ b/Assets/_Project/Art/VFX/spells/Fireball.prefab @@ -104,7 +104,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::TD.VFX.FallFromSkyVisual dropHeight: 20 - duration: 0.5 + duration: 1.2 fallCurve: serializedVersion: 2 m_Curve: @@ -129,5 +129,5 @@ MonoBehaviour: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 - fallAngleDegrees: 0 - fallDirection: {x: 0, y: 0, z: 1} + fallAngleDegrees: 25.6 + fallDirection: {x: 0.2, y: 0.2, z: 1} diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab b/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab new file mode 100644 index 0000000..b5d5e68 --- /dev/null +++ b/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab @@ -0,0 +1,120 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1462673130280185047 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 30710218362299472} + - component: {fileID: 2262385832724230530} + - component: {fileID: 5239089805406934537} + m_Layer: 0 + m_Name: VFX_slowarea + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &30710218362299472 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462673130280185047} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -55.61683, y: -0, z: -33.87226} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!2083052967 &2262385832724230530 +VisualEffect: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462673130280185047} + m_Enabled: 1 + m_Asset: {fileID: 8926484042661614526, guid: 397a5bed36b1e63a0a3eef17b04f65bd, type: 3} + m_InitialEventName: OnPlay + m_InitialEventNameOverriden: 0 + m_StartSeed: 0 + m_ResetSeedOnPlay: 1 + m_AllowInstancing: 1 + m_ResourceVersion: 1 + m_PropertySheet: + m_Float: + m_Array: [] + m_Vector2f: + m_Array: [] + m_Vector3f: + m_Array: [] + m_Vector4f: + m_Array: [] + m_Uint: + m_Array: [] + m_Int: + m_Array: [] + m_Matrix4x4f: + m_Array: [] + m_AnimationCurve: + m_Array: [] + m_Gradient: + m_Array: [] + m_NamedObject: + m_Array: [] + m_Bool: + m_Array: [] +--- !u!73398921 &5239089805406934537 +VFXRenderer: + serializedVersion: 1 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1462673130280185047} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 0 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 0 + m_RayTracingMode: 0 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta b/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta new file mode 100644 index 0000000..ecc94a0 --- /dev/null +++ b/Assets/_Project/Art/VFX/spells/VFX_slowarea.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bf2f1f2a9a54e9162b80673e3f7eeaf6 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx b/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx new file mode 100644 index 0000000..a94dcde --- /dev/null +++ b/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx @@ -0,0 +1,2601 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &114340500867371532 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d01270efd3285ea4a9d6c555cb0a8027, type: 3} + m_Name: VFXUI + m_EditorClassIdentifier: + groupInfos: + - title: Base Loop + position: + serializedVersion: 2 + x: 851 + y: -1433 + width: 475 + height: 2277 + contents: + - model: {fileID: 8926484042661614608} + id: 0 + isStickyNote: 0 + - model: {fileID: 8926484042661614613} + id: 0 + isStickyNote: 0 + - model: {fileID: 8926484042661614662} + id: 0 + isStickyNote: 0 + - model: {fileID: 8926484042661614681} + id: 0 + isStickyNote: 0 + stickyNoteInfos: [] + categories: [] + uiBounds: + serializedVersion: 2 + x: 852 + y: -1433 + width: 474 + height: 2255 +--- !u!114 &114350483966674976 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7d4c867f6b72b714dbb5fd1780afe208, type: 3} + m_Name: VFX_slowarea + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614608} + - {fileID: 8926484042661614613} + - {fileID: 8926484042661614662} + - {fileID: 8926484042661614681} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_UIInfos: {fileID: 114340500867371532} + m_CustomAttributes: [] + m_ParameterInfo: [] + m_ImportDependencies: [] + m_GraphVersion: 19 + m_ResourceVersion: 1 + m_SubgraphDependencies: [] + m_CategoryPath: +--- !u!2058629511 &8926484042661614527 +VisualEffectResource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: VFX_slowarea + m_Graph: {fileID: 114350483966674976} + m_Infos: + m_RendererSettings: + motionVectorGenerationMode: 0 + shadowCastingMode: 0 + m_CullingFlags: 3 + m_UpdateMode: 0 + m_PreWarmDeltaTime: 0.05 + m_PreWarmStepCount: 0 + m_InitialEventName: OnPlay + m_InstancingMode: 0 + m_InstancingCapacity: 64 +--- !u!114 &8926484042661614608 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 73a13919d81fb7444849bae8b5c812a2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614610} + m_UIPosition: {x: 877, y: -1374} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: Spawn system + m_Data: {fileID: 8926484042661614609} + m_InputFlowSlot: + - link: [] + - link: [] + m_OutputFlowSlot: + - link: + - context: {fileID: 8926484042661614613} + slotIndex: 0 + loopDuration: 0 + loopCount: 0 + delayBeforeLoop: 0 + delayAfterLoop: 0 +--- !u!114 &8926484042661614609 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f68759077adc0b143b6e1c101e82065e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + title: + m_Owners: + - {fileID: 8926484042661614608} +--- !u!114 &8926484042661614610 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f05c6884b705ce14d82ae720f0ec209f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614608} + m_Children: [] + m_UIPosition: {x: 357.33423, y: 1216.2454} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614611} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614612} +--- !u!114 &8926484042661614611 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614611} + m_MasterData: + m_Owner: {fileID: 8926484042661614610} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 64 + m_Space: -1 + m_Property: + name: Rate + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614612 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614612} + m_MasterData: + m_Owner: {fileID: 8926484042661614610} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614613 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9dfea48843f53fc438eabc12a3a30abc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614628} + - {fileID: 8926484042661614834} + - {fileID: 8926484042661614806} + m_UIPosition: {x: 877, y: -1086} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614774} + - {fileID: 8926484042661614783} + m_OutputSlots: [] + m_Label: Initialize Particles + m_Data: {fileID: 8926484042661614627} + m_InputFlowSlot: + - link: + - context: {fileID: 8926484042661614608} + slotIndex: 0 + m_OutputFlowSlot: + - link: + - context: {fileID: 8926484042661614662} + slotIndex: 0 +--- !u!114 &8926484042661614627 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d78581a96eae8bf4398c282eb0b098bd, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + title: Simple Loop + m_Owners: + - {fileID: 8926484042661614613} + - {fileID: 8926484042661614662} + - {fileID: 8926484042661614681} + dataType: 0 + capacity: 68 + stripCapacity: 1 + particlePerStripCount: 32 + needsComputeBounds: 0 + boundsMode: 0 + m_Space: 1 +--- !u!114 &8926484042661614628 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a971fa2e110a0ac42ac1d8dae408704b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614613} + m_Children: [] + m_UIPosition: {x: 357.33423, y: 1214.2454} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614629} + - {fileID: 8926484042661614630} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614631} + attribute: lifetime + Composition: 0 + Source: 0 + Random: 2 + channels: 6 +--- !u!114 &8926484042661614629 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614629} + m_MasterData: + m_Owner: {fileID: 8926484042661614628} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0.8 + m_Space: -1 + m_Property: + name: A + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614630 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614630} + m_MasterData: + m_Owner: {fileID: 8926484042661614628} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 1.2 + m_Space: -1 + m_Property: + name: B + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614631 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614631} + m_MasterData: + m_Owner: {fileID: 8926484042661614628} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614662 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2dc095764ededfa4bb32fa602511ea4b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614820} + - {fileID: 8926484042661614827} + m_UIPosition: {x: 877, y: -187} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Label: Update Particles + m_Data: {fileID: 8926484042661614627} + m_InputFlowSlot: + - link: + - context: {fileID: 8926484042661614613} + slotIndex: 0 + m_OutputFlowSlot: + - link: + - context: {fileID: 8926484042661614681} + slotIndex: 0 + integration: 0 + angularIntegration: 0 + ageParticles: 1 + reapParticles: 1 + skipZeroDeltaUpdate: 0 +--- !u!114 &8926484042661614681 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a0b9e6b9139e58d4c957ec54595da7d3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 114350483966674976} + m_Children: + - {fileID: 8926484042661614685} + - {fileID: 8926484042661614830} + - {fileID: 8926484042661614722} + m_UIPosition: {x: 877, y: 214} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614682} + m_OutputSlots: [] + m_Label: Render Quad + m_Data: {fileID: 8926484042661614627} + m_InputFlowSlot: + - link: + - context: {fileID: 8926484042661614662} + slotIndex: 0 + m_OutputFlowSlot: + - link: [] + blendMode: 1 + cullMode: 0 + zWriteMode: 0 + zTestMode: 0 + useAlphaClipping: 0 + generateMotionVector: 0 + excludeFromTUAndAA: 0 + sortingPriority: 0 + m_SubOutputs: + - {fileID: 8926484042661614687} + - {fileID: 8926484042661614833} + useBaseColorMap: 3 + colorMapping: 0 + uvMode: 0 + flipbookLayout: 0 + flipbookBlendFrames: 0 + flipbookMotionVectors: 0 + useSoftParticle: 0 + vfxSystemSortPriority: 0 + sort: 0 + sortMode: 0 + revertSorting: 0 + indirectDraw: 0 + computeCulling: 0 + frustumCulling: 0 + castShadows: 0 + useExposureWeight: 0 + enableRayTracing: 0 + decimationFactor: 1 + raytracedScaleMode: 0 + needsOwnSort: 1 + needsOwnAabbBuffer: 0 + shaderGraph: {fileID: 0} + materialSettings: + m_PropertyNames: [] + m_PropertyValues: [] + renderQueue: -1 + primitiveType: 1 + useGeometryShader: 0 +--- !u!114 &8926484042661614682 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70a331b1d86cc8d4aa106ccbe0da5852, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614682} + m_MasterData: + m_Owner: {fileID: 8926484042661614681} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"obj":{"fileID":2800000,"guid":"8aafaa78fe944854997fef757ff4ba72","type":3}}' + m_Space: -1 + m_Property: + name: mainTexture + m_serializedType: + m_SerializableType: UnityEngine.Texture2D, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614685 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d16c6aeaef944094b9a1633041804207, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614681} + m_Children: [] + m_UIPosition: {x: 0, y: 2} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: [] + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614686} + mode: 0 + axes: 4 + faceRay: 1 +--- !u!114 &8926484042661614686 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614686} + m_MasterData: + m_Owner: {fileID: 8926484042661614685} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614687 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 081ffb0090424ba4cb05370a42ead6b9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &8926484042661614722 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 01ec2c1930009b04ea08905b47262415, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614681} + m_Children: [] + m_UIPosition: {x: 508.1385, y: 271.34802} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614723} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614724} + attribute: color + Composition: 2 + AlphaComposition: 0 + SampleMode: 0 + Mode: 1 + ColorMode: 3 + channels: 6 +--- !u!114 &8926484042661614723 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76f778ff57c4e8145b9681fe3268d8e9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614723} + m_MasterData: + m_Owner: {fileID: 8926484042661614722} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Gradient, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"colorKeys":[{"color":{"r":0.003921564668416977,"g":0.7162883877754211,"b":0.9725490212440491,"a":1.0},"time":0.0},{"color":{"r":0.2158605307340622,"g":0.6866854429244995,"b":1.0,"a":1.0},"time":1.0}],"alphaKeys":[{"alpha":1.0,"time":0.0},{"alpha":1.0,"time":0.800000011920929},{"alpha":0.0,"time":1.0}],"gradientMode":0}' + m_Space: -1 + m_Property: + name: Color + m_serializedType: + m_SerializableType: UnityEngine.Gradient, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614724 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614724} + m_MasterData: + m_Owner: {fileID: 8926484042661614722} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614774 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614775} + - {fileID: 8926484042661614779} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 8926484042661614613} + m_Value: + m_Type: + m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"center":{"x":0.0,"y":1.0,"z":0.0},"size":{"x":3.5,"y":4.0,"z":3.5}}' + m_Space: 0 + m_Property: + name: bounds + m_serializedType: + m_SerializableType: UnityEditor.VFX.AABox, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614775 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614774} + m_Children: + - {fileID: 8926484042661614776} + - {fileID: 8926484042661614777} + - {fileID: 8926484042661614778} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: center + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614776 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614775} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614777 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614775} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614778 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614775} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614779 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614774} + m_Children: + - {fileID: 8926484042661614780} + - {fileID: 8926484042661614781} + - {fileID: 8926484042661614782} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: size + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614780 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614779} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614781 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614779} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614782 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614779} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614774} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614783 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614784} + - {fileID: 8926484042661614785} + - {fileID: 8926484042661614786} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614783} + m_MasterData: + m_Owner: {fileID: 8926484042661614613} + m_Value: + m_Type: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"x":0.5,"y":0.5,"z":0.5}' + m_Space: -1 + m_Property: + name: boundsPadding + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614784 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614783} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614783} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614785 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614783} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614783} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614786 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614783} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614783} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614806 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 26096dfac7c062b4b94c293605ba085e, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614613} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614807} + - {fileID: 8926484042661614818} + - {fileID: 8926484042661614819} + - {fileID: 8926484042661614813} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614814} + composition: 0 + speedMode: 1 +--- !u!114 &8926484042661614807 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e8f2b4a846fd4c14a893cde576ad172b, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614808} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614807} + m_MasterData: + m_Owner: {fileID: 8926484042661614806} + m_Value: + m_Type: + m_SerializableType: UnityEditor.VFX.DirectionType, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"direction":{"x":0.0,"y":1.0,"z":0.0}}' + m_Space: 0 + m_Property: + name: Direction + m_serializedType: + m_SerializableType: UnityEditor.VFX.DirectionType, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614808 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614807} + m_Children: + - {fileID: 8926484042661614809} + - {fileID: 8926484042661614810} + - {fileID: 8926484042661614811} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614807} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: direction + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614809 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614808} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614807} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614810 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614808} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614807} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614811 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614808} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614807} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614813 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614813} + m_MasterData: + m_Owner: {fileID: 8926484042661614806} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0.85 + m_Space: -1 + m_Property: + name: DirectionBlend + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614814 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614814} + m_MasterData: + m_Owner: {fileID: 8926484042661614806} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614818 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614818} + m_MasterData: + m_Owner: {fileID: 8926484042661614806} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 4.8 + m_Space: -1 + m_Property: + name: MinSpeed + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614819 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614819} + m_MasterData: + m_Owner: {fileID: 8926484042661614806} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 7.5 + m_Space: -1 + m_Property: + name: MaxSpeed + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614820 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e5dce54ae3368c042b26ab1f305e15b2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614662} + m_Children: [] + m_UIPosition: {x: 0, y: 2} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614821} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614826} +--- !u!114 &8926484042661614821 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a9f9544b71b7dab44a4644b6807e8bf6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614822} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614821} + m_MasterData: + m_Owner: {fileID: 8926484042661614820} + m_Value: + m_Type: + m_SerializableType: UnityEditor.VFX.Vector, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"vector":{"x":0.0,"y":-9.8100004196167,"z":0.0}}' + m_Space: 1 + m_Property: + name: Force + m_serializedType: + m_SerializableType: UnityEditor.VFX.Vector, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614822 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614821} + m_Children: + - {fileID: 8926484042661614823} + - {fileID: 8926484042661614824} + - {fileID: 8926484042661614825} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614821} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: vector + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614823 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614822} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614821} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614824 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614822} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614821} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614825 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614822} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614821} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614826 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614826} + m_MasterData: + m_Owner: {fileID: 8926484042661614820} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: False + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614827 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b294673e879f9cf449cc9de536818ea9, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614662} + m_Children: [] + m_UIPosition: {x: 0, y: 77} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614828} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614829} + UseParticleSize: 0 +--- !u!114 &8926484042661614828 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614828} + m_MasterData: + m_Owner: {fileID: 8926484042661614827} + m_Value: + m_Type: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: 0.5 + m_Space: -1 + m_Property: + name: dragCoefficient + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614829 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614829} + m_MasterData: + m_Owner: {fileID: 8926484042661614827} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614830 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 01ec2c1930009b04ea08905b47262415, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614681} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614831} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614832} + attribute: size + Composition: 2 + AlphaComposition: 0 + SampleMode: 0 + Mode: 1 + ColorMode: 3 + channels: 6 +--- !u!114 &8926484042661614831 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c117b74c5c58db542bffe25c78fe92db, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614831} + m_MasterData: + m_Owner: {fileID: 8926484042661614830} + m_Value: + m_Type: + m_SerializableType: UnityEngine.AnimationCurve, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"frames":[{"time":0.0,"value":0.75,"inTangent":0.0,"outTangent":1.25,"tangentMode":0,"leftTangentMode":2,"rightTangentMode":2,"broken":true},{"time":1.0,"value":2.0,"inTangent":1.25,"outTangent":2.0,"tangentMode":0,"leftTangentMode":2,"rightTangentMode":2,"broken":true}],"preWrapMode":8,"postWrapMode":8,"version":1}' + m_Space: -1 + m_Property: + name: Size + m_serializedType: + m_SerializableType: UnityEngine.AnimationCurve, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614832 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614832} + m_MasterData: + m_Owner: {fileID: 8926484042661614830} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614833 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 388ad3b1dc9c6ae45b630f914fab638f, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 +--- !u!114 &8926484042661614834 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fb1f6794ace8b0c4592af9c5604cddbf, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614613} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 0 + m_UISuperCollapsed: 0 + m_InputSlots: + - {fileID: 8926484042661614871} + m_OutputSlots: [] + m_Disabled: 0 + m_ActivationSlot: {fileID: 8926484042661614852} + compositionPosition: 0 + compositionAxes: 0 + compositionDirection: 0 + positionMode: 1 + spawnMode: 0 + shape: 0 + heightMode: 1 + applyOrientation: 1 + killOutliers: 0 + projectionSteps: 2 +--- !u!114 &8926484042661614852 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b4c11ff25089a324daf359f4b0629b33, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614852} + m_MasterData: + m_Owner: {fileID: 8926484042661614834} + m_Value: + m_Type: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_SerializableObject: True + m_Space: -1 + m_Property: + name: _vfx_enabled + m_serializedType: + m_SerializableType: System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614871 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlot + m_UIIgnoredErrors: [] + m_Parent: {fileID: 0} + m_Children: + - {fileID: 8926484042661614872} + - {fileID: 8926484042661614887} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 8926484042661614834} + m_Value: + m_Type: + m_SerializableType: UnityEditor.VFX.TArcSphere, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_SerializableObject: '{"sphere":{"transform":{"position":{"x":0.0,"y":0.0,"z":0.0},"angles":{"x":0.0,"y":0.0,"z":0.0},"scale":{"x":1.0,"y":1.0,"z":1.0}},"radius":1.0},"arc":6.2831854820251469}' + m_Space: 0 + m_Property: + name: arcSphere + m_serializedType: + m_SerializableType: UnityEditor.VFX.TArcSphere, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614872 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1b605c022ee79394a8a776c0869b3f9a, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlot + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614871} + m_Children: + - {fileID: 8926484042661614873} + - {fileID: 8926484042661614886} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: sphere + m_serializedType: + m_SerializableType: UnityEditor.VFX.TSphere, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614873 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3e3f628d80ffceb489beac74258f9cf7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotTransform + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614872} + m_Children: + - {fileID: 8926484042661614874} + - {fileID: 8926484042661614878} + - {fileID: 8926484042661614882} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: transform + m_serializedType: + m_SerializableType: UnityEditor.VFX.Transform, Unity.VisualEffectGraph.Editor, + Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614874 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat3 + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614873} + m_Children: + - {fileID: 8926484042661614875} + - {fileID: 8926484042661614876} + - {fileID: 8926484042661614877} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: position + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614875 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614874} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614876 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614874} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614877 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614874} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614878 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat3 + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614873} + m_Children: + - {fileID: 8926484042661614879} + - {fileID: 8926484042661614880} + - {fileID: 8926484042661614881} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: angles + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614879 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614878} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614880 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614878} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614881 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614878} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614882 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac39bd03fca81b849929b9c966f1836a, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat3 + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614873} + m_Children: + - {fileID: 8926484042661614883} + - {fileID: 8926484042661614884} + - {fileID: 8926484042661614885} + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: scale + m_serializedType: + m_SerializableType: UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, + Culture=neutral, PublicKeyToken=null + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614883 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614882} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: x + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614884 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614882} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: y + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614885 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614882} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: z + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614886 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614872} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: radius + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] +--- !u!114 &8926484042661614887 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f780aa281814f9842a7c076d436932e7, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.VisualEffectGraph.Editor::UnityEditor.VFX.VFXSlotFloat + m_UIIgnoredErrors: [] + m_Parent: {fileID: 8926484042661614871} + m_Children: [] + m_UIPosition: {x: 0, y: 0} + m_UICollapsed: 1 + m_UISuperCollapsed: 0 + m_MasterSlot: {fileID: 8926484042661614871} + m_MasterData: + m_Owner: {fileID: 0} + m_Value: + m_Type: + m_SerializableType: + m_SerializableObject: + m_Space: -1 + m_Property: + name: arc + m_serializedType: + m_SerializableType: System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + m_Direction: 0 + m_LinkedSlots: [] diff --git a/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta b/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta new file mode 100644 index 0000000..b32e89c --- /dev/null +++ b/Assets/_Project/Art/VFX/spells/VFX_slowarea.vfx.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: 397a5bed36b1e63a0a3eef17b04f65bd +VisualEffectImporter: + externalObjects: {} + serializedVersion: 2 + template: + name: + category: + description: + icon: {instanceID: 0} + thumbnail: {instanceID: 0} + useAsTemplate: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset index 5f45c46..d78d1f8 100644 --- a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset +++ b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset @@ -22,7 +22,7 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 1024 impactVfxPrefab: {fileID: 158073311046191680, guid: 80eaad6d0b024835482b64625b63053c, type: 3} - impactVfxLifetime: 2 + impactVfxLifetime: 3 impactSound: clip: {fileID: 8300000, guid: 4ee1b63f27ea04451802bafd35ecef89, type: 3} volume: 0.5 diff --git a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset b/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset index 74694ff..d6f043a 100644 --- a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset +++ b/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset @@ -16,10 +16,16 @@ MonoBehaviour: Description: Slows enemies in an area Icon: {fileID: 0} Cooldown: 5 - TargetType: 0 + TargetType: 1 Radius: 5 enemyLayerMask: serializedVersion: 2 m_Bits: 1024 + areaVfxPrefab: {fileID: 1462673130280185047, guid: bf2f1f2a9a54e9162b80673e3f7eeaf6, type: 3} + areaSound: + clip: {fileID: 0} + volume: 0 + minPitch: 0 + maxPitch: 0 SlowFactor: 0.5 EffectDuration: 3 diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs index 4bee6bd..b992845 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs @@ -1,5 +1,6 @@ // Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs using UnityEngine; +using TD.Audio; using TD.Core; namespace TD.Gameplay.BuilderSpells @@ -19,6 +20,15 @@ namespace TD.Gameplay.BuilderSpells { public override BuilderSpellKind Kind => BuilderSpellKind.SlowArea; + [Header("Area VFX")] + [Tooltip("Prefab spawned at the target point on a successful cast, authored at a 1-unit " + + "radius — scaled up to match Radius here. Lives for EffectDuration, matching " + + "how long the slow itself lasts. Optional — leave empty for no visual.")] + [SerializeField] private GameObject areaVfxPrefab; + + [Tooltip("Sound played on every peer when this spell resolves successfully.")] + [SerializeField] private SoundConfig areaSound; + [Header("Slow Area")] [Tooltip("Speed multiplier applied to affected enemies for EffectDuration " + "(e.g. 0.5 = half speed).")] @@ -51,5 +61,19 @@ namespace TD.Gameplay.BuilderSpells return hitAny; } + + public override void ClientPlayVfx(Vector3 targetPoint) + { + if (areaVfxPrefab != null) + { + var instance = Instantiate(areaVfxPrefab, targetPoint, Quaternion.identity); + instance.transform.localScale *= Mathf.Max(Radius, 0.01f); + Destroy(instance, EffectDuration); + } + + if (areaSound.clip != null) + AudioManager.Instance?.Play(areaSound.clip, AudioCategory.Combat, + areaSound.RandomPitch(), areaSound.volume); + } } } From a33d951abd4f2c59acab81b62c9655c1657d532b Mon Sep 17 00:00:00 2001 From: Matt F Date: Sat, 18 Jul 2026 18:12:56 -0700 Subject: [PATCH 10/33] Updates to spells, HUD, Gold, and Camera Controls. New sound effects! --- Assets/_Project/Art/Sprites/Spells.meta | 8 ++ .../Art/Sprites/Spells/FireballSpell.png | 3 + .../Art/Sprites/Spells/FireballSpell.png.meta | 117 ++++++++++++++++++ .../_Project/Art/Sprites/Spells/SlowSpell.png | 3 + .../Art/Sprites/Spells/SlowSpell.png.meta | 117 ++++++++++++++++++ .../Audio/Sound Effects/FireballExplosion.ogg | 3 + .../Sound Effects/FireballExplosion.ogg.meta | 23 ++++ .../_Project/Audio/Sound Effects/TimeSlow.ogg | 3 + .../Audio/Sound Effects/TimeSlow.ogg.meta | 23 ++++ .../BuilderSpells/FireballSpell.asset | 13 +- .../BuilderSpells/SlowAreaSpell.asset | 14 +-- Assets/_Project/Definitions/GoldConfig.asset | 24 ++-- .../Gameplay/BuilderInputController.cs | 19 ++- .../Gameplay/BuilderSpellCastController.cs | 39 ++++++ .../BuilderSpells/BuilderSpellDefinition.cs | 31 ++++- .../BuilderSpells/BuilderSpellPool.cs | 3 +- .../BuilderSpells/FireballSpellDefinition.cs | 15 ++- .../BuilderSpells/SlowAreaSpellDefinition.cs | 6 +- .../Scripts/Gameplay/CameraController.cs | 15 +-- .../Gameplay/Draft/BuilderSpellDraftOption.cs | 9 ++ .../Scripts/Gameplay/Draft/DraftOption.cs | 12 +- .../Gameplay/Draft/NewTowerDraftOption.cs | 4 + .../Scripts/Gameplay/PlayerSpellLoadout.cs | 69 +++++++++-- Assets/_Project/Scripts/UI/HUDController.cs | 58 +++++++-- Assets/_Project/UI/HUD.uss | 7 +- Assets/_Project/UI/HUD.uxml | 2 +- Assets/_Project/UI/HUDPanelSettings.asset | 6 +- 27 files changed, 578 insertions(+), 68 deletions(-) create mode 100644 Assets/_Project/Art/Sprites/Spells.meta create mode 100644 Assets/_Project/Art/Sprites/Spells/FireballSpell.png create mode 100644 Assets/_Project/Art/Sprites/Spells/FireballSpell.png.meta create mode 100644 Assets/_Project/Art/Sprites/Spells/SlowSpell.png create mode 100644 Assets/_Project/Art/Sprites/Spells/SlowSpell.png.meta create mode 100644 Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg create mode 100644 Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg.meta create mode 100644 Assets/_Project/Audio/Sound Effects/TimeSlow.ogg create mode 100644 Assets/_Project/Audio/Sound Effects/TimeSlow.ogg.meta diff --git a/Assets/_Project/Art/Sprites/Spells.meta b/Assets/_Project/Art/Sprites/Spells.meta new file mode 100644 index 0000000..599da31 --- /dev/null +++ b/Assets/_Project/Art/Sprites/Spells.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b086eebc9f3f87543bf2c98de8c8e4af +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/Spells/FireballSpell.png b/Assets/_Project/Art/Sprites/Spells/FireballSpell.png new file mode 100644 index 0000000..6c62964 --- /dev/null +++ b/Assets/_Project/Art/Sprites/Spells/FireballSpell.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c58fd337b19c098a34a4eb7730e87fad72ec3b4819665e00535676b008348146 +size 177456 diff --git a/Assets/_Project/Art/Sprites/Spells/FireballSpell.png.meta b/Assets/_Project/Art/Sprites/Spells/FireballSpell.png.meta new file mode 100644 index 0000000..25bac7d --- /dev/null +++ b/Assets/_Project/Art/Sprites/Spells/FireballSpell.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: eff45e5e3dab24f438c054a095d34578 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Art/Sprites/Spells/SlowSpell.png b/Assets/_Project/Art/Sprites/Spells/SlowSpell.png new file mode 100644 index 0000000..9f0cdef --- /dev/null +++ b/Assets/_Project/Art/Sprites/Spells/SlowSpell.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d54e2ec41954205c8775d2c6f09e6a134e8a960a797394c6e01ce67daebc840 +size 357045 diff --git a/Assets/_Project/Art/Sprites/Spells/SlowSpell.png.meta b/Assets/_Project/Art/Sprites/Spells/SlowSpell.png.meta new file mode 100644 index 0000000..98e89b4 --- /dev/null +++ b/Assets/_Project/Art/Sprites/Spells/SlowSpell.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 5f5072d8c9f626c4690a7b231c7488f9 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg b/Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg new file mode 100644 index 0000000..77a3f9b --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2263f258fb816411ff3c118c796cf622bf8327c597c2037f628d5b7dee32ab2a +size 54249 diff --git a/Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg.meta b/Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg.meta new file mode 100644 index 0000000..e3b4013 --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects/FireballExplosion.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: e54448243d0478045b6566412c54e4a7 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Audio/Sound Effects/TimeSlow.ogg b/Assets/_Project/Audio/Sound Effects/TimeSlow.ogg new file mode 100644 index 0000000..6540f44 --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects/TimeSlow.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4d6c70f74ae50b15bcbcf1b53cdf63f521f671b119aa6c32ea9a41c9e07e563 +size 30845 diff --git a/Assets/_Project/Audio/Sound Effects/TimeSlow.ogg.meta b/Assets/_Project/Audio/Sound Effects/TimeSlow.ogg.meta new file mode 100644 index 0000000..fe80db5 --- /dev/null +++ b/Assets/_Project/Audio/Sound Effects/TimeSlow.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 038ff3eab9aa0034bac26ccb648ef2a1 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset index d78d1f8..b63d958 100644 --- a/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset +++ b/Assets/_Project/Definitions/BuilderSpells/FireballSpell.asset @@ -14,18 +14,19 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpells.FireballSpellDefinition DisplayName: Fireball Description: Shoot a fireball - Icon: {fileID: 0} - Cooldown: 5 + Icon: {fileID: 21300000, guid: eff45e5e3dab24f438c054a095d34578, type: 3} + Cooldown: 1 TargetType: 0 - Radius: 3 + Radius: 5 enemyLayerMask: serializedVersion: 2 m_Bits: 1024 impactVfxPrefab: {fileID: 158073311046191680, guid: 80eaad6d0b024835482b64625b63053c, type: 3} impactVfxLifetime: 3 + impactDelay: 0.9 impactSound: - clip: {fileID: 8300000, guid: 4ee1b63f27ea04451802bafd35ecef89, type: 3} - volume: 0.5 + clip: {fileID: 8300000, guid: e54448243d0478045b6566412c54e4a7, type: 3} + volume: 0.603 minPitch: 1.048 maxPitch: 0.969 - Damage: 50 + Damage: 500 diff --git a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset b/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset index d6f043a..e2550d2 100644 --- a/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset +++ b/Assets/_Project/Definitions/BuilderSpells/SlowAreaSpell.asset @@ -14,8 +14,8 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::TD.Gameplay.BuilderSpells.SlowAreaSpellDefinition DisplayName: Slow Area Description: Slows enemies in an area - Icon: {fileID: 0} - Cooldown: 5 + Icon: {fileID: 21300000, guid: 5f5072d8c9f626c4690a7b231c7488f9, type: 3} + Cooldown: 10 TargetType: 1 Radius: 5 enemyLayerMask: @@ -23,9 +23,9 @@ MonoBehaviour: m_Bits: 1024 areaVfxPrefab: {fileID: 1462673130280185047, guid: bf2f1f2a9a54e9162b80673e3f7eeaf6, type: 3} areaSound: - clip: {fileID: 0} - volume: 0 - minPitch: 0 - maxPitch: 0 + clip: {fileID: 8300000, guid: 038ff3eab9aa0034bac26ccb648ef2a1, type: 3} + volume: 0.632 + minPitch: 1.14 + maxPitch: 0.96 SlowFactor: 0.5 - EffectDuration: 3 + EffectDuration: 8 diff --git a/Assets/_Project/Definitions/GoldConfig.asset b/Assets/_Project/Definitions/GoldConfig.asset index 58f29f6..abf9261 100644 --- a/Assets/_Project/Definitions/GoldConfig.asset +++ b/Assets/_Project/Definitions/GoldConfig.asset @@ -17,44 +17,40 @@ MonoBehaviour: - Wave: {fileID: 11400000, guid: 65f66289ea1233b4897f46cd997d9c7a, type: 2} GoldPerEnemy: 5 CompletionBonus: 25 - NoLeaksBonus: 50 + NoLeaksBonus: 10 - Wave: {fileID: 11400000, guid: 190e39db44aa0794aa808fd60976f7c4, type: 2} GoldPerEnemy: 7 CompletionBonus: 30 - NoLeaksBonus: 50 + NoLeaksBonus: 10 - Wave: {fileID: 11400000, guid: 39921b44a1a0a56478200028940c5202, type: 2} GoldPerEnemy: 10 CompletionBonus: 35 - NoLeaksBonus: 50 + NoLeaksBonus: 10 - Wave: {fileID: 11400000, guid: 50f498bc5bfc46e44b064cc96403e2cb, type: 2} GoldPerEnemy: 15 CompletionBonus: 40 - NoLeaksBonus: 50 + NoLeaksBonus: 10 - Wave: {fileID: 11400000, guid: 9ee6dee12f0660844b4d46880f01c02f, type: 2} GoldPerEnemy: 15 CompletionBonus: 45 - NoLeaksBonus: 50 + NoLeaksBonus: 10 - Wave: {fileID: 11400000, guid: 41231de63e8f25d448f19f3816e0c22f, type: 2} GoldPerEnemy: 20 CompletionBonus: 50 - NoLeaksBonus: 100 + NoLeaksBonus: 10 - Wave: {fileID: 11400000, guid: 6290df178cbd3144aa92a0f09833a7be, type: 2} GoldPerEnemy: 20 CompletionBonus: 55 - NoLeaksBonus: 100 + NoLeaksBonus: 20 - Wave: {fileID: 11400000, guid: 86736fd52c18fa84e8ced40f30b514fa, type: 2} GoldPerEnemy: 25 CompletionBonus: 60 - NoLeaksBonus: 100 + NoLeaksBonus: 20 - Wave: {fileID: 11400000, guid: 8fdf53cfc405a5f41a00f376198b8d84, type: 2} GoldPerEnemy: 25 CompletionBonus: 65 - NoLeaksBonus: 100 + NoLeaksBonus: 20 - Wave: {fileID: 11400000, guid: 4db677d2940202340841471f90a5b73a, type: 2} GoldPerEnemy: 25 CompletionBonus: 70 - NoLeaksBonus: 100 - - Wave: {fileID: 11400000, guid: fc1a55fab4ce81047b4925f53a3a8b8d, type: 2} - GoldPerEnemy: 50 - CompletionBonus: 75 - NoLeaksBonus: 500 + NoLeaksBonus: 20 diff --git a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs index 72bd7c3..23a1c05 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs @@ -85,6 +85,7 @@ namespace TD.Gameplay // Cached reference to the local TowerPaintController, looked up lazily (same // rationale as the placement controller). private TowerPaintController cachedPaintController; + private BuilderSpellCastController cachedSpellCastController; // ----- Lifecycle -------------------------------------------------- @@ -120,7 +121,7 @@ namespace TD.Gameplay // Placement and paint are both modal: while either is active, the local // controller for that mode owns left-/right-click, so selection here yields. - bool isModal = IsLocalPlayerPlacing() || IsLocalPlayerPainting(); + bool isModal = IsLocalPlayerPlacing() || IsLocalPlayerPainting() || IsLocalPlayerAimingSpell(); Vector2 mousePos = mouse.position.ReadValue(); // UI Toolkit dispatches button click events AFTER Update runs, but raw mouse @@ -292,5 +293,21 @@ namespace TD.Gameplay } return cachedPaintController.IsPainting; } + + private bool IsLocalPlayerAimingSpell() + { + if (cachedSpellCastController == null) + { + // Find lazily — controller may have been added after this component spawned. + cachedSpellCastController = + UnityEngine.Object.FindAnyObjectByType(); + if (cachedSpellCastController == null) return false; + } + // IsAiming covers "aiming, click not yet made"; ConsumedCastClickThisFrame covers the + // frame the confirming click casts and exits aim mode — together they suppress the + // selection click regardless of Update order between the two controllers. + return cachedSpellCastController.IsAiming + || cachedSpellCastController.ConsumedCastClickThisFrame; + } } } \ No newline at end of file diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs index 49160da..745ebe8 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs @@ -56,6 +56,21 @@ namespace TD.Gameplay // -1 when not aiming. private int activeSlot = -1; + + // Frame on which the confirming cast click was consumed. Lets the selection controller + // ignore that click order-independently — see ConsumedCastClickThisFrame. + private int lastCastClickFrame = -1; + + /// True while a spell is being aimed (awaiting the confirming click). The + /// selection input controller treats this as a modal state, so the click that confirms + /// the cast doesn't also fall through to selection and deselect the builder. + public bool IsAiming => activeSlot >= 0; + + /// True during the frame the confirming cast click was consumed. Aim mode exits + /// the same frame the cast is submitted, flipping false; this stays + /// true for the rest of that frame so the selection controller ignores the click no matter + /// which controller's Update ran first. + public bool ConsumedCastClickThisFrame => lastCastClickFrame == Time.frameCount; private BuilderSpellDefinition activeDefinition; private bool lastHitValid; @@ -85,6 +100,14 @@ namespace TD.Gameplay if (activeSlot < 0) return; // idle — nothing to aim + // Deselecting the builder mid-aim cancels the cast, so you can't start aiming while + // selected and then deselect to sneak a cast past the gate above. + if (!LocalBuilderSelected()) + { + ExitAimMode(); + return; + } + var keyboard = Keyboard.current; if (keyboard != null && keyboard.escapeKey.wasPressedThisFrame) { @@ -115,16 +138,32 @@ namespace TD.Gameplay if (mouse.leftButton.wasPressedThisFrame && lastHitValid) { + // Record the frame so the selection controller ignores this click even though + // TrySubmitCast exits aim mode this same frame (IsAiming flips false). Without + // this, whether the click also deselected the builder depended on Update order. + lastCastClickFrame = Time.frameCount; TrySubmitCast(); } } // ----- Hotkey scan -------------------------------------------------- + // True when the local player's own builder is the current selection. Casting is gated + // on this so it matches the spell HUD (shown only for the selected builder). + private static bool LocalBuilderSelected() + { + var selected = SelectionState.Instance?.SelectedObject; + return selected is Builder builder && builder.IsOwner; + } + private void ScanHotkeys() { if (activeSlot >= 0) return; // already aiming — hotkeys re-scanned only when idle + // Spells cast only while the local player's OWN builder is selected — keeps casting + // in sync with the spell HUD, which is shown only for the selected builder. + if (!LocalBuilderSelected()) return; + var loadout = PlayerSpellLoadout.Local; if (loadout == null) return; diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs index e1ca3b2..2bf7c9e 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellDefinition.cs @@ -24,8 +24,9 @@ namespace TD.Gameplay.BuilderSpells /// Server-only resolution, client-only visual. runs on /// the server and applies damage/status via the same Physics.OverlapSphereNonAlloc + /// EnemyHealth/EnemyStatus pattern TowerCombat already uses. - /// runs on every peer (including the server) after a successful - /// cast, purely for presentation. + /// Presentation is split into (on cast) and + /// (on contact, seconds later for a + /// projectile spell), both running on every peer including the server. /// public abstract class BuilderSpellDefinition : ScriptableObject { @@ -82,10 +83,28 @@ namespace TD.Gameplay.BuilderSpells public abstract bool ServerCast(ulong clientId, Vector3 targetPoint); /// - /// Runs on every peer (via 's ClientRpc) after a - /// successful . Default no-op; override to spawn an impact VFX - /// prefab and self-destroy it, the same idiom used elsewhere for one-off visuals. + /// Seconds between the cast and the effect landing. 0 = instant: damage and the impact + /// sound resolve immediately on cast. A projectile-style spell (e.g. the Fireball meteor) + /// overrides this with its fall/travel time, so spawns the + /// visual on cast but holds (damage) and + /// (sound) until the projectile reaches the ground. Set it to match the VFX's fall time. /// - public virtual void ClientPlayVfx(Vector3 targetPoint) { } + public virtual float ImpactDelay => 0f; + + /// + /// Runs on every peer (via 's ClientRpc) the moment the + /// spell is cast. Spawns the visual: for an instant spell that's the whole effect; for a + /// delayed spell it's the projectile/travel visual that lands after . + /// Default no-op. + /// + public virtual void ClientSpawnVfx(Vector3 targetPoint) { } + + /// + /// Runs on every peer when the spell makes contact — immediately for an instant spell, or + /// seconds after cast for a delayed one. Play the impact sound + /// (and any impact-moment visual) here so it lands with the effect, not the throw. + /// Default no-op. + /// + public virtual void ClientPlayImpact(Vector3 targetPoint) { } } } diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs index 2f44df6..1327be9 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpells/BuilderSpellPool.cs @@ -14,7 +14,8 @@ namespace TD.Gameplay.BuilderSpells /// /// Plain MonoBehaviour: identical on every peer (same assets), so there is nothing to sync. /// The server reads it to resolve casts; clients read it to resolve and to render the cast hotbar. Mirrors + /// cref="BuilderSpellDefinition.ClientSpawnVfx"/> / and to render the cast hotbar. Mirrors /// exactly. /// public class BuilderSpellPool : MonoBehaviour diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs index 5f34a1c..b4917ca 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpells/FireballSpellDefinition.cs @@ -28,6 +28,14 @@ namespace TD.Gameplay.BuilderSpells [Min(0f)] [SerializeField] private float impactVfxLifetime = 2f; + [Tooltip("Seconds from cast until the falling fireball reaches the ground. Damage and the " + + "impact sound are held until then so they land with the visual — SET THIS TO MATCH " + + "the meteor VFX's fall time. 0 = everything resolves instantly on cast.")] + [Min(0f)] + [SerializeField] private float impactDelay = 0.8f; + + public override float ImpactDelay => impactDelay; + [Header("Impact Sound")] [Tooltip("Sound played on every peer when this spell resolves successfully. Same " + "SoundConfig struct TowerBuiltSound uses — reuse a tower's clip directly if " + @@ -59,11 +67,16 @@ namespace TD.Gameplay.BuilderSpells return hitAny; } - public override void ClientPlayVfx(Vector3 targetPoint) + public override void ClientSpawnVfx(Vector3 targetPoint) { + // The meteor VFX plays its full fall-and-crash animation from here; it reaches the + // ground after ImpactDelay, which is when ClientPlayImpact and ServerCast fire. if (impactVfxPrefab != null) Destroy(Instantiate(impactVfxPrefab, targetPoint, Quaternion.identity), impactVfxLifetime); + } + public override void ClientPlayImpact(Vector3 targetPoint) + { if (impactSound.clip != null) AudioManager.Instance?.Play(impactSound.clip, AudioCategory.Combat, impactSound.RandomPitch(), impactSound.volume); diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs index b992845..bd4cd8b 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaSpellDefinition.cs @@ -62,7 +62,7 @@ namespace TD.Gameplay.BuilderSpells return hitAny; } - public override void ClientPlayVfx(Vector3 targetPoint) + public override void ClientSpawnVfx(Vector3 targetPoint) { if (areaVfxPrefab != null) { @@ -70,7 +70,11 @@ namespace TD.Gameplay.BuilderSpells instance.transform.localScale *= Mathf.Max(Radius, 0.01f); Destroy(instance, EffectDuration); } + } + public override void ClientPlayImpact(Vector3 targetPoint) + { + // Instant spell (ImpactDelay = 0), so this fires on cast alongside ClientSpawnVfx. if (areaSound.clip != null) AudioManager.Instance?.Play(areaSound.clip, AudioCategory.Combat, areaSound.RandomPitch(), areaSound.volume); diff --git a/Assets/_Project/Scripts/Gameplay/CameraController.cs b/Assets/_Project/Scripts/Gameplay/CameraController.cs index b80f33e..bd071d6 100644 --- a/Assets/_Project/Scripts/Gameplay/CameraController.cs +++ b/Assets/_Project/Scripts/Gameplay/CameraController.cs @@ -227,16 +227,17 @@ namespace TD.Gameplay { Vector2 dir = Vector2.zero; - // Keyboard: WASD + arrow keys. Suppressed entirely while the player - // is typing — pressing 'a' or 'w' into chat should not pan the camera. - // (Edge-pan below stays active since it's mouse-driven.) + // Keyboard: arrow keys only. WASD is reserved for tower-build hotkeys (the command + // grid) — camera panning is arrow keys plus the mouse edge-pan below. Suppressed + // entirely while the player is typing so arrow keys in chat navigate text instead of + // panning. (Edge-pan below stays active since it's mouse-driven.) var kb = HUDController.IsTextInputActive ? null : Keyboard.current; if (kb != null) { - if (kb.aKey.isPressed || kb.leftArrowKey.isPressed) dir.x -= 1f; - if (kb.dKey.isPressed || kb.rightArrowKey.isPressed) dir.x += 1f; - if (kb.sKey.isPressed || kb.downArrowKey.isPressed) dir.y -= 1f; - if (kb.wKey.isPressed || kb.upArrowKey.isPressed) dir.y += 1f; + if (kb.leftArrowKey.isPressed) dir.x -= 1f; + if (kb.rightArrowKey.isPressed) dir.x += 1f; + if (kb.downArrowKey.isPressed) dir.y -= 1f; + if (kb.upArrowKey.isPressed) dir.y += 1f; } // Edge-pan: mouse near screen edge adds to keyboard direction. diff --git a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs index 416fc03..7582ea2 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/BuilderSpellDraftOption.cs @@ -37,5 +37,14 @@ namespace TD.Gameplay.Draft var loadout = PlayerSpellLoadout.GetForClient(clientId); return loadout != null && loadout.ServerGrantSpell(Kind); } + + /// Inherits the granted spell's icon (resolved from the pool by + /// ) unless this option assigns an override. + public override Sprite ResolveIcon() + { + if (Icon != null) return Icon; + var def = BuilderSpellPool.Instance != null ? BuilderSpellPool.Instance.Get(Kind) : null; + return def != null ? def.Icon : null; + } } } diff --git a/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs index 8ae8e94..c098caf 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/DraftOption.cs @@ -34,9 +34,19 @@ namespace TD.Gameplay.Draft [TextArea(2, 4)] public string Description; - [Tooltip("Icon shown on the draft card. Optional for placeholder content.")] + [Tooltip("OPTIONAL override for the draft card icon. Leave empty to inherit the icon of " + + "the item this option grants (its tower / spell); assign one only when you want " + + "to override that inherited icon.")] public Sprite Icon; + /// + /// The icon actually shown on the draft card. Returns the explicit + /// override when one is assigned; otherwise subclasses fall back to the icon of the item + /// they grant (tower, spell). The base class has no referenced item, so it just returns + /// (which may be null). + /// + public virtual Sprite ResolveIcon() => Icon; + [Header("Generation")] [Tooltip("Relative draw weight. Higher = offered more often. Rarer rewards use " + "lower weights. Must be > 0.")] diff --git a/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs b/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs index aab2a98..e7af9f6 100644 --- a/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs +++ b/Assets/_Project/Scripts/Gameplay/Draft/NewTowerDraftOption.cs @@ -48,5 +48,9 @@ namespace TD.Gameplay.Draft return deck.ServerGrantTower(typeId); } + + /// Inherits the granted tower's icon unless this option assigns an override. + public override Sprite ResolveIcon() + => Icon != null ? Icon : (Tower != null ? Tower.Icon : null); } } diff --git a/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs b/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs index a6a1f68..ef994bb 100644 --- a/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs +++ b/Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs @@ -1,4 +1,5 @@ // Assets/_Project/Scripts/Gameplay/PlayerSpellLoadout.cs +using System.Collections; using System.Collections.Generic; using Unity.Netcode; using UnityEngine; @@ -20,9 +21,12 @@ namespace TD.Gameplay /// slot index and an aimed world point. The server re-validates everything (slot exists, /// off cooldown, ) since client-side checks in /// are UX-only, resolves the - /// via , and calls - /// . A successful cast starts the cooldown - /// and fires so every peer plays the same visual. + /// via . An instant + /// spell ( == 0) resolves on cast: a hit starts + /// the cooldown and fires ; a miss is a no-op. A delayed + /// spell (a projectile, e.g. the Fireball meteor) commits on the throw — cooldown + the falling + /// visual fire immediately — while its damage and impact sound are held until the projectile + /// lands seconds later. /// public class PlayerSpellLoadout : NetworkBehaviour { @@ -142,7 +146,7 @@ namespace TD.Gameplay /// at . All validation happens /// here on the server; the client only uses this to trigger an attempt. /// - [Rpc(SendTo.Server, RequireOwnership = true)] + [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] public void RequestCastSpellRpc(int slot, Vector3 targetPoint) { if (MatchState.Instance == null || MatchState.Instance.Phase != MatchPhase.Playing) @@ -160,18 +164,69 @@ namespace TD.Gameplay return; } - if (!definition.ServerCast(OwnerClientId, targetPoint)) return; + if (definition.ImpactDelay <= 0f) + { + // Instant spell (e.g. Slow Area): resolve on cast. A miss (hit nothing) is a no-op + // and does NOT start the cooldown — unchanged behavior. + if (!definition.ServerCast(OwnerClientId, targetPoint)) return; + StartCooldown(slot, definition); + PlayVfxClientRpc(slotValue.Kind, targetPoint); + } + else + { + // Delayed spell (e.g. the Fireball meteor): the projectile has to fall before it + // lands, so the cast is COMMITTED on the throw — cooldown starts and the falling + // visual spawns now — while damage and the impact sound wait until it hits the + // ground (ImpactDelay later). Enemies are re-scanned at impact, so movement during + // the fall resolves correctly. + StartCooldown(slot, definition); + PlayVfxClientRpc(slotValue.Kind, targetPoint); + StartCoroutine(ServerResolveImpactAfterDelay( + slotValue.Kind, OwnerClientId, targetPoint, definition.ImpactDelay)); + } + } + + // Server-only: stamp the slot's cooldown from the definition and replicate it. + private void StartCooldown(int slot, BuilderSpellDefinition definition) + { + var slotValue = spells[slot]; slotValue.CooldownEndServerTime = NetworkManager.ServerTime.Time + definition.Cooldown; spells[slot] = slotValue; + } - PlayVfxClientRpc(slotValue.Kind, targetPoint); + // Server-only: apply a delayed spell's effect once its projectile has landed. Re-resolves + // targets at impact — the enemy set may have shifted during the fall. + private IEnumerator ServerResolveImpactAfterDelay( + BuilderSpellKind kind, ulong clientId, Vector3 targetPoint, float delay) + { + yield return new WaitForSeconds(delay); + if (!IsServer) yield break; + BuilderSpellPool.Instance?.Get(kind)?.ServerCast(clientId, targetPoint); } [ClientRpc] private void PlayVfxClientRpc(BuilderSpellKind kind, Vector3 targetPoint) { - BuilderSpellPool.Instance?.Get(kind)?.ClientPlayVfx(targetPoint); + var def = BuilderSpellPool.Instance?.Get(kind); + if (def == null) return; + + def.ClientSpawnVfx(targetPoint); // spawn the (possibly falling) visual now + + if (def.ImpactDelay <= 0f) + def.ClientPlayImpact(targetPoint); + else + StartCoroutine(ClientPlayImpactAfterDelay(kind, targetPoint, def.ImpactDelay)); + } + + // Client-side: play the impact (sound + any contact visual) when the projectile lands. + // Timed locally off the same ImpactDelay so it stays in lockstep with this peer's own + // falling visual — no second RPC, no double latency. + private IEnumerator ClientPlayImpactAfterDelay( + BuilderSpellKind kind, Vector3 targetPoint, float delay) + { + yield return new WaitForSeconds(delay); + BuilderSpellPool.Instance?.Get(kind)?.ClientPlayImpact(targetPoint); } } } diff --git a/Assets/_Project/Scripts/UI/HUDController.cs b/Assets/_Project/Scripts/UI/HUDController.cs index 7d17387..03cb3b0 100644 --- a/Assets/_Project/Scripts/UI/HUDController.cs +++ b/Assets/_Project/Scripts/UI/HUDController.cs @@ -116,13 +116,17 @@ namespace TD.UI private bool draftSubscribed; private PlayerDraft subscribedDraft; - // Spell hotbar (bottom-ui Section 6). Frame is display:none while the local player + // Spell hotbar (bottom-ui Section 6). Frame is visibility:hidden (but still occupies + // its reserved width, so the centered command bar never shifts) while the local player // has no granted spells; rebuilt on grant (append-only, so this is rare). Cooldown // state changes continuously and has no change event, so it's polled every Update. private VisualElement spellHotbarFrame; private VisualElement spellHotbar; private bool spellLoadoutSubscribed; private PlayerSpellLoadout subscribedSpellLoadout; + // The loadout the hotbar is currently showing — the SELECTED builder's, or null when + // no builder is selected (hotbar hidden). Cooldown polling reads this. + private PlayerSpellLoadout displayedSpellLoadout; private readonly List spellSlotUis = new List(); private readonly struct SpellSlotUi @@ -419,9 +423,10 @@ namespace TD.UI title.style.marginBottom = 6; card.Add(title); - if (option.Icon != null) + var iconSprite = option.ResolveIcon(); + if (iconSprite != null) { - var img = new Image { sprite = option.Icon }; + var img = new Image { sprite = iconSprite }; img.style.width = 48; img.style.height = 48; img.style.marginBottom = 6; @@ -475,23 +480,41 @@ namespace TD.UI // ----- Spell hotbar ------------------------------------------------- - // Rebuilds the hotbar cells from the local player's current loadout. Called on - // OnLoadoutChanged (a new spell granted) — spells are append-only, so this is rare, - // not a per-frame concern. + // Rebuilds the hotbar cells for the SELECTED builder's loadout. Called on selection + // change and on OnLoadoutChanged (a new spell granted). Spells are append-only, so + // this is rare, not a per-frame concern. + // + // The hotbar follows selection: it shows the selected builder's spells and is removed + // entirely when no builder is selected (spells belong to the builder). While a builder + // IS selected, the frame keeps its reserved width (visibility toggle, not display) so + // granting a spell mid-selection doesn't reflow/shift the centered command bar. private void RebuildSpellHotbar() { if (spellHotbar == null) return; spellHotbar.Clear(); spellSlotUis.Clear(); - var loadout = PlayerSpellLoadout.Local; - int slotCount = loadout?.SlotCount ?? 0; + var loadout = GetSelectedBuilderLoadout(); + displayedSpellLoadout = loadout; if (spellHotbarFrame != null) - spellHotbarFrame.style.display = slotCount > 0 ? DisplayStyle.Flex : DisplayStyle.None; + { + if (loadout == null) + { + // No builder selected → remove the slot (the command grid is hidden too). + spellHotbarFrame.style.display = DisplayStyle.None; + return; + } + // Builder selected → keep the reserved slot in layout; toggle only visibility so + // a mid-selection spell grant doesn't jump the command bar. + spellHotbarFrame.style.display = DisplayStyle.Flex; + spellHotbarFrame.style.visibility = + loadout.SlotCount > 0 ? Visibility.Visible : Visibility.Hidden; + } if (loadout == null) return; + int slotCount = loadout.SlotCount; var layout = SpellHotkeys.Layout; for (int i = 0; i < slotCount; i++) { @@ -531,6 +554,17 @@ namespace TD.UI } } + // The loadout the spell hotbar should display: the currently-selected builder's + // (resolved via its owner, so it shows whichever builder is selected — normally the + // local player's), or null when the selection isn't a builder → hotbar hidden. + private PlayerSpellLoadout GetSelectedBuilderLoadout() + { + var selected = SelectionState.Instance?.SelectedObject; + if (selected is Builder builder) + return PlayerSpellLoadout.GetForClient(builder.OwnerClientId); + return null; + } + // Per-frame: dims each slot while on cooldown and shows the remaining whole seconds. // Cooldown has no change event (it advances continuously with server time), so this // has to be polled — cheap at hotbar scale (at most MaxSpellSlots cells). @@ -538,7 +572,7 @@ namespace TD.UI { if (spellSlotUis.Count == 0) return; - var loadout = PlayerSpellLoadout.Local; + var loadout = displayedSpellLoadout; if (loadout == null) return; for (int i = 0; i < spellSlotUis.Count; i++) @@ -1403,6 +1437,10 @@ namespace TD.UI // hides via PopulateGridForSelection when there are no actions. PopulateInfoPanel(selection); PopulateGridForSelection(selection); + + // Section 6 (spell hotbar) follows selection: show the selected builder's spells, + // hide entirely when the selection isn't a builder. + RebuildSpellHotbar(); } /// diff --git a/Assets/_Project/UI/HUD.uss b/Assets/_Project/UI/HUD.uss index 08f154b..34c2a1e 100644 --- a/Assets/_Project/UI/HUD.uss +++ b/Assets/_Project/UI/HUD.uss @@ -169,8 +169,11 @@ flex-shrink: 0; flex-direction: row; align-items: flex-end; /* short sections hug the bottom */ - justify-content: flex-start; - padding: 0 100px; /* margin on either side — the X regions */ + justify-content: center; /* keep the command bar centered at ANY resolution — the row + auto-centers, and re-centers symmetrically when the spell + hotbar appears/disappears */ + padding: 0; /* was 0 100px; reclaimed so a smaller reference resolution + (= bigger HUD) still fits the bar without clipping */ background-color: rgba(0, 0, 0, 0); } diff --git a/Assets/_Project/UI/HUD.uxml b/Assets/_Project/UI/HUD.uxml index f458a3b..d3164ce 100644 --- a/Assets/_Project/UI/HUD.uxml +++ b/Assets/_Project/UI/HUD.uxml @@ -76,7 +76,7 @@ - + /// + /// Volume is the authored scaled by the player's music slider + /// (). Unlike one-shot SFX, the track is + /// continuous, so this subscribes to and + /// re-applies live while the slider is dragged. + /// [RequireComponent(typeof(AudioSource))] public class MusicPlayer : MonoBehaviour { @@ -14,14 +20,36 @@ namespace TD.Audio [Range(0f, 1f)] [SerializeField] private float volume = 1f; + private AudioSource source; + + private void Awake() + { + source = GetComponent(); + } + + private void OnEnable() + { + AudioVolumeSettings.OnChanged += ApplyVolume; + } + + private void OnDisable() + { + AudioVolumeSettings.OnChanged -= ApplyVolume; + } + private void Start() { - var src = GetComponent(); - src.clip = clip; - src.volume = volume; - src.loop = true; - src.playOnAwake = false; - src.Play(); + source.clip = clip; + source.loop = true; + source.playOnAwake = false; + ApplyVolume(); + source.Play(); + } + + private void ApplyVolume() + { + if (source == null) return; + source.volume = volume * AudioVolumeSettings.MusicScalar; } } } diff --git a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs index 41eeee6..955f301 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderInputController.cs @@ -139,10 +139,11 @@ namespace TD.Gameplay // Escape: clear selection. Allowed during placement mode too — Escape never // means anything else here, and clearing selection during placement is fine. - // Suppressed while chat (or any HUD text field) has focus, since Escape there - // means "cancel typing" and should not also clear the unit selection. + // Suppressed while chat (or any HUD text field) has focus or the gear menu is + // open, since Escape there means "cancel typing" / "back out of the menu" and + // should not also clear the unit selection. if (keyboard != null && keyboard.escapeKey.wasPressedThisFrame - && !HUDController.IsTextInputActive) + && !HUDController.IsUiCapturingInput) { SelectionState.Instance?.Clear(); } @@ -153,7 +154,7 @@ namespace TD.Gameplay // Tab: select the builder, or (if already selected) recenter the camera on it. if (keyboard != null && keyboard.tabKey.wasPressedThisFrame - && !HUDController.IsTextInputActive) + && !HUDController.IsUiCapturingInput) { var selection = SelectionState.Instance; if (selection != null && selection.IsSelected(builder)) diff --git a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs b/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs index 745ebe8..557fe3d 100644 --- a/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs +++ b/Assets/_Project/Scripts/Gameplay/BuilderSpellCastController.cs @@ -95,7 +95,7 @@ namespace TD.Gameplay private void Update() { - if (!HUDController.IsTextInputActive) + if (!HUDController.IsUiCapturingInput) ScanHotkeys(); if (activeSlot < 0) return; // idle — nothing to aim diff --git a/Assets/_Project/Scripts/Gameplay/CameraController.cs b/Assets/_Project/Scripts/Gameplay/CameraController.cs index bd071d6..4a2009a 100644 --- a/Assets/_Project/Scripts/Gameplay/CameraController.cs +++ b/Assets/_Project/Scripts/Gameplay/CameraController.cs @@ -229,9 +229,10 @@ namespace TD.Gameplay // Keyboard: arrow keys only. WASD is reserved for tower-build hotkeys (the command // grid) — camera panning is arrow keys plus the mouse edge-pan below. Suppressed - // entirely while the player is typing so arrow keys in chat navigate text instead of - // panning. (Edge-pan below stays active since it's mouse-driven.) - var kb = HUDController.IsTextInputActive ? null : Keyboard.current; + // entirely while the player is typing (so arrow keys in chat navigate text instead + // of panning) or while the gear menu is open. Edge-pan below is mouse-driven and + // gated separately by the pointer-over-HUD check, which the menu overlay satisfies. + var kb = HUDController.IsUiCapturingInput ? null : Keyboard.current; if (kb != null) { if (kb.leftArrowKey.isPressed) dir.x -= 1f; diff --git a/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs b/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs index e6c52e0..05a1613 100644 --- a/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs +++ b/Assets/_Project/Scripts/Gameplay/TowerPaintController.cs @@ -73,10 +73,11 @@ namespace TD.Gameplay var keyboard = Keyboard.current; // Right-click or Escape exits paint mode. (Escape is ignored while a HUD text - // field has focus so it means "cancel typing" there, matching other systems.) + // field has focus or the gear menu is open, so it means "cancel typing" / + // "back out of the menu" there, matching other systems.) bool escape = keyboard != null && keyboard.escapeKey.wasPressedThisFrame - && !HUDController.IsTextInputActive; + && !HUDController.IsUiCapturingInput; if (mouse.rightButton.wasPressedThisFrame || escape) { CancelPaint(); diff --git a/Assets/_Project/Scripts/UI/GameMenuView.cs b/Assets/_Project/Scripts/UI/GameMenuView.cs new file mode 100644 index 0000000..7db20bd --- /dev/null +++ b/Assets/_Project/Scripts/UI/GameMenuView.cs @@ -0,0 +1,407 @@ +// Assets/_Project/Scripts/UI/GameMenuView.cs +using UnityEngine; +using UnityEngine.UIElements; +using TD.Audio; + +namespace TD.UI +{ + /// + /// The in-match menu: a gear button in the top-right of the HUD top bar plus a modal + /// overlay with two options — Return to Title Screen and Audio Settings. + /// + /// + /// Ownership. A plain class (not a MonoBehaviour), constructed by + /// and given the HUD's root element — same pattern as + /// MinimapView. Everything is built programmatically and appended last, so it + /// z-orders above the rest of the HUD with no extra UIDocument or PanelSettings. + /// + /// Modality. The overlay is full-screen with + /// , which both dims the match and makes + /// true everywhere — so clicks + /// can't reach towers or the ground underneath. HUDController also sets + /// while it's open, which gates keyboard-driven + /// gameplay (camera pan, hotkeys, Escape handlers). The match does not pause: + /// this is a multiplayer game and waves keep running. + /// + /// Pages. One panel, three swapped bodies: the option list, the audio mixer, + /// and a confirm step for leaving the match. Escape backs out one page at a time and + /// closes from the root page. + /// + public class GameMenuView + { + private enum Page { Root, Audio, ConfirmLeave } + + // ----- Wiring ----------------------------------------------------- + + private readonly System.Action onReturnToTitle; + + private readonly VisualElement overlay; + private readonly Label header; + private readonly VisualElement rootPage; + private readonly VisualElement audioPage; + private readonly VisualElement confirmPage; + + private readonly SliderInt musicSlider; + private readonly Label musicValue; + private readonly SliderInt sfxSlider; + private readonly Label sfxValue; + + private Page page = Page.Root; + + // ----- Public API ------------------------------------------------- + + public bool IsOpen { get; private set; } + + /// The HUD's rootVisualElement. The overlay is appended to it. + /// The top-bar "menu-button" from HUD.uxml. May be null + /// (Escape still works); the gear glyph is painted into it here. + /// Optional sprite for the gear. When null, the icon is drawn + /// procedurally so the button never depends on an art asset existing. + /// Invoked once the player confirms leaving the match. + public GameMenuView(VisualElement root, Button gearButton, Sprite gearIcon, + System.Action onReturnToTitle) + { + this.onReturnToTitle = onReturnToTitle; + + if (gearButton != null) + { + gearButton.text = string.Empty; + gearButton.Add(CreateGearIcon(gearIcon)); + gearButton.clicked += Toggle; + gearButton.tooltip = "Menu (Esc)"; + } + + // ----- Overlay + panel shell ---------------------------------- + + overlay = new VisualElement(); + overlay.style.position = Position.Absolute; + overlay.style.left = 0; + overlay.style.right = 0; + overlay.style.top = 0; + overlay.style.bottom = 0; + overlay.style.alignItems = Align.Center; + overlay.style.justifyContent = Justify.Center; + overlay.style.backgroundColor = new Color(0f, 0f, 0f, 0.55f); + overlay.style.display = DisplayStyle.None; + overlay.pickingMode = PickingMode.Position; + + var panel = new VisualElement(); + panel.style.minWidth = 360; + panel.style.paddingTop = panel.style.paddingBottom = 24; + panel.style.paddingLeft = panel.style.paddingRight = 32; + panel.style.backgroundColor = new Color(0.08f, 0.08f, 0.10f, 0.97f); + panel.style.borderTopWidth = panel.style.borderBottomWidth = + panel.style.borderLeftWidth = panel.style.borderRightWidth = 2; + var border = new Color(0.4f, 0.4f, 0.45f); + panel.style.borderTopColor = panel.style.borderBottomColor = + panel.style.borderLeftColor = panel.style.borderRightColor = border; + panel.style.alignItems = Align.Center; + overlay.Add(panel); + + header = new Label("Menu"); + header.style.fontSize = 24; + header.style.color = Color.white; + header.style.marginBottom = 18; + header.style.unityFontStyleAndWeight = FontStyle.Bold; + panel.Add(header); + + // ----- Page 1: option list ------------------------------------ + + rootPage = new VisualElement(); + rootPage.style.alignItems = Align.Center; + rootPage.Add(MakeMenuButton("Return to Title Screen", () => GoTo(Page.ConfirmLeave))); + rootPage.Add(MakeMenuButton("Audio Settings", () => GoTo(Page.Audio))); + rootPage.Add(MakeMenuButton("Resume", Close)); + panel.Add(rootPage); + + // ----- Page 2: audio mixer ------------------------------------ + + audioPage = new VisualElement(); + audioPage.style.alignItems = Align.Stretch; + audioPage.style.display = DisplayStyle.None; + + audioPage.Add(BuildVolumeRow("Music", AudioVolumeSettings.MusicVolume, + v => AudioVolumeSettings.MusicVolume = v, + out musicSlider, out musicValue)); + audioPage.Add(BuildVolumeRow("Sound Effects", AudioVolumeSettings.SfxVolume, + v => AudioVolumeSettings.SfxVolume = v, + out sfxSlider, out sfxValue)); + + var audioNote = new Label("Sound effects covers spells, towers, building, and enemies."); + audioNote.style.fontSize = 11; + audioNote.style.color = new Color(0.6f, 0.6f, 0.65f); + audioNote.style.marginTop = 4; + audioNote.style.marginBottom = 12; + audioNote.style.whiteSpace = WhiteSpace.Normal; + audioPage.Add(audioNote); + + var audioBack = MakeMenuButton("Back", () => GoTo(Page.Root)); + audioBack.style.alignSelf = Align.Center; + audioPage.Add(audioBack); + panel.Add(audioPage); + + // ----- Page 3: leave confirmation ----------------------------- + + confirmPage = new VisualElement(); + confirmPage.style.alignItems = Align.Center; + confirmPage.style.display = DisplayStyle.None; + + var confirmText = new Label("Leave the match and return to the title screen?"); + confirmText.style.color = new Color(0.88f, 0.88f, 0.9f); + confirmText.style.whiteSpace = WhiteSpace.Normal; + confirmText.style.marginBottom = 16; + confirmText.style.unityTextAlign = TextAnchor.MiddleCenter; + confirmPage.Add(confirmText); + + var confirmRow = new VisualElement(); + confirmRow.style.flexDirection = FlexDirection.Row; + confirmPage.Add(confirmRow); + + var leaveBtn = MakeMenuButton("Leave Match", ConfirmLeave); + leaveBtn.style.marginRight = 12; + leaveBtn.style.minWidth = 150; + confirmRow.Add(leaveBtn); + + var cancelBtn = MakeMenuButton("Cancel", () => GoTo(Page.Root)); + cancelBtn.style.minWidth = 150; + confirmRow.Add(cancelBtn); + panel.Add(confirmPage); + + root.Add(overlay); + } + + public void Open() + { + if (IsOpen) return; + IsOpen = true; + GoTo(Page.Root); + overlay.style.display = DisplayStyle.Flex; + } + + public void Close() + { + if (!IsOpen) return; + IsOpen = false; + overlay.style.display = DisplayStyle.None; + // Volume setters only touch the in-memory pref so a slider drag stays cheap; + // write it out now that the player is done adjusting. + AudioVolumeSettings.Flush(); + } + + public void Toggle() + { + if (IsOpen) Close(); + else Open(); + } + + /// + /// Escape while the menu is open: back out one page, or close from the root page. + /// + public void Back() + { + if (page == Page.Root) Close(); + else GoTo(Page.Root); + } + + // ----- Pages ------------------------------------------------------ + + private void GoTo(Page next) + { + page = next; + + rootPage.style.display = next == Page.Root ? DisplayStyle.Flex : DisplayStyle.None; + audioPage.style.display = next == Page.Audio ? DisplayStyle.Flex : DisplayStyle.None; + confirmPage.style.display = next == Page.ConfirmLeave ? DisplayStyle.Flex : DisplayStyle.None; + + header.text = next switch + { + Page.Audio => "Audio Settings", + Page.ConfirmLeave => "Leave Match", + _ => "Menu", + }; + + // Another surface could have changed the volumes since this page was last + // shown (a future title-screen mixer, a debug command). Re-sync on entry so + // the sliders never display a stale value. + if (next == Page.Audio) SyncSlidersFromSettings(); + } + + private void SyncSlidersFromSettings() + { + // SetValueWithoutNotify: writing the settings value back through the change + // callback would be a no-op today (the setter early-outs on an unchanged value) + // but it's the wrong direction of data flow, so don't. + musicSlider.SetValueWithoutNotify(AudioVolumeSettings.MusicVolume); + musicValue.text = AudioVolumeSettings.MusicVolume.ToString(); + sfxSlider.SetValueWithoutNotify(AudioVolumeSettings.SfxVolume); + sfxValue.text = AudioVolumeSettings.SfxVolume.ToString(); + } + + private void ConfirmLeave() + { + AudioVolumeSettings.Flush(); + IsOpen = false; + overlay.style.display = DisplayStyle.None; + onReturnToTitle?.Invoke(); + } + + // ----- Element builders ------------------------------------------- + + private static Button MakeMenuButton(string text, System.Action onClick) + { + var btn = new Button(() => onClick?.Invoke()) { text = text }; + btn.style.minWidth = 260; + btn.style.height = 40; + btn.style.fontSize = 16; + btn.style.marginBottom = 8; + return btn; + } + + // One mixer row: name, 0..100 slider, live numeric readout. + private static VisualElement BuildVolumeRow(string label, int initial, + System.Action onChange, + out SliderInt slider, out Label valueLabel) + { + var row = new VisualElement(); + row.style.flexDirection = FlexDirection.Row; + // FlexStart, not Center: the labels are aligned to the slider's track by + // AlignLabelsToTrack below, which needs every child's box to start at the same + // top edge. See that method for why centering the boxes isn't enough. + row.style.alignItems = Align.FlexStart; + row.style.marginBottom = 10; + + var name = new Label(label); + name.style.color = new Color(0.88f, 0.88f, 0.9f); + name.style.fontSize = 14; + name.style.width = 110; + name.style.flexShrink = 0; + name.style.unityTextAlign = TextAnchor.MiddleLeft; + row.Add(name); + + slider = new SliderInt(AudioVolumeSettings.MinVolume, AudioVolumeSettings.MaxVolume); + slider.style.width = 200; + slider.style.flexShrink = 0; + slider.SetValueWithoutNotify(initial); + row.Add(slider); + + // Fixed width + right-align so the slider doesn't shift as the number goes + // from 1 to 3 digits while dragging. + var value = new Label(initial.ToString()); + value.style.color = Color.white; + value.style.fontSize = 14; + value.style.width = 40; + value.style.flexShrink = 0; + value.style.unityTextAlign = TextAnchor.MiddleRight; + row.Add(value); + + AlignLabelsToTrack(row, slider, name, value); + + var captured = value; + slider.RegisterValueChangedCallback(evt => + { + captured.text = evt.newValue.ToString(); + onChange(evt.newValue); + }); + + valueLabel = value; + return row; + } + + // Vertically lines the row's text up with the groove the player actually sees. + // + // The default runtime theme gives a horizontal slider a box that's taller than its + // track and does NOT center the track inside it, so `align-items: center` on the row + // centers the *boxes* and leaves the text sitting well below the groove. The exact + // offset is a theme detail, so it's measured rather than hardcoded: with the row + // aligned FlexStart every child's box starts at the same top edge, so giving a label + // a height of twice the track's offset from that edge puts its vertically-centered + // text exactly on the track's center line. + // + // Runs on GeometryChangedEvent (not once at build time) because layout hasn't + // happened yet during construction, and because it needs to re-solve when the panel + // is rescaled or the menu is reopened at a different resolution. + private static void AlignLabelsToTrack(VisualElement row, SliderInt slider, + params Label[] labels) + { + // Align to the *tracker* — the thin groove. Not the drag-container: that's the + // full hit area, tall enough to hold the dragger handle (which overhangs the + // groove on both sides), so its center sits below the groove. Fall back through + // the container to the slider itself if the theme's internal names ever change; + // worst case is the old box-centered look, not a broken layout. + VisualElement track = slider.Q(className: "unity-base-slider__tracker") + ?? slider.Q(className: "unity-base-slider__drag-container") + ?? slider; + + void Align(GeometryChangedEvent _) + { + float rowTop = row.worldBound.y; + float trackCenter = track.worldBound.center.y; + float half = trackCenter - rowTop; + if (half <= 0f || float.IsNaN(half)) return; // pre-layout; a later event fixes it + + foreach (var label in labels) + label.style.height = half * 2f; + } + + row.RegisterCallback(Align); + track.RegisterCallback(Align); + } + + // Gear glyph. Drawn with Painter2D rather than a font glyph or a texture: Unity's + // default runtime font has no U+2699 gear, and a procedural icon keeps the button + // working in any scene without an imported sprite. Pass a sprite to override. + private static VisualElement CreateGearIcon(Sprite icon) + { + var el = new VisualElement(); + el.pickingMode = PickingMode.Ignore; + el.style.flexGrow = 1; + + if (icon != null) + { + el.style.backgroundImage = new StyleBackground(icon); + return el; + } + + el.generateVisualContent += PaintGear; + // generateVisualContent runs against contentRect, which is 0×0 until the first + // layout pass — repaint once the element actually has a size. + el.RegisterCallback(_ => el.MarkDirtyRepaint()); + return el; + } + + private static void PaintGear(MeshGenerationContext ctx) + { + var rect = ctx.visualElement.contentRect; + if (rect.width < 4f || rect.height < 4f) return; + + var painter = ctx.painter2D; + Vector2 center = rect.center; + float outer = Mathf.Min(rect.width, rect.height) * 0.5f - 1f; + float ring = outer * 0.62f; + float hub = outer * 0.24f; + + painter.strokeColor = new Color(0.95f, 0.93f, 0.75f); + painter.lineWidth = Mathf.Max(1.5f, outer * 0.20f); + + // Teeth: radial spokes from just inside the ring out to the edge. + const int teeth = 8; + painter.BeginPath(); + for (int i = 0; i < teeth; i++) + { + float angle = i * Mathf.PI * 2f / teeth; + var dir = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); + painter.MoveTo(center + dir * (ring * 0.85f)); + painter.LineTo(center + dir * outer); + } + painter.Stroke(); + + painter.BeginPath(); + painter.Arc(center, ring, new Angle(0f, AngleUnit.Degree), new Angle(360f, AngleUnit.Degree)); + painter.Stroke(); + + painter.BeginPath(); + painter.Arc(center, hub, new Angle(0f, AngleUnit.Degree), new Angle(360f, AngleUnit.Degree)); + painter.Stroke(); + } + } +} diff --git a/Assets/_Project/Scripts/UI/GameMenuView.cs.meta b/Assets/_Project/Scripts/UI/GameMenuView.cs.meta new file mode 100644 index 0000000..0d488ea --- /dev/null +++ b/Assets/_Project/Scripts/UI/GameMenuView.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0f5b5b3bcd6ea4765a92a784b9c8de13 \ No newline at end of file diff --git a/Assets/_Project/Scripts/UI/HUDController.cs b/Assets/_Project/Scripts/UI/HUDController.cs index 9ff9ca4..488cea9 100644 --- a/Assets/_Project/Scripts/UI/HUDController.cs +++ b/Assets/_Project/Scripts/UI/HUDController.cs @@ -43,6 +43,10 @@ namespace TD.UI [Header("Settings")] [SerializeField] private float rejectionMessageDuration = 2.5f; + [Tooltip("Optional icon for the top-right menu button. Leave empty to use the " + + "procedurally-drawn gear (no art asset required).")] + [SerializeField] private Sprite menuButtonIcon; + [Tooltip("Maximum visible height of the chat feed in pixels. Content past this " + "height is clipped — older messages scroll off the top of the visible area " + "but stay in history (scroll up while chat is open to view).")] @@ -159,6 +163,21 @@ namespace TD.UI // instead of every gameplay script needing to know about every input widget. public static bool IsTextInputActive { get; internal set; } + /// + /// True while a modal UI surface (currently the gear menu) owns the screen. Gameplay + /// systems should treat this exactly like — see + /// , which is the flag they actually gate on. + /// + public static bool IsModalUiOpen { get; private set; } + + /// + /// True when any UI surface is consuming keyboard/mouse input this frame: a focused + /// text field OR an open modal menu. Gameplay input handlers (camera, selection, + /// hotkeys, Escape-to-cancel) gate on this so typing or a menu never doubles as a + /// gameplay command. + /// + public static bool IsUiCapturingInput => IsTextInputActive || IsModalUiOpen; + // Frame until which chat's "Enter opens chat" behavior is suppressed. Other // standalone text-input surfaces (e.g. TD.Dev.DebugConsole) set this when their // own Enter-driven submit/close already consumed the keypress, so the same @@ -183,6 +202,7 @@ namespace TD.UI private bool deckSubscribed; // true once we've hooked the local PlayerTowerDeck.OnDeckChanged private PlayerTowerDeck subscribedDeck; // the deck we hooked, so we can unsubscribe the same instance private MinimapView minimapView; + private GameMenuView gameMenu; // gear button + modal menu overlay private IPanel myPanel; // tracked separately so OnDestroy only clears the static if it still points at us // ----- Hotkeys ---------------------------------------------------- @@ -703,6 +723,12 @@ namespace TD.UI // ChatService.PostLocalSystem on every peer. BuildChatPanel(root); + // Gear menu (top-right of the top bar). Built last so its overlay z-orders + // above every other HUD surface. "Return to Title Screen" reuses the same + // disconnect path as the match-end overlay's button. + gameMenu = new GameMenuView(root, Require