diff --git a/Assets/Scenes/Ingame.unity b/Assets/Scenes/Ingame.unity index 3c99727..d84f587 100644 --- a/Assets/Scenes/Ingame.unity +++ b/Assets/Scenes/Ingame.unity @@ -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 diff --git a/Assets/Scripts/Background/InfiniteHorizontalBackground.cs b/Assets/Scripts/Background/InfiniteHorizontalBackground.cs new file mode 100644 index 0000000..4912de1 --- /dev/null +++ b/Assets/Scripts/Background/InfiniteHorizontalBackground.cs @@ -0,0 +1,95 @@ +using UnityEngine; + +namespace EerieVillage.Background +{ + /// + /// 무한 가로 스크롤 배경 — 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 영역 영역 영역 영역 영역 영역 영역 충분. + /// + [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(); + 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(); + 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); + } + } + } +} diff --git a/Assets/Scripts/Background/InfiniteHorizontalBackground.cs.meta b/Assets/Scripts/Background/InfiniteHorizontalBackground.cs.meta new file mode 100644 index 0000000..c40b4d2 --- /dev/null +++ b/Assets/Scripts/Background/InfiniteHorizontalBackground.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4de83d4e43dec1541b816717e1fd2afd \ No newline at end of file