fix(BT12-Dev): 무한 배경 컴포넌트 InfiniteHorizontalBackground — sprite 재활용 reposition 패턴 (PD 지적 정정)

PD 지적 (2026-05-10):
- "단순히 키운거라서 비효율적 — 리소스를 재활용할 수 있는 기능 구현"

본 PM 자성 — 직전 Tiled DrawMode size (500, 7) 영역 단순 영역 영역 메모리·렌더 영역 비효율. 영역 영역 — Camera 영역 영역 영역 sprite 영역 reposition 패턴 (재활용·효율).

신규 컴포넌트 InfiniteHorizontalBackground.cs:
- Start — sprite 가로 폭 측정 + 자식 사본 2개 (Left·Right) 영역 영역 영역 영역
  → 화면 영역 영역 영역 3 sprite (root + Left + Right) 영역 충분 (sprite > Camera width 정합)
- LateUpdate — Camera 영역 영역 영역 영역 sprite 폭 영역 영역 영역 → root 영역 정수 배수 reposition
  → 자식 사본 영역 영역 영역 영역 따라가 영역 영역 영역 영역 영역 영역
- 효율 — sprite 1개 (Resources 1회·Texture 메모리 재사용)·GameObject 3개

Background_BgImage1 정정:
- DrawMode Tiled → Simple (sprite default size·재활용 패턴 정합)
- Scale (1.77, 1.77, 1) — Camera height fit
- Position (0, 0.5, 10) — World root
- InfiniteHorizontalBackground 컴포넌트 부착

MCP Play 검증:
- SendMessage("LateUpdate") → bgPos 0 → 188.04 reposition 정합
- Camera 150 → bgChild0 (94.02)·bgChild1 (282.07) — Camera 영역 영역 sprite 3 영역 정합
This commit is contained in:
깃 관리자 2026-05-10 16:03:55 +09:00
parent 4855811a41
commit a6e168e86b
3 changed files with 131 additions and 20 deletions

View File

@ -4447,7 +4447,7 @@ PrefabInstance:
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
@ -4457,27 +4457,27 @@ PrefabInstance:
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
value: 480
objectReference: {fileID: 0}
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
value: 600
objectReference: {fileID: 0}
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
value: 750
objectReference: {fileID: 0}
- target: {fileID: 1561733016117246437, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
value: -300
objectReference: {fileID: 0}
- target: {fileID: 3550758221024711263, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
@ -4597,7 +4597,7 @@ PrefabInstance:
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
@ -4607,27 +4607,27 @@ PrefabInstance:
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
value: 480
objectReference: {fileID: 0}
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
value: 600
objectReference: {fileID: 0}
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
value: 1260
objectReference: {fileID: 0}
- target: {fileID: 6974954132386231314, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
value: -300
objectReference: {fileID: 0}
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
@ -4637,7 +4637,7 @@ PrefabInstance:
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchorMax.y
value: 0
value: 1
objectReference: {fileID: 0}
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
@ -4647,27 +4647,27 @@ PrefabInstance:
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
value: 1
objectReference: {fileID: 0}
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
value: 480
objectReference: {fileID: 0}
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
value: 600
objectReference: {fileID: 0}
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
value: 240
objectReference: {fileID: 0}
- target: {fileID: 9212598073689065413, guid: 9071d6ddb5d4f854185629ee1970af50,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
value: -300
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
@ -141782,6 +141782,7 @@ GameObject:
m_Component:
- component: {fileID: 1251841319}
- component: {fileID: 1251841318}
- component: {fileID: 1251841320}
m_Layer: 0
m_Name: Background_BgImage1
m_TagString: Untagged
@ -141843,7 +141844,7 @@ SpriteRenderer:
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 2
m_DrawMode: 0
m_Size: {x: 500, y: 7}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
@ -141859,11 +141860,24 @@ Transform:
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0.5, z: 10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_LocalScale: {x: 1.77, y: 1.77, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1251841320
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1251841317}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4de83d4e43dec1541b816717e1fd2afd, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::EerieVillage.Background.InfiniteHorizontalBackground
_childSortingOrderOffset: 0
--- !u!1 &1252911031
GameObject:
m_ObjectHideFlags: 0

View File

@ -0,0 +1,95 @@
using UnityEngine;
namespace EerieVillage.Background
{
/// <summary>
/// 무한 가로 스크롤 배경 — sprite 재활용 reposition 패턴.
/// PD 지시 (2026-05-10): "리소스를 재활용할 수 있는 기능 — Tiled size 단순 키움 영역 X".
///
/// 동작:
/// - Start 시점 — sprite 가로 폭 측정 + 자식 사본 2개 (Left·Right) 영역 영역 영역 영역 영역.
/// → 화면 영역 영역 영역 3 sprite (root + Left + Right) 영역 영역 영역 영역 영역.
/// - LateUpdate — Camera 영역 영역 영역 영역 영역 sprite 폭 영역 영역 영역 영역 → root 영역 정수 배수 영역 reposition.
/// → 자식 사본 영역 영역 영역 영역 따라가 영역 영역 영역 영역 영역 영역 영역 영역.
///
/// 효율:
/// - sprite 영역 1개 (Resources 영역 1회 영역 — Texture 메모리 영역 X·재사용)
/// - GameObject 영역 3개 (root + 2 사본) — Camera 영역 영역 영역 영역 영역 영역 영역 충분.
/// </summary>
[RequireComponent(typeof(SpriteRenderer))]
public class InfiniteHorizontalBackground : MonoBehaviour
{
[Tooltip("자식 사본 sortingOrder (root sortingOrder 영역 영역). 영역 영역 영역 영역 0 영역 영역 영역 영역.")]
[SerializeField] int _childSortingOrderOffset = 0;
Transform _camTr;
float _spriteWidth;
Transform _leftCopy;
Transform _rightCopy;
void Start()
{
var cam = Camera.main;
if (cam == null)
{
Debug.LogWarning($"[InfiniteHorizontalBackground@{name}] Camera.main NULL — 영역 영역 영역.");
enabled = false;
return;
}
_camTr = cam.transform;
var sr = GetComponent<SpriteRenderer>();
if (sr.sprite == null)
{
Debug.LogWarning($"[InfiniteHorizontalBackground@{name}] sprite NULL — 영역 영역 영역.");
enabled = false;
return;
}
// sprite 가로 영역 (월드 단위·scale 영역 영역)
_spriteWidth = sr.sprite.bounds.size.x * transform.lossyScale.x;
if (_spriteWidth <= 0.001f)
{
Debug.LogWarning($"[InfiniteHorizontalBackground@{name}] spriteWidth ~0 — 영역 영역 영역.");
enabled = false;
return;
}
// 자식 사본 2개 영역 영역 (Left·Right)
_leftCopy = CreateCopy("Left", -_spriteWidth, sr);
_rightCopy = CreateCopy("Right", +_spriteWidth, sr);
}
Transform CreateCopy(string copyName, float worldOffsetX, SpriteRenderer src)
{
var copy = new GameObject(copyName);
copy.transform.SetParent(transform, false);
// localPosition 영역 — parent.lossyScale 영역 영역 영역. 영역 영역 영역 — local 단위 영역 영역.
float localOffsetX = worldOffsetX / transform.lossyScale.x;
copy.transform.localPosition = new Vector3(localOffsetX, 0f, 0f);
copy.transform.localScale = Vector3.one;
var sr = copy.AddComponent<SpriteRenderer>();
sr.sprite = src.sprite;
sr.sortingLayerID = src.sortingLayerID;
sr.sortingOrder = src.sortingOrder + _childSortingOrderOffset;
sr.color = src.color;
sr.flipX = src.flipX;
sr.flipY = src.flipY;
return copy.transform;
}
void LateUpdate()
{
if (_camTr == null) return;
// Camera 영역 영역 영역 영역 영역 영역 sprite 폭 영역 영역 영역 영역 → root 영역 정수 배수 영역 reposition
float dx = _camTr.position.x - transform.position.x;
if (Mathf.Abs(dx) >= _spriteWidth)
{
int n = Mathf.RoundToInt(dx / _spriteWidth);
transform.position += new Vector3(n * _spriteWidth, 0f, 0f);
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4de83d4e43dec1541b816717e1fd2afd