using UnityEngine; using System.Collections; namespace SpecialMoveCards { /// /// Handles world pickup visuals and behavior for a card: hover, rotate, glow, and pickup. /// Expect a trigger collider and optionally a Rigidbody set to kinematic. /// [RequireComponent(typeof(Collider))] public class CardBehaviour : MonoBehaviour { [SerializeField] private CardData cardData; [Header("Visual References")] [Tooltip("Renderer(s) that should have emissive color applied.")] [SerializeField] private Renderer[] emissiveRenderers; [Tooltip("Optional glow mesh (cube/cylinder/etc) used for volumetric-looking glow.")] [SerializeField] private Transform glowCube; // kept for backward-compat; any mesh child works [Tooltip("Optional explicit renderer for the glow mesh. If assigned, takes priority over 'glowCube'.")] [SerializeField] private Renderer glowRenderer; [Tooltip("Optional light to boost bloom.")] [SerializeField] private Light glowLight; [Header("Glow Sync")] [Tooltip("If true, reads emission color from the first emissive renderer's material and uses it for glow, without overriding the material. If false, uses CardData color to set emission on the renderers.")] [SerializeField] private bool deriveGlowFromMaterial = true; [Tooltip("Scales the glow intensity derived from material or CardData.")] [SerializeField] private float glowIntensityMultiplier = 1f; [Header("Motion")] [SerializeField] private float defaultHoverAmplitude = 0.25f; [SerializeField] private float defaultHoverSpeed = 1.0f; [SerializeField] private float defaultRotationSpeed = 35f; private Vector3 basePos; private float hoverPhase; private MaterialPropertyBlock mpb; private Collider trigger; private Color baseEmissive = Color.white; [Header("Glow Pulse (Optional)")] [SerializeField] private bool pulseGlow = false; [SerializeField] private float pulseSpeed = 2f; [SerializeField, Range(0f, 2f)] private float pulseAmplitude = 0.25f; public CardData Data => cardData; private void Reset() { var col = GetComponent(); if (col) col.isTrigger = true; } private void Awake() { // Skip if card system is disabled globally - destroy this card if (CardSpawner.CARD_SYSTEM_DISABLED) { Destroy(gameObject); return; } trigger = GetComponent(); if (trigger) trigger.isTrigger = true; EnsureMaterialPropertyBlock(); basePos = transform.position; ApplyVisuals(); } private void OnValidate() { if (Application.isPlaying) return; EnsureMaterialPropertyBlock(); ApplyVisuals(); } private void Update() { float amp = (cardData && cardData.hoverAmplitude > 0f) ? cardData.hoverAmplitude : defaultHoverAmplitude; float spd = (cardData && cardData.hoverSpeed > 0f) ? cardData.hoverSpeed : defaultHoverSpeed; float rot = (cardData && cardData.rotationSpeed > 0f) ? cardData.rotationSpeed : defaultRotationSpeed; hoverPhase += spd * Time.deltaTime; float offset = Mathf.Sin(hoverPhase) * amp; transform.position = basePos + Vector3.up * offset; transform.Rotate(Vector3.up, rot * Time.deltaTime, Space.World); // Optional pulsing for volumetric glow look if (pulseGlow) { float f = 1f + Mathf.Sin(Time.time * pulseSpeed) * pulseAmplitude; Color current = baseEmissive * f; ApplyGlowOnly(current); } } private void OnTriggerEnter(Collider other) { // Look for a PlayerPocket on the other object or its parents var pocket = other.GetComponentInParent(); if (pocket == null) return; if (pocket.TryAddCard(cardData)) { if (cardData && cardData.particlePrefab) { Instantiate(cardData.particlePrefab, transform.position, Quaternion.identity); } Destroy(gameObject); } } private void ApplyVisuals() { EnsureMaterialPropertyBlock(); // Determine target emissive color Color emissive; if (deriveGlowFromMaterial && TryGetMaterialEmissionColor(out emissive)) { emissive *= glowIntensityMultiplier; } else { Color c = cardData ? cardData.color : Color.white; float intensity = cardData ? cardData.emissionIntensity : 2.5f; emissive = c * Mathf.LinearToGammaSpace(intensity) * glowIntensityMultiplier; // Only in this branch we override renderer emission to match CardData if (emissiveRenderers != null) { for (int i = 0; i < emissiveRenderers.Length; i++) { var r = emissiveRenderers[i]; if (r == null) continue; r.GetPropertyBlock(mpb); mpb.SetColor("_EmissionColor", emissive); r.SetPropertyBlock(mpb); } } } baseEmissive = emissive; // store for pulse updates ApplyGlowOnly(emissive); } private void ApplyGlowOnly(Color emissive) { EnsureMaterialPropertyBlock(); // Prefer explicit glowRenderer if provided Renderer targetRend = glowRenderer; if (targetRend == null && glowCube != null) targetRend = glowCube.GetComponent(); if (targetRend) { targetRend.GetPropertyBlock(mpb); mpb.SetColor("_EmissionColor", emissive); targetRend.SetPropertyBlock(mpb); } if (glowLight) { Color lightColor = new Color(Mathf.Clamp01(emissive.r), Mathf.Clamp01(emissive.g), Mathf.Clamp01(emissive.b)); glowLight.color = lightColor; glowLight.intensity = Mathf.Max(1.5f, emissive.maxColorComponent * 2.5f); glowLight.range = 3f; } } private bool TryGetMaterialEmissionColor(out Color color) { color = Color.black; if (emissiveRenderers == null) return false; // Common property names across pipelines string[] props = { "_EmissionColor", "_EmissiveColor", "_EmissiveColorLDR" }; for (int i = 0; i < emissiveRenderers.Length; i++) { var r = emissiveRenderers[i]; if (r == null) continue; var mat = r.sharedMaterial != null ? r.sharedMaterial : r.material; if (mat == null) continue; for (int p = 0; p < props.Length; p++) { string prop = props[p]; if (mat.HasProperty(prop)) { color = mat.GetColor(prop); return true; } } } return false; } /// Assign the data at runtime for generic prefabs. public void SetData(CardData data) { cardData = data; ApplyVisuals(); } private void EnsureMaterialPropertyBlock() { if (mpb == null) { mpb = new MaterialPropertyBlock(); } } } }