2026-04-22 15:58:44 +00:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using Platformer.Gameplay;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using static Platformer.Core.Simulation;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Platformer.Mechanics
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// A simple controller for enemies. Provides movement control over a patrol path.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[RequireComponent(typeof(AnimationController), typeof(Collider2D))]
|
|
|
|
|
|
public class EnemyController : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
public PatrolPath path;
|
|
|
|
|
|
public AudioClip ouch;
|
|
|
|
|
|
|
2026-05-07 06:29:34 +00:00
|
|
|
|
/// <summary>BT5-Dev #16 — Distance 기반 감지 영역 X 임계값 (전체 폭). 표준 platformer Enemy 옆 닿음 영역 0.6~0.8.</summary>
|
|
|
|
|
|
public float hitRangeX = 0.7f;
|
|
|
|
|
|
/// <summary>Y 임계값. 위/아래 둘 다 인정.</summary>
|
|
|
|
|
|
public float hitRangeY = 1.0f;
|
|
|
|
|
|
/// <summary>밟기 판정 — Player가 Enemy보다 위 거리.</summary>
|
|
|
|
|
|
public float stompMinDy = 0.5f;
|
|
|
|
|
|
|
2026-04-22 15:58:44 +00:00
|
|
|
|
internal PatrolPath.Mover mover;
|
|
|
|
|
|
internal AnimationController control;
|
|
|
|
|
|
internal Collider2D _collider;
|
|
|
|
|
|
internal AudioSource _audio;
|
|
|
|
|
|
SpriteRenderer spriteRenderer;
|
|
|
|
|
|
|
|
|
|
|
|
public Bounds Bounds => _collider.bounds;
|
|
|
|
|
|
|
2026-05-07 06:29:34 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// PD 지시 2026-05-07 — Enemy 시각(SpriteRenderer) 영역 기반 충돌 감지용. CapsuleCollider2D는 작은 ground sensor 영역(0.45×0.09)이라 감지에 부적합.
|
|
|
|
|
|
/// SpriteRenderer 부재 시 Collider Bounds로 fallback.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Bounds VisualBounds => spriteRenderer != null ? spriteRenderer.bounds : _collider.bounds;
|
|
|
|
|
|
|
|
|
|
|
|
PlayerController _cachedPlayer;
|
|
|
|
|
|
|
2026-04-22 15:58:44 +00:00
|
|
|
|
void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
control = GetComponent<AnimationController>();
|
|
|
|
|
|
_collider = GetComponent<Collider2D>();
|
|
|
|
|
|
_audio = GetComponent<AudioSource>();
|
|
|
|
|
|
spriteRenderer = GetComponent<SpriteRenderer>();
|
|
|
|
|
|
|
2026-05-07 06:29:34 +00:00
|
|
|
|
// PD 지시 2026-05-07 — Player ↔ Enemy 물리 충돌 무시 (통과 가능). 감지는 Bounds.Intersects 별도.
|
|
|
|
|
|
// Enemy Collider 일반 유지 (지면 충돌 영역 보존) → 등장 정합.
|
|
|
|
|
|
var playerObj = GameObject.FindGameObjectWithTag("Player");
|
|
|
|
|
|
if (playerObj != null && _collider != null)
|
2026-04-22 15:58:44 +00:00
|
|
|
|
{
|
2026-05-07 06:29:34 +00:00
|
|
|
|
var pc = playerObj.GetComponent<Collider2D>();
|
|
|
|
|
|
if (pc != null) Physics2D.IgnoreCollision(_collider, pc, true);
|
2026-04-22 15:58:44 +00:00
|
|
|
|
}
|
2026-05-07 06:29:34 +00:00
|
|
|
|
|
2026-05-07 06:40:39 +00:00
|
|
|
|
// BT5-Dev #17 marker — 본 영역 출력 시 새 코드 영역 적용 정합. 출력 X = Editor Asset Refresh 영역 미수행
|
|
|
|
|
|
Debug.Log($"[BT17-MARKER@{name}] sr={(spriteRenderer != null ? "OK" : "NULL")} hitX={hitRangeX} hitY={hitRangeY} stomp={stompMinDy} | colB={_collider?.bounds.size} vB={VisualBounds.size}");
|
2026-04-22 15:58:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (path != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (mover == null) mover = path.CreateMover(control.maxSpeed * 0.5f);
|
|
|
|
|
|
control.move.x = Mathf.Clamp(mover.Position.x - transform.position.x, -1, 1);
|
|
|
|
|
|
}
|
2026-05-07 06:29:34 +00:00
|
|
|
|
|
|
|
|
|
|
// PD 지시 2026-05-07 — Player ↔ Enemy 통과 가능이지만 Bounds.Intersects로 매 프레임 감지
|
|
|
|
|
|
if (_cachedPlayer == null)
|
|
|
|
|
|
{
|
2026-05-07 06:45:33 +00:00
|
|
|
|
// 1차: tag 영역 발견
|
2026-05-07 06:29:34 +00:00
|
|
|
|
var pgo = GameObject.FindGameObjectWithTag("Player");
|
|
|
|
|
|
if (pgo != null) _cachedPlayer = pgo.GetComponent<PlayerController>();
|
2026-05-07 06:45:33 +00:00
|
|
|
|
|
|
|
|
|
|
// 2차 fallback: tag 영역 미설정 영역에 대비해 PlayerController 영역 직접 검색
|
|
|
|
|
|
if (_cachedPlayer == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_cachedPlayer = Object.FindFirstObjectByType<PlayerController>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-07 06:40:39 +00:00
|
|
|
|
if (Time.frameCount % 60 == 0)
|
2026-05-07 06:45:33 +00:00
|
|
|
|
{
|
|
|
|
|
|
int allCount = Object.FindObjectsByType<PlayerController>(FindObjectsSortMode.None).Length;
|
|
|
|
|
|
Debug.Log($"[BT17-Update@{name}] f={Time.frameCount} cached={(_cachedPlayer != null ? _cachedPlayer.name : "NULL")} pgoTag={(pgo != null ? pgo.name : "NULL")} allPCcount={allCount}");
|
|
|
|
|
|
}
|
2026-05-07 06:29:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
if (_cachedPlayer != null && _cachedPlayer.health != null && _cachedPlayer.health.IsAlive)
|
|
|
|
|
|
{
|
|
|
|
|
|
// BT5-Dev #16 — Distance 기반 단순 감지 (Bounds 영역 산수 영역 의존 X·항상 작동)
|
|
|
|
|
|
// dx 0.7·|dy| 1.0 = 표준 platformer Enemy/Player 닿음 영역. dy > 0.5 = Player가 Enemy 위에서 밟음.
|
|
|
|
|
|
Vector3 ePos = transform.position;
|
|
|
|
|
|
Vector3 pPos = _cachedPlayer.transform.position;
|
|
|
|
|
|
float dx = Mathf.Abs(pPos.x - ePos.x);
|
|
|
|
|
|
float dy = pPos.y - ePos.y;
|
|
|
|
|
|
|
|
|
|
|
|
bool inRange = dx < hitRangeX && Mathf.Abs(dy) < hitRangeY;
|
|
|
|
|
|
|
|
|
|
|
|
if (inRange != _diagWasIntersecting)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"[EnemyDiag@{name}] inRange={inRange} dx={dx:F2} dy={dy:F2} (thresholds dx<{hitRangeX} |dy|<{hitRangeY}) | ePos={ePos} pPos={pPos}");
|
|
|
|
|
|
_diagWasIntersecting = inRange;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (inRange)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ev = Schedule<PlayerEnemyCollision>();
|
|
|
|
|
|
ev.player = _cachedPlayer;
|
|
|
|
|
|
ev.enemy = this;
|
|
|
|
|
|
ev.dyAtCollision = dy;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool _diagWasIntersecting;
|
|
|
|
|
|
|
|
|
|
|
|
void OnDrawGizmos()
|
|
|
|
|
|
{
|
|
|
|
|
|
// BT5-Dev #15 진단 — Scene 영역 시각화 (Editor에서만 표시)
|
|
|
|
|
|
if (Application.isPlaying && spriteRenderer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Gizmos.color = Color.red;
|
|
|
|
|
|
Gizmos.DrawWireCube(VisualBounds.center, VisualBounds.size);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (Application.isPlaying && _collider != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Gizmos.color = Color.yellow;
|
|
|
|
|
|
Gizmos.DrawWireCube(_collider.bounds.center, _collider.bounds.size);
|
|
|
|
|
|
}
|
2026-04-22 15:58:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|