chunk 1: core gameplay scripts scenes runtime assets
This commit is contained in:
214
Assets/Scripts/SpecialMoveCardSystem/CardBehaviour.cs
Normal file
214
Assets/Scripts/SpecialMoveCardSystem/CardBehaviour.cs
Normal file
@@ -0,0 +1,214 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user