์„œ๋น„์Šค
๊ต์œก ์ฒ ํ•™

Resource Loading and Caching

Abstract

๐Ÿ“Œ
๋กœ๋”ฉ๊ณผ ์บ์‹ฑ์—์„œ ์•Œ์•„์•ผ ํ•  ๊ฒƒ์€ ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค โ€” ๋กœ๋“œ๋Š” ๋น„๋™๊ธฐ๋‹ค, ๊ทธ๋ฆฌ๊ณ  ํ•œ ๋ฒˆ ๋กœ๋“œํ•œ ๊ฒƒ์€ ํ•œ๋™์•ˆ ๋‚จ์•„ ์žˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์บ์‹œ๋ฅผ ๋‘ ๊ฒน์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค. ๊ฒ‰์€ "์ˆจ๊ธด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด๊ด€ํ•˜๋Š” ํ’€", ์†์€ "ํ”„๋ฆฌํŒน ์›๋ณธ์„ ๋ถ™์žก๊ณ  ์žˆ๋Š” Addressables ํ•ธ๋“ค". ์ด ๋‘ ๊ฒน์ด ์–ธ์ œ ์ฑ„์›Œ์ง€๊ณ  ์–ธ์ œ ๋น„์›Œ์ง€๋Š”์ง€๋ฅผ ์•Œ๋ฉด ๋กœ๋”ฉ ๋Š๊น€๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์„ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์‹ค๋ฌด์—์„œ ํ•„์š”ํ•œ ์ˆœ๊ฐ„
โ€ข
์ฒซ ์Šคํฐ๋งŒ ๋Š๊ธฐ๊ณ  ๊ทธ ๋’ค๋Š” ๋งค๋„๋Ÿฌ์šด ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•  ๋•Œ
โ€ข
"์ ์„ ๋‹ค ์žก์•˜๋Š”๋ฐ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์•ˆ ์ค„์–ด๋“ ๋‹ค"๋Š” ๋ณด๊ณ ๋ฅผ ๋ฐ›์•˜์„ ๋•Œ
โ€ข
ํ’€ ์šฉ๋Ÿ‰๊ณผ ๋งŒ๋ฃŒ ์‹œ๊ฐ„์„ ์–ผ๋งˆ๋กœ ์žก์•„์•ผ ํ• ์ง€ ์ •ํ•  ๋•Œ
ToyboxNightmare ์—์„œ๋Š”
์—”ํ‹ฐํ‹ฐ ๊ทธ๋ฃน 5๊ฐœ๊ฐ€ ๊ฐ์ž ์ธ์Šคํ„ด์Šค ํ’€์„ ๊ฐ–๊ณ , ์ „๋ถ€ ๋งŒ๋ฃŒ 60์ดˆ ยท ๊ฒ€์‚ฌ ์ฃผ๊ธฐ 60์ดˆ์ž…๋‹ˆ๋‹ค. ์ ๊ณผ ํˆฌ์‚ฌ์ฒด๊ฐ€ ๋Š์ž„์—†์ด ์žฌ์‚ฌ์šฉ๋˜๋ฏ€๋กœ ์ „ํˆฌ ์ค‘์—๋Š” ์ƒˆ ๋กœ๋”ฉ์ด ๊ฑฐ์˜ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋กœ๋”ฉ์ด ์ผ์–ด๋‚˜๋Š” ์ˆœ์„œ๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ๋ณด๋ ค๋ฉด Resource Loading(๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ)-Addressable, ํ’€์˜ ๋‚ด๋ถ€ ๊ทœ์น™์€ ์˜ค๋ธŒ์ ํŠธ ํ’€๋ง (Object Pooling) ์„ ๋ณด์„ธ์š”.

์บ์‹œ๋Š” ๋‘ ๊ฒน์ด๋‹ค

graph TD
    A["ShowEntity(&quot;Zombunny&quot;)"] --> B{"โ‘  ์ธ์Šคํ„ด์Šค ํ’€์—<br>์‰ฌ๊ณ  ์žˆ๋Š” Zombunny ๊ฐ€ ์žˆ๋‚˜"}
    B -- ์žˆ๋‹ค --> Z["๊ทธ ์ธ์Šคํ„ด์Šค๋ฅผ ๊บผ๋‚ด OnShow<br>(๋กœ๋”ฉ ์—†์Œ, ๊ฐ™์€ ํ”„๋ ˆ์ž„)"]
    B -- ์—†๋‹ค --> C{"โ‘ก ํ”„๋ฆฌํŒน์ด ์ด๋ฏธ<br>๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋‚˜"}
    C -- ์žˆ๋‹ค --> D["Instantiate<br>(๋กœ๋“œ๋Š” ์ฆ‰์‹œ ๋๋‚จ)"]
    C -- ์—†๋‹ค --> E["๋ฒˆ๋“ค์—์„œ ํ”„๋ฆฌํŒน ๋กœ๋“œ<br>(๋ช‡ ํ”„๋ ˆ์ž„)"] --> D
    D --> Z2["OnInit โ†’ OnShow"]
Mermaid
๋ณต์‚ฌ
โ‘  ์ธ์Šคํ„ด์Šค ํ’€
โ‘ก ์—์…‹ ํ•ธ๋“ค
๋ณด๊ด€ํ•˜๋Š” ๊ฒƒ
HideEntity ๋œ GameObject
ํ”„๋ฆฌํŒนยทํด๋ฆฝ ์›๋ณธ
๋ˆ„๊ฐ€ ๊ด€๋ฆฌํ•˜๋‚˜
์—”ํ‹ฐํ‹ฐ ๊ทธ๋ฃน / UI ๊ทธ๋ฃน (ํ”„๋ ˆ์ž„์›Œํฌ)
Addressables
์•„๋ผ๋Š” ๋น„์šฉ
Instantiate ์™€ OnInit
๋””์Šคํฌ ์ฝ๊ธฐ
๋น„์›Œ์ง€๋Š” ๋•Œ
๋งŒ๋ฃŒ ์‹œ๊ฐ„์ด ์ง€๋‚˜๊ฑฐ๋‚˜ ์šฉ๋Ÿ‰์„ ๋„˜์„ ๋•Œ
๊ทธ ์—์…‹์œผ๋กœ ๋งŒ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ชจ๋‘ ํŒŒ๊ดด๋์„ ๋•Œ
์„ค์ •ํ•˜๋Š” ๊ณณ
Entity / UI ์ปดํฌ๋„ŒํŠธ์˜ ๊ทธ๋ฃน ์„ค์ •
(์ž๋™)
์† ์บ์‹œ(โ‘ก)๋Š” ๊ฒ‰ ์บ์‹œ(โ‘ )์— ๋งค์—ฌ ์žˆ์Šต๋‹ˆ๋‹ค. ํ’€์— ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ๋‚จ์•„ ์žˆ์œผ๋ฉด ํ”„๋ฆฌํŒน๋„ ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์Šต๋‹ˆ๋‹ค.

ํ’€ ์„ค์ •๊ฐ’ ์ฝ๋Š” ๋ฒ•

GameFramework.prefab ์˜ Entity ์˜ค๋ธŒ์ ํŠธ์—์„œ ๊ทธ๋ฃน๋งˆ๋‹ค ๋„ค ๊ฐ€์ง€๋ฅผ ์ •ํ•ฉ๋‹ˆ๋‹ค.
ํ•„๋“œ
๋œป
์˜ˆ์ œ์˜ ๊ฐ’
Instance Capacity
ํ’€์— ๋ณด๊ด€ํ•ด ๋‘˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜. ์Šคํฐ ์ƒํ•œ์ด ์•„๋‹ˆ๋‹ค โ€” ๋„˜์ณ๋„ ์Šคํฐ์€ ๋˜๊ณ , ๋„˜์นœ ๋งŒํผ๋งŒ ํšŒ์ˆ˜๋  ๋•Œ ๋ณด๊ด€๋˜์ง€ ์•Š๊ณ  ํŒŒ๊ดด๋œ๋‹ค
Player 4 / Enemy 64 / Projectile 64 / Effect 32 / Ally 2
Instance Expire Time
์ด ์‹œ๊ฐ„ ๋™์•ˆ ๋‹ค์‹œ ์“ฐ์ด์ง€ ์•Š์€ ์ธ์Šคํ„ด์Šค๋Š” ์ •๋ฆฌ ๋Œ€์ƒ์ด ๋œ๋‹ค
60์ดˆ
Instance Auto Release Interval
์ •๋ฆฌ ๊ฒ€์‚ฌ๋ฅผ ๋„๋Š” ์ฃผ๊ธฐ
60์ดˆ
Instance Priority
์šฉ๋Ÿ‰์ด ๋„˜์น  ๋•Œ ๋‚ฎ์€ ๊ฒƒ๋ถ€ํ„ฐ ๋ฒ„๋ฆฐ๋‹ค
0
์ •ํ•˜๋Š” ์š”๋ น
โ€ข
Capacity ๋Š” ๋™์‹œ ์ตœ๋Œ€ ๋“ฑ์žฅ ์ˆ˜๋ณด๋‹ค ์กฐ๊ธˆ ํฌ๊ฒŒ. ๋„ˆ๋ฌด ์ž‘์œผ๋ฉด ์›จ์ด๋ธŒ๋งˆ๋‹ค Instantiate / Destroy ๊ฐ€ ๋ฐ˜๋ณต๋˜์–ด ํ’€๋ง ํšจ๊ณผ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค
โ€ข
Expire Time ์€ ์›จ์ด๋ธŒ ์‚ฌ์ด ๊ฐ„๊ฒฉ๋ณด๋‹ค ๊ธธ๊ฒŒ. ์งง์œผ๋ฉด ์‰ฌ๋Š” ๋™์•ˆ ๋‹ค ํŒŒ๊ดด๋˜๊ณ  ๋‹ค์Œ ์›จ์ด๋ธŒ์—์„œ ๋‹ค์‹œ ๋งŒ๋“ ๋‹ค
โ€ข
๋ณด์Šค์ „์—๋งŒ ๋‚˜์˜ค๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ€๋” ์“ฐ๋Š” ๋ฌด๊ฑฐ์šด ๊ฒƒ์€ ๊ทธ๋ฃน์„ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ๋งŒ๋ฃŒ๋ฅผ ์งง๊ฒŒ ์ค€๋‹ค. ๋๋‚œ ๋’ค ์˜ค๋ž˜ ๋ถ™์žก๊ณ  ์žˆ์„ ์ด์œ ๊ฐ€ ์—†๋‹ค

๋ฉ”๋ชจ๋ฆฌ๋Š” ์–ธ์ œ ์ค„์–ด๋“œ๋‚˜

์—”ํ‹ฐํ‹ฐ๋ฅผ ์ˆจ๊ธด ์งํ›„์—๋Š” ์ค„์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ธ์Šคํ„ด์Šค๊ฐ€ ํ’€์— ๋‚จ๊ณ , ๊ทธ๋ž˜์„œ ํ”„๋ฆฌํŒน๋„ ๋‚จ์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ ๊ธฐ์ค€์œผ๋กœ ์Šคํฐ์ด ๋ฉˆ์ถ˜ ๋’ค 1~2๋ถ„(๋งŒ๋ฃŒ 60์ดˆ + ๋‹ค์Œ ๊ฒ€์‚ฌ๊นŒ์ง€ ์ตœ๋Œ€ 60์ดˆ)์ด ์ง€๋‚˜์•ผ ์ธ์Šคํ„ด์Šค๊ฐ€ ํŒŒ๊ดด๋˜๊ณ , ๋งˆ์ง€๋ง‰ ์ธ์Šคํ„ด์Šค๊นŒ์ง€ ์‚ฌ๋ผ์ง€๋ฉด ํ”„๋ฆฌํŒน์ด ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค.
์ง€๊ธˆ ๋‹น์žฅ ๋น„์šฐ๊ณ  ์‹ถ์„ ๋•Œ:
// ์‰ฌ๊ณ  ์žˆ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋ถ€ ์ •๋ฆฌํ•œ๋‹ค (์Šคํ…Œ์ด์ง€๋ฅผ ๋– ๋‚  ๋•Œ) GameEntry.GetComponent<ObjectPoolComponent>().ReleaseAllUnused(); // ์ด์–ด์„œ, ์•„๋ฌด๋„ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ฒŒ ๋œ ์—์…‹์„ ์—”์ง„์ด ์ •๋ฆฌํ•˜๋„๋ก ์˜ˆ์•ฝํ•œ๋‹ค GameEntry.GetComponent<ResourceComponent>().UnloadUnusedAssets(true);
C#
๋ณต์‚ฌ
ํ™•์ธํ•˜๋Š” ๋ฒ• โ€” ํ”Œ๋ ˆ์ด ์ค‘ ๋””๋ฒ„๊ฑฐ ์ฐฝ์„ ์—ด์–ด ๋‹ค์Œ ํƒญ์„ ๋ด…๋‹ˆ๋‹ค.
ํƒญ
๋ณด์ด๋Š” ๊ฒƒ
Profiler โ†’ Object Pool
๊ทธ๋ฃน๋ณ„ ์ธ์Šคํ„ด์Šค ํ’€. ๊ฐœ์ˆ˜๊ฐ€ Capacity ๊ทผ์ฒ˜์—์„œ ๋ฉˆ์ถ”๋Š”์ง€, ์Šคํฐ์ด ๋๋‚œ ๋’ค ์ค„์–ด๋“œ๋Š”์ง€
Profiler โ†’ Memory โ†’ Summary
ํ…์Šค์ฒ˜ยท๋ฉ”์‹œยท์˜ค๋””์˜ค๋ณ„ ๋ฉ”๋ชจ๋ฆฌ. ์Šคํ…Œ์ด์ง€๋ฅผ ๋ฐ˜๋ณตํ•ด๋„ ๊ณ„๋‹จ์‹์œผ๋กœ ์˜ค๋ฅด์ง€ ์•Š๋Š”์ง€

๋กœ๋”ฉ ๋Š๊น€ ์ค„์ด๊ธฐ

์ฒซ ์Šคํฐ์€ "ํ”„๋ฆฌํŒน ๋กœ๋“œ + ์ฒซ Instantiate" ๊ฐ€ ํ•œ๊บผ๋ฒˆ์— ์ผ์–ด๋‚˜ ๋Š๊น๋‹ˆ๋‹ค. ๋กœ๋”ฉ ํ™”๋ฉด์—์„œ ๋ฏธ๋ฆฌ ์น˜๋Ÿฌ ๋‘๋ฉด ๋ฉ๋‹ˆ๋‹ค.
๋ฐฉ๋ฒ•
๋ฏธ๋ฆฌ ์น˜๋ฅด๋Š” ๊ฒƒ
๋งž๋Š” ๋Œ€์ƒ
ResourceComponent.LoadAsset ์œผ๋กœ ์žก์•„ ๋‘๊ธฐ
๋กœ๋“œ๋งŒ
์‚ฌ์šด๋“œ ํด๋ฆฝ, ScriptableObject
ํ•œ ๋ฒˆ ShowEntity ํ–ˆ๋‹ค๊ฐ€ ๋ฐ”๋กœ HideEntity
๋กœ๋“œ + ์ธ์Šคํ„ด์Šคํ™”
์ , ํˆฌ์‚ฌ์ฒด, ์ดํŽ™ํŠธ
๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์œผ๋กœ ๋„ฃ์–ด ๋‘” ์ธ์Šคํ„ด์Šค๋„ Expire Time ์ด ์ง€๋‚˜๋ฉด ์‚ฌ๋ผ์ง€๋ฏ€๋กœ, ์“ฐ๊ธฐ ์ง์ „(์Šคํ…Œ์ด์ง€ ๋กœ๋”ฉ ํ™”๋ฉด)์— ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” Resource Loading(๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ)-Addressable ์˜ "๋ฏธ๋ฆฌ ๋ฐ์šฐ๊ธฐ" ์ ˆ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์ฃผ ๊ฑธ๋ฆฌ๋Š” ๊ณณ

โš ๏ธ
โ€ข
ํ’€์—์„œ ๋‹ค์‹œ ๋‚˜์˜จ ์ธ์Šคํ„ด์Šค๋Š” ์ด์ „ ์ƒํƒœ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค. ์ฒด๋ ฅยท์œ„์น˜ยทํƒ€์ด๋จธยท์• ๋‹ˆ๋ฉ”์ดํ„ฐ๋ฅผ OnShow ์—์„œ ์ „๋ถ€ ๋ฆฌ์…‹ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. OnInit ์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ฒ˜์Œ ๋งŒ๋“ค์–ด์งˆ ๋•Œ ํ•œ ๋ฒˆ๋งŒ ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.
โ€ข
์žฌ์‚ฌ์šฉ์€ ์ฃผ์†Œ ๋‹จ์œ„์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ๊ทธ๋ฃน ์•ˆ์—์„œ๋„ Zombunny ์ธ์Šคํ„ด์Šค๋Š” Zombunny ์š”์ฒญ์—๋งŒ ์“ฐ์ด๊ณ  Hellephant ์š”์ฒญ์—๋Š” ์“ฐ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
โ€ข
Destroy ๋‚˜ SetActive(false) ๋กœ ์น˜์šฐ๋ฉด ํ’€์ด ์–ด๊ธ‹๋‚ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ HideEntity(์˜ˆ์ œ์—์„œ๋Š” SafeHide())๋กœ ๋Œ๋ ค๋ณด๋ƒ…๋‹ˆ๋‹ค.
โ€ข
๋กœ๋“œ์— ์‹คํŒจํ•ด๋„ ์˜ˆ์™ธ๋Š” ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‹คํŒจ ์ด๋ฒคํŠธ๋งŒ ์˜ต๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ์ฃผ์†Œ๋ฅผ ๋ฐ˜๋ณต ์š”์ฒญํ•ด๋„ ์‹คํŒจํ•œ ํ•ธ๋“ค์€ ๊ทธ๋•Œ๊ทธ๋•Œ ํ•ด์ œ๋˜๋ฏ€๋กœ ์Œ“์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.