using System.Collections; using System.Collections.Generic; using Platformer.Core; using Platformer.Model; using UnityEngine; namespace Platformer.Mechanics { /// /// AnimationController integrates physics and animation. It is generally used for simple enemy animation. /// // BT12-Dev 2026-05-12 — Visual 자식 분리: RequireComponent SpriteRenderer·Animator 폐기. // GetComponentInChildren fallback로 Visual 자식 영역 영역 영역. public class AnimationController : KinematicObject { /// /// Max horizontal speed. /// public float maxSpeed = 7; /// /// Max jump velocity /// public float jumpTakeOffSpeed = 7; /// /// Used to indicated desired direction of travel. /// public Vector2 move; /// /// Set to true to initiate a jump. /// public bool jump; /// /// Set to true to set the current jump velocity to zero. /// public bool stopJump; SpriteRenderer spriteRenderer; Animator animator; PlatformerModel model; protected virtual void Awake() { // BT12-Dev 2026-05-12 — Visual 자식 분리 (PD 지시): SpriteRenderer·Animator가 자식 Visual GameObject에 위치할 수 있음. spriteRenderer = GetComponent(); if (spriteRenderer == null) spriteRenderer = GetComponentInChildren(); animator = GetComponent(); if (animator == null) animator = GetComponentInChildren(); // BT12-Dev 2026-05-12 — field initializer Awake 영역 이동 (Editor·Play mode 전환 시 model 미초기화 NRE 회피). try { model = Simulation.GetModel(); } catch { model = null; } } protected override void ComputeVelocity() { float jumpMod = model != null ? model.jumpModifier : 1f; float jumpDec = model != null ? model.jumpDeceleration : 0.5f; if (jump && IsGrounded) { velocity.y = jumpTakeOffSpeed * jumpMod; jump = false; } else if (stopJump) { stopJump = false; if (velocity.y > 0) { velocity.y = velocity.y * jumpDec; } } // PD 명시 2026-05-08 — PlayerController와 동일 영역 정합: 좌측 향한 sprite 기준 우측 이동 시 flipX=true if (spriteRenderer != null) { if (move.x > 0.01f) spriteRenderer.flipX = true; else if (move.x < -0.01f) spriteRenderer.flipX = false; } if (animator != null) { animator.SetBool("grounded", IsGrounded); animator.SetFloat("velocityX", Mathf.Abs(velocity.x) / maxSpeed); } targetVelocity = move * maxSpeed; } } }