RoguelikeKit/Assets/Common/Scripts/Player/CharacterBehavior.cs

122 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using OctoberStudio.Easing;
using OctoberStudio.Rendering;
using OctoberStudio.VAT;
using UnityEngine;
using UnityEngine.Events;
namespace OctoberStudio
{
public class CharacterBehavior : MonoBehaviour, ICharacterBehavior
{
protected static readonly int DEFEAT_TRIGGER = Animator.StringToHash("Defeat");
protected static readonly int REVIVE_TRIGGER = Animator.StringToHash("Revive");
protected static readonly int SPEED_FLOAT = Animator.StringToHash("Speed");
protected static readonly int _Overlay = Shader.PropertyToID("_Overlay");
// 把"角色逻辑事件"翻译成"VAT clip 名"。3D 模式下挂 controller 即可,2D 模式留空不影响。
protected const string VAT_CLIP_IDLE = "Idle";
protected const string VAT_CLIP_RUN = "Run";
protected const string VAT_CLIP_DIE = "Die";
protected const float VAT_SPEED_THRESHOLD = 0.01f;
[Tooltip("可选:挂载 RendererAdapter 切换 2D/3D 渲染。未挂时回退到下方 SpriteRenderer 字段。")]
[SerializeField] protected RendererAdapter rendererAdapter;
[SerializeField] protected SpriteRenderer playerSpriteRenderer;
[SerializeField] protected Animator animator;
[Tooltip("可选3D VAT 模式下使用。SetSpeed/PlayDefeatAnimation/PlayReviveAnimation 会同步切换 VAT clip。")]
[SerializeField] protected VATAnimationController vatAnimationController;
[SerializeField] protected Color hitColor;
[SerializeField] protected Transform centerTransform;
public Transform CenterTransform => centerTransform;
public Transform Transform => transform;
protected IEasingCoroutine damageCoroutine;
/// <summary>
/// 优先用 RendererAdapter 的 Material否则回退到 SpriteRenderer.material。
/// </summary>
protected virtual Material HitMaterial
{
get => rendererAdapter != null ? rendererAdapter.Material : playerSpriteRenderer.material;
set
{
if (rendererAdapter != null) rendererAdapter.Material = value;
else playerSpriteRenderer.material = value;
}
}
protected virtual void Reset()
{
if (rendererAdapter == null) rendererAdapter = GetComponent<RendererAdapter>();
if (vatAnimationController == null) vatAnimationController = GetComponentInChildren<VATAnimationController>(true);
}
protected virtual void Awake()
{
// 编辑器没拖时,运行时再尝试自动找(支持 nested prefab 中后挂上来的情况)
if (vatAnimationController == null) vatAnimationController = GetComponentInChildren<VATAnimationController>(true);
}
public virtual void SetSpeed(float speed)
{
if (animator != null) animator.SetFloat(SPEED_FLOAT, speed);
if (vatAnimationController != null)
{
vatAnimationController.Play(speed > VAT_SPEED_THRESHOLD ? VAT_CLIP_RUN : VAT_CLIP_IDLE);
}
}
public virtual void SetLocalScale(Vector3 scale)
{
// VAT 3D 模式: PlayerBehavior 传过来的 scale.x=±1 是 2D 翻转语义,
// 3D 模型不能用 scale.x=-1 (会翻转法线 / culling),改用 VATAnimationController.SetFacing 旋转
if (vatAnimationController != null)
{
vatAnimationController.SetFacing(scale.x >= 0 ? 1 : -1);
return;
}
transform.localScale = scale;
}
public virtual void PlayReviveAnimation()
{
if (animator != null) animator.SetTrigger(REVIVE_TRIGGER);
if (vatAnimationController != null) vatAnimationController.Play(VAT_CLIP_IDLE);
}
public virtual void PlayDefeatAnimation()
{
if (animator != null) animator.SetTrigger(DEFEAT_TRIGGER);
if (vatAnimationController != null) vatAnimationController.Play(VAT_CLIP_DIE, loop: false);
}
public virtual void SetSortingOrder(int order)
{
if (rendererAdapter != null) rendererAdapter.SortingOrder = order;
else if (playerSpriteRenderer != null) playerSpriteRenderer.sortingOrder = order;
}
public virtual void FlashHit(UnityAction onFinish = null)
{
if (damageCoroutine.ExistsAndActive()) return;
var transparentColor = hitColor;
transparentColor.a = 0;
var mat = HitMaterial;
if (mat == null || !mat.HasProperty(_Overlay))
{
onFinish?.Invoke();
return;
}
mat.SetColor(_Overlay, transparentColor);
damageCoroutine = mat.DoColor(_Overlay, hitColor, 0.05f).SetOnFinish(() =>
{
damageCoroutine = mat.DoColor(_Overlay, transparentColor, 0.05f).SetOnFinish(onFinish);
});
}
}
}