215 lines
7.8 KiB
C#
215 lines
7.8 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
|
|
namespace SpecialMoveCards
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
[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<Collider>();
|
|
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<Collider>();
|
|
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<PlayerPocket>();
|
|
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<Renderer>();
|
|
|
|
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;
|
|
}
|
|
|
|
/// <summary>Assign the data at runtime for generic prefabs.</summary>
|
|
public void SetData(CardData data)
|
|
{
|
|
cardData = data;
|
|
ApplyVisuals();
|
|
}
|
|
|
|
private void EnsureMaterialPropertyBlock()
|
|
{
|
|
if (mpb == null)
|
|
{
|
|
mpb = new MaterialPropertyBlock();
|
|
}
|
|
}
|
|
}
|
|
}
|