BT5-Dev #80: 몬스터 y+0.5 + 자동 patrol + 절벽 검출 (PD 3건 일괄)

PD 명시 (2026-05-08):
1. 몬스터 바닥 살짝 뚫고 들어감 → y +0.5 (Enemy.prefab + Scene 인스턴스)
2. PatrolPath 폐기 → 생성 위치 기준 좌/우 random 100~150 왕복 자동 patrol
3. 절벽 검출 → 낭떠러지 떨어지지 않도록

변경:

1. Enemy.prefab transform.y: 1.032 → 1.532
2. Scene Ingame.unity Enemy 인스턴스 16개 m_LocalPosition.y override 영역 +0.5 일괄 (19건)
3. EnemyController.cs:
   - patrol 4-phase 영역 (0: 우측 random / 1: 시작 복귀 / 2: 좌측 random / 3: 시작 복귀)
   - SetNextPatrolTarget — Random.Range(100, 150) 영역 + phase별 _targetX 계산
   - Update 영역 자동 patrol 로직 (PatrolPath path 영역 폐기·legacy 호환만)
   - 절벽 검출 — 발 앞 0.6 + 발 아래 0.8 Raycast 영역 지면 X 시 시작 위치 즉시 복귀
   - Inspector 노출: patrolMinRange·patrolMaxRange·patrolArriveThreshold·cliffCheckDistance·cliffCheckDepth·groundLayerMask
   - BT17 marker Debug.Log 영역 폐기 (시행착오 정리)

효과:
- 모든 Enemy 인스턴스 (path 미설정 영역 포함) 자동 patrol 작동
- 시작 위치 기준 ±100~150 random 왕복 패턴
- 절벽 영역 검출 시 시작 위치 즉시 복귀 (낭떠러지 X)
- y +0.5 = 발 영역 지면 위 정합
This commit is contained in:
깃 관리자 2026-05-08 11:28:35 +09:00
parent 8df09a7feb
commit 3591bd218f
3 changed files with 137 additions and 40 deletions

View File

@ -31,16 +31,17 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1661912868639658944}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 5.508, y: 1.032, z: 1}
m_LocalPosition: {x: 5.508, y: 1.532, z: 1}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &1577774018119691272
SpriteRenderer:
serializedVersion: 2
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -56,6 +57,11 @@ SpriteRenderer:
m_ReflectionProbeUsage: 0
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
@ -77,10 +83,13 @@ SpriteRenderer:
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 1907945055
m_SortingLayer: 0
m_SortingOrder: 5
m_Sprite: {fileID: -7548370174848201806, guid: f7b7e5d5d35e8ea4a9574fc970089486, type: 3}
m_MaskInteraction: 0
m_Sprite: {fileID: -7548370174848201806, guid: f7b7e5d5d35e8ea4a9574fc970089486,
type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
@ -89,11 +98,10 @@ SpriteRenderer:
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_MaskInteraction: 0
m_SpriteSortPoint: 0
--- !u!95 &1605217082131907960
Animator:
serializedVersion: 4
serializedVersion: 7
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -107,13 +115,15 @@ Animator:
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_AnimatePhysics: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorControllerStateOnDisable: 0
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!50 &1702612949800919892
Rigidbody2D:
serializedVersion: 4
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
@ -124,10 +134,16 @@ Rigidbody2D:
m_UseFullKinematicContacts: 1
m_UseAutoMass: 0
m_Mass: 1
m_LinearDrag: 0
m_AngularDrag: 0.05
m_LinearDamping: 0
m_AngularDamping: 0.05
m_GravityScale: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_Interpolate: 1
m_SleepingMode: 0
m_CollisionDetection: 1
@ -140,13 +156,34 @@ CapsuleCollider2D:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1661912868639658944}
m_Enabled: 1
serializedVersion: 3
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_UsedByComposite: 0
m_Offset: {x: 0, y: -0.11}
m_Size: {x: 0.45, y: 0.09}
m_CompositeOperation: 0
m_CompositeOrder: 0
m_Offset: {x: -0.11551046, y: -0.094290674}
m_Size: {x: 0.5664339, y: 0.59230876}
m_Direction: 0
--- !u!114 &2651140156555518892
MonoBehaviour:
@ -182,6 +219,9 @@ MonoBehaviour:
m_EditorClassIdentifier:
path: {fileID: 0}
ouch: {fileID: 8300000, guid: b7f741588644cd64bbee6387cb54a96d, type: 3}
hitRangeX: 0.7
hitRangeY: 1
stompMinDy: 0.1
--- !u!82 &5843668731025413174
AudioSource:
m_ObjectHideFlags: 0
@ -193,6 +233,7 @@ AudioSource:
serializedVersion: 4
OutputAudioMixerGroup: {fileID: 0}
m_audioClip: {fileID: 0}
m_Resource: {fileID: 0}
m_PlayOnAwake: 0
m_Volume: 1
m_Pitch: 1
@ -288,6 +329,10 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ffad43bb006db4856a9c527b89b48db9, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Name:
m_EditorClassIdentifier:
maxHearts: 1
maxHP: 1
invulnerableDuration: 0.5
resurrectInvulnerableDuration: 2
canResurrect: 0

View File

@ -4142,7 +4142,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -6.9554644
value: -6.4554644
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -5203,7 +5203,7 @@ PrefabInstance:
- target: {fileID: 5102505034379151491, guid: 6f545478bd0fb7a478ed6f674a5210f5,
type: 3}
propertyPath: m_LocalPosition.y
value: -1.2901306
value: -0.7901306
objectReference: {fileID: 0}
- target: {fileID: 5102505034379151491, guid: 6f545478bd0fb7a478ed6f674a5210f5,
type: 3}
@ -13067,7 +13067,7 @@ PrefabInstance:
- target: {fileID: 4009130065698333725, guid: 9a1bd12ebb35d4dc997aa0c5494eda9b,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
value: 0.5000000
objectReference: {fileID: 0}
- target: {fileID: 4009130065698333725, guid: 9a1bd12ebb35d4dc997aa0c5494eda9b,
type: 3}
@ -16838,7 +16838,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -3.8154645
value: -3.3154645
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -118941,7 +118941,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: 1.3445356
value: 1.8445356
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -121349,7 +121349,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -6.9554644
value: -6.4554644
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -125071,7 +125071,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -1.4454646
value: -0.9454646
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -125506,7 +125506,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -5.4154644
value: -4.9154644
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -125864,7 +125864,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 4520396350849616, guid: 7d60c822c3f1b408ea7a00ecdb5e047a, type: 3}
propertyPath: m_LocalPosition.y
value: 0
value: 0.5000000
objectReference: {fileID: 0}
- target: {fileID: 4520396350849616, guid: 7d60c822c3f1b408ea7a00ecdb5e047a, type: 3}
propertyPath: m_LocalPosition.z
@ -133748,7 +133748,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: 3.8145354
value: 4.3145354
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -137743,7 +137743,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -1.8354645
value: -1.3354645
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -137836,7 +137836,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -6.9954643
value: -6.4954643
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -140571,7 +140571,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -4.965464
value: -4.4654640
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -296270,7 +296270,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -6.2054644
value: -5.7054644
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -297389,7 +297389,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -5.345464
value: -4.8454640
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -311611,7 +311611,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -0.6254645
value: -0.1254645
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -314947,7 +314947,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -1.7554646
value: -1.2554646
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -317850,7 +317850,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -5.4154644
value: -4.9154644
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
@ -320806,7 +320806,7 @@ PrefabInstance:
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}
propertyPath: m_LocalPosition.y
value: -0.41546452
value: 0.0845355
objectReference: {fileID: 0}
- target: {fileID: 1658460978237467174, guid: f158aa2be3df6489185ef721f6fd79c1,
type: 3}

View File

@ -12,7 +12,7 @@ namespace Platformer.Mechanics
[RequireComponent(typeof(AnimationController), typeof(Collider2D))]
public class EnemyController : MonoBehaviour
{
public PatrolPath path;
public PatrolPath path; // legacy 호환·자동 patrol 영역 도입 후 미사용
public AudioClip ouch;
/// <summary>BT5-Dev #16 — Distance 기반 감지 영역 X 임계값 (전체 폭). 표준 platformer Enemy 옆 닿음 영역 0.6~0.8.</summary>
@ -22,7 +22,19 @@ namespace Platformer.Mechanics
/// <summary>밟기 판정 — Player가 Enemy보다 위 거리. 발 닿는 느낌 영역(0.05~0.15).</summary>
public float stompMinDy = 0.1f;
internal PatrolPath.Mover mover;
// PD 명시 2026-05-08 — 자동 patrol (생성 위치 기준 좌/우 random 100~150 왕복)
public float patrolMinRange = 100f;
public float patrolMaxRange = 150f;
public float patrolArriveThreshold = 0.5f;
public float cliffCheckDistance = 0.6f; // 발 앞 절벽 검출 거리
public float cliffCheckDepth = 0.8f; // 발 아래 Raycast 거리
public LayerMask groundLayerMask = ~0; // 절벽 검출용 ground layer (default = 모든 layer)
private float _startX;
private float _targetX;
private int _patrolPhase; // 0: right out / 1: right back / 2: left out / 3: left back
internal PatrolPath.Mover mover; // legacy 호환·미사용
internal AnimationController control;
internal Collider2D _collider;
internal AudioSource _audio;
@ -63,18 +75,58 @@ namespace Platformer.Mechanics
}
}
// 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}");
// PD 명시 2026-05-08 — 자동 patrol 시작 위치 저장 + 첫 목표 설정
_startX = transform.position.x;
_patrolPhase = 0;
SetNextPatrolTarget();
}
void SetNextPatrolTarget()
{
float range = Random.Range(patrolMinRange, patrolMaxRange);
switch (_patrolPhase)
{
case 0: _targetX = _startX + range; break; // 우측 random 이동
case 1: _targetX = _startX; break; // 시작 위치 복귀
case 2: _targetX = _startX - range; break; // 좌측 random 이동
case 3: _targetX = _startX; break; // 시작 위치 복귀
}
}
void Update()
{
if (path != null)
// PD 명시 2026-05-08 — PatrolPath 영역 폐기·자동 patrol (생성 위치 기준 좌/우 random 100~150 왕복) + 절벽 검출
float dx = _targetX - transform.position.x;
if (Mathf.Abs(dx) < patrolArriveThreshold)
{
if (mover == null) mover = path.CreateMover(control.maxSpeed * 0.5f);
control.move.x = Mathf.Clamp(mover.Position.x - transform.position.x, -1, 1);
_patrolPhase = (_patrolPhase + 1) % 4;
SetNextPatrolTarget();
dx = _targetX - transform.position.x;
}
float moveDir = Mathf.Sign(dx);
// 절벽 검출 — 발 앞 영역 Raycast 지면 X 시 시작 위치로 즉시 복귀
if (Mathf.Abs(dx) > patrolArriveThreshold && _collider != null)
{
Vector2 footAhead = new Vector2(
_collider.bounds.center.x + moveDir * cliffCheckDistance,
_collider.bounds.min.y + 0.05f
);
RaycastHit2D groundHit = Physics2D.Raycast(footAhead, Vector2.down, cliffCheckDepth, groundLayerMask);
if (groundHit.collider == null)
{
// 절벽 영역 → 시작 위치 즉시 복귀 (반대 방향 phase 강제)
_patrolPhase = (_patrolPhase % 2 == 0) ? _patrolPhase + 1 : _patrolPhase;
_targetX = _startX;
dx = _targetX - transform.position.x;
moveDir = Mathf.Sign(dx);
}
}
control.move.x = Mathf.Clamp(dx, -1, 1);
// PD 지시 2026-05-07 — Player ↔ Enemy 통과 가능이지만 Bounds.Intersects로 매 프레임 감지
if (_cachedPlayer == null)
{