EerieVillage/Assets/Scripts/Mechanics/AnimationController.cs

108 lines
4.0 KiB
C#
Raw Normal View History

using System.Collections;
using System.Collections.Generic;
using Platformer.Core;
using Platformer.Model;
using UnityEngine;
namespace Platformer.Mechanics
{
/// <summary>
/// AnimationController integrates physics and animation. It is generally used for simple enemy animation.
/// </summary>
// BT12-Dev 2026-05-12 — Visual 자식 분리: RequireComponent SpriteRenderer·Animator 폐기.
// GetComponentInChildren fallback로 Visual 자식 영역 영역 영역.
public class AnimationController : KinematicObject
{
/// <summary>
/// Max horizontal speed.
/// </summary>
public float maxSpeed = 7;
/// <summary>
/// Max jump velocity
/// </summary>
public float jumpTakeOffSpeed = 7;
/// <summary>
/// Used to indicated desired direction of travel.
/// </summary>
public Vector2 move;
/// <summary>
/// Set to true to initiate a jump.
/// </summary>
public bool jump;
/// <summary>
/// Set to true to set the current jump velocity to zero.
/// </summary>
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<SpriteRenderer>();
if (spriteRenderer == null) spriteRenderer = GetComponentInChildren<SpriteRenderer>();
animator = GetComponent<Animator>();
if (animator == null) animator = GetComponentInChildren<Animator>();
// BT12-Dev 2026-05-12 — field initializer Awake 영역 이동 (Editor·Play mode 전환 시 model 미초기화 NRE 회피).
try { model = Simulation.GetModel<PlatformerModel>(); } catch { model = null; }
fix(BT12-Dev): KinematicObject base magic method override·body 초기화 (Enemy 영구 정지 근본) PD: "여전히 움직이지 않아·실측해보고 근본 원인 체크" 근본 (MCP Play 실측·자성 #12·#13): - KinematicObject.OnEnable·Start·Update·FixedUpdate 모두 `protected virtual` - AnimationController는 KinematicObject 상속하지만 override X - Unity는 Component 정의된 magic method만 호출·base class virtual은 derived가 override 안 하면 호출 안 됨 - 결과: KinematicObject.OnEnable 호출 X → body=NULL·KinematicObject.FixedUpdate 호출 X → velocity 갱신 X·gravity 적용 X - Enemy 자연 낙하 X·patrol 동작 X·영구 정지 검증: - MCP Play 후 body field reflection 읽기 → NULL - Rigidbody2D 컴포넌트 자체는 GetComponent OK·OnEnable이 body 설정 안 함 fix (AnimationController): 1. Awake 영역에 base 초기화 위임: - body = GetComponent<Rigidbody2D>()·body.bodyType = Kinematic - contactFilter.useTriggers/SetLayerMask/useLayerMask 2. Update·FixedUpdate override 추가: - protected override void Update() { base.Update(); } - protected override void FixedUpdate() { base.FixedUpdate(); } - Unity가 AnimationController 인스턴스의 Update/FixedUpdate 호출 → base 실행 검증 후 (MCP Play): - body=OK·IsGrounded=True·자연 낙하 정합 (pos.y=-2.5 등) - Enemy 일부 발판 위 정착·일부 InfiniteHorizontalGround 영역 밖 무한 낙하 (별건) 회귀 영역 X: - spriteRenderer/animator GetComponentInChildren·field initializer 가드 영역 영역 X - KinematicObject 자체 영역 영역 X (다른 KinematicObject 상속 클래스는 별도 검증) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:57:01 +00:00
// BT12-Dev 2026-05-12 — KinematicObject base 영역 protected virtual OnEnable/Start/Update/FixedUpdate Unity 호출 X 정정
// (override X·derived class만 magic method 영역). Awake 영역 base 초기화 위임.
body = GetComponent<Rigidbody2D>();
if (body != null) body.bodyType = RigidbodyType2D.Kinematic;
contactFilter.useTriggers = false;
contactFilter.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer));
contactFilter.useLayerMask = true;
}
// BT12-Dev 2026-05-12 — Update·FixedUpdate Unity 호출 정합 (override 영역 derived 영역 호출 영역)
protected override void Update()
{
base.Update();
}
protected override void FixedUpdate()
{
base.FixedUpdate();
}
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;
}
}
}