[Sparta-BCamp] TIL 3 (Coroutine) โญ

์—…๋ฐ์ดํŠธ:

์นดํ…Œ๊ณ ๋ฆฌ:

ํƒœ๊ทธ: , ,


Coroutine

๋ฏธ๋‹ˆ ํ”„๋กœ์ ํŠธ 3์ผ์ฐจ

3์ผ์ฐจ

  1. ์—ฐ์†์œผ๋กœ ์ •๋‹ต ์‹œ ํŒ€์› ์ด๋ฆ„์ด ์‚ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค. -> Invoke๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌ์€ ํ•  ์ˆ˜ ์—†๋‹ค. Coroutine์„ ์‚ฌ์šฉํ•˜์ž
  2. ๋‚œ์ด๋„ ๋‚˜๋ˆ„๊ธฐ-> start์—์„œ ํด๋ฆญ ์‹œ, level ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ–ˆ์—ˆ๋‹ค. -> ํŒ€์›๋ถ„์˜ ์ข‹์€ ์ฝ”๋“œ๋กœ ์”ฌname์„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ.
  3. 24์žฅ ๋ฐฐ์—ด -> ํฌ๊ธฐ ์กฐ์ • -> ๋ถ€๋ชจ ์Šค์ผ€์ผ
  4. ์ด๋ฏธ์ง€๊ฐ€ 12๊ฐœ๋กœ ๋Š˜์–ด๋‚˜๋ฉด์„œ Substring ์ฝ”๋“œ -> ์ด๋ฏธ์ง€ ์ด๋ฆ„ ๋ณ€๊ฒฝ์œผ๋กœ ํ•ด๊ฒฐ
  5. ์นด๋“œ ๋“ฑ์žฅํšจ๊ณผ -> ์• ๋‹ˆ๋ฉ”์ด์…˜? ํ•˜๋‚˜์”ฉ? -> movetowards

github๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ main, ๋ธŒ๋Ÿฐ์น˜๋ฅผ ๋ฐ”๊พธ๋ฉด ๋ฐ”๋กœ unity๊ฐ€ ๋ฐ”๋€Œ๋Š”๊ฒŒ ์‹ ๊ธฐํ•˜๋‹ค.
๋ฆฌํŠธ๋ผ์ด ๋ฅผ IF๋ฌธ์œผ๋กœ ํ–ˆ๋Š”๋ฐ ํŒ€์›๋ถ„์ด ํ•œ ์ค„๋กœ ๋œ ์ข‹์€ ์ฝ”๋”ฉ์ด ์žˆ์—ˆ๋‹ค.
vector ๋„ ๋ฆฌ์ŠคํŠธ ๊ฐ€๋Šฅํ•˜๊ตฌ๋‚˜.

์งˆ๋ฌธํ•˜๊ธฐ time< maxtime SCALE์ด 0์ธ๋ฐ ์™œ ๊ณ„์† ๋ฐ˜๋ณต??, INVOKE ํ•˜๋ฉด ์™œ ๋ฐ˜๋ณต X? TIME ์ด ์™œ 0.0023? ํ•ด๊ฒฐ๋ฒ•์€?
์งˆ๋ฌธํ•ด ๋ณด๊ณ  -> ํ˜„์žฌ๋Š” ๋ถˆ๋ฆฌ์–ธ ์‚ฌ์šฉ, ์œ ๋‹ˆํ‹ฐ๋ฅผ ๋” ๋ฐฐ์šฐ๋ฉด ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
์ฝ”๋“œ ๊ธฐ๋Šฅ์„ ์™„์„ฑ ํ›„ ๋์ด ์•„๋‹Œ ๋” ์ •ํ™•ํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ์—†์„๋งŒํ•œ ์ฝ”๋”ฉ ์ฒดํฌ -> ํŒ€ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ ํŒ€์›๋“ค์˜ ์ข‹์€ ์ฝ”๋“œ๊ฐ€ ๋งŽ๊ณ  ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ๋‹ค.
๋ฉ”์ธ ์ฝ”๋“œ์—์„œ ์ค‘๋ณต๋‚ด์šฉ์€ ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ํ•˜๋Š” ๊ฒŒ ์ข‹์€ ๋ฐฉ๋ฒ•์ธ๊ฐ€? ๊ถ๊ธˆ. ๋ฌผ์–ด๋ณด๊ธฐ
์ฃผ๊ฐ„ WIL -> ์ด์‹œ๊ฐ„ ํ‘œ์‹œ

TIL ๊ฐ•์˜
๋‚œ til ์„ ์ฒ˜์Œ ์‹œ์ž‘ํ•˜๊ฒŒ ๋œ ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ๋ฉ”๋ชจ ๊ธฐ๋Šฅ์œผ๋กœ ๋‚ด๊ฐ€ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ๋‚ด ๋ธ”๋กœ๊ทธ์—์„œ ์ฐพ์•„ ์“ฐ๊ธฐ ์œ„ํ•ด ๊ธฐ๋ก์„ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.
๊ทธ ํ›„ til ์„ ์“ฐ๊ณ  ๋‚œ ํ›„ ๋ณต์Šตํ•˜๋Š” ํšจ๊ณผ๋„ ์žˆ์—ˆ๊ณ  ๋ณต์Šต์„ ํ•˜๋‹ค ๋ณด๋ฉด ๋˜ ๊ฑฐ๊ธฐ์„œ ๋ฌธ์ œ์ ๊ณผ ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์„ ๋ฐœ๊ฒฌํ•˜๋ฉด์„œ ๋ฐœ์ „ํ•˜๋Š” ๊ฒŒ ๋Š๊ปด์ ธ์„œ ์ข‹์•˜๋‹ค.
์ถ”๊ฐ€์  ์“ธ ๊ฑฐ ex) ๋ฐœ์ƒํ–ˆ๋˜ ๋ฌธ์ œ์  ์„œ๋กœ ์ดํ•ดํ•  ๋•Œ ์ข€ ๋” ์ด์•ผ๊ธฐ๋ฅผ ์ž์„ธํ•˜๊ฒŒ ํ•˜๊ธฐ
๊ฐ€์žฅ ์ค‘์š”ํ•œ ์  ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •








1. ์—ฐ์†๋งค์นญ ์‹œ ํŒ€์›๋ช…

์—ฐ์† ์ •๋‹ต ์‹œ ํŒ€์›๋ช…์ด ์‚ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค.
๋ฒ„๊ทธ์กฐ๊ฑด -> (invoke ์‹œ๊ฐ„ ๋‚ด 2๊ฐœ) ๋น ๋ฅด๊ฒŒ ๋งค์นญ ์‹œ check ๋ณ€์ˆ˜๊ฐ€ ๋ฐ”๋€Œ๋ฉด์„œ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ๋‹ค.
nActiveFalse์— ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ invoke๋ฅผ ํ•˜๊ณ  ์‹ถ์—ˆ์ง€๋งŒ invoke๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•œ๋‹ค
ํ•ด๊ฒฐ๋ฒ• coroutine์„ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•œ๋‹ค.
coroutine์„ ์‚ฌ์šฉํ•ด ๋ณด์•˜๋‹ค. -> ์ฝ”๋ฃจํ‹ด

gamemanager.cs

gamemanager.cs

string info = firstCard.GetComponentInChildren<SpriteRenderer>().sprite.name;   // sprite์˜ ์ด๋ฆ„ rtanx info์— ์ €์žฅ
check = int.Parse(info.Substring(info.Length - 1)) -1;  // rtanx ์˜ x๋ถ€๋ถ„ ์ž๋ฅด๊ธฐ, int ๋กœ ๋ณ€ํ˜•

namelist[check].SetActive(true);            // Active True
StartCoroutine(nActiveFalse(check));

IEnumerator nActiveFalse(int check)
{
    yield return new WaitForSeconds(1.0f);      //1์ดˆ ๋”œ๋ ˆ์ด
    namelist[check].SetActive(false);
}








2.๋‚œ์ด๋„ ๋‚˜๋ˆ„๊ธฐ

๋ณ€์ˆ˜ํ•˜๋‚˜๋กœ ์Šคํƒ€ํŠธ์—์„œ ํด๋ฆญ์‹œ LEVEL=X ์‚ฌ์šฉ
STARTSCENE์—๋Š” ๊ฒŒ์ž„๋ฉ”๋‹ˆ์ €๊ฐ€ ์—†๊ธฐ๋•Œ๋ฌธ์— (gamemanager.i.level)์—ฌ๋Ÿฌ๊ฒฝ์šฐ๋ฅผ ํ•ด๋ณด๊ณ  LEVEL์€ STATIC์‚ฌ์šฉ
ํ•ด๊ฒฐ๋ฒ• LEVEL์€ STATIC์‚ฌ์šฉ

์ดํ›„ retry ๊ฒŒ์ž„์„ ๋ณ€๊ฒฝํ•  ์ผ์ด ์žˆ์—ˆ๋Š”๋ฐ if,switch๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋Œ€ ํŒ€์›๋ถ„์˜ ์ฝ”๋“œ๊ฐ€ ํ•œ์ค„๋กœ ๋˜์—ˆ๋‹ค. SceneManager.LoadScene(SceneManager.GetActiveScene().name);

Startbtn.cs

Startbtn.cs


public void GameStartE()
{
    SceneManager.LoadScene("EasyScene");
}

public void GameStartN()
{
    SceneManager.LoadScene("NormalScene");
}

public void GameStartH()
{
    SceneManager.LoadScene("HardScene");
}

  • ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋‚œ์ด๋„์— ๋งž๋Š” ์”ฌ์œผ๋กœ ์ด๋™








3. 24์žฅ ๋ฐฐ์—ด -> ํฌ๊ธฐ ์กฐ์ • -> ๋ถ€๋ชจ ์Šค์ผ€์ผ

์ดํ›„ retry ๊ฒŒ์ž„์„ ๋ณ€๊ฒฝํ•  ์ผ์ด ์žˆ์—ˆ๋Š”๋ฐ if,switch๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋Œ€ ํŒ€์›๋ถ„์˜ ์ฝ”๋“œ๊ฐ€ ํ•œ์ค„๋กœ ๋˜์—ˆ๋‹ค. SceneManager.LoadScene(SceneManager.GetActiveScene().name);

GameManager.cs

GameManager.cs


void Start()
{
    isShuffle = false;
    tempSprite = sprites[0];
    tempSpriteNum = 0;
    //PlayerPrefs.DeleteAll();

    transaddtxt = addTxt.GetComponent<RectTransform>();
    Time.timeScale = 1.0f;
    cardList = new List<GameObject>();
    //namelist = new List<GameObject>();

    // 12๊ฐœ์˜ ์นด๋“œ ์ƒ์„ฑ
    // ์นด๋“œ sprite๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ๋„ฃ์–ด์คŒ
    if (scene.name == "EasyScene")
    {
        for (int i = 0; i < 12; ++i)
        {
            // ์นด๋“œ๋Š” 12๊ฐœ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ sprite๋Š” 6๊ฐœ
            // 2๊ฐœ์˜ ์นด๋“œ๋Š” ๊ฐ™์€ ์นด๋“œ์—ฌ์•ผ ํ•˜๋ฏ€๋กœ
            if (i % 2 == 0)     // 0, 2, 4, 6, 8, 10 ์ผ๋•Œ๋งŒ sprite๊ฐ€ ๋ฐ”๋€œ
            {
                tempSprite = sprites[i / 2];
                tempSpriteNum = i / 2;
            }

            GameObject newCard = Instantiate(card);
            newCard.transform.parent = GameObject.Find("Cards").transform;

            float x = (i / 3) * 1.4f - 2.1f;
            float y = (i % 3) * 1.4f - 3.0f;
            newCard.transform.position = new Vector3(x, y, 1);
            points.Add(new Vector3(x, y, 1));

            newCard.transform.Find("Front").GetComponent<SpriteRenderer>().sprite = tempSprite;
            newCard.GetComponent<Card>().spriteNum = tempSpriteNum; // card์— spriteNum ๋„ฃ์–ด์ฃผ๊ธฐ
            cardList.Add(newCard);  // List์— ์ƒ์„ฑํ•œ ์นด๋“œ ๋„ฃ์–ด์ฃผ๊ธฐ
        }
    }
    else
    {
        for (int i = 0; i < 24; ++i)
        {
            // ์นด๋“œ๋Š” 12๊ฐœ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ sprite๋Š” 6๊ฐœ
            // 2๊ฐœ์˜ ์นด๋“œ๋Š” ๊ฐ™์€ ์นด๋“œ์—ฌ์•ผ ํ•˜๋ฏ€๋กœ
            if (i % 2 == 0)     // 0, 2, 4, 6, 8, 10 ์ผ๋•Œ๋งŒ sprite๊ฐ€ ๋ฐ”๋€œ
            {
                tempSprite = sprites[i / 2];
                tempSpriteNum = i / 2;
            }

            GameObject newCard = Instantiate(card);
            newCard.transform.parent = GameObject.Find("Cards").transform;
            newCard.transform.parent.localScale = new Vector3(0.8f, 0.8f, 1f);
            newCard.transform.position = new Vector3(0, -1.5f, 1);

            float x = (i / 6) * 1.4f - 2.1f;
            float y = (i % 6) * 1.1f - 4.2f;
            points.Add(new Vector3(x, y, 1));
            

            newCard.transform.Find("Front").GetComponent<SpriteRenderer>().sprite = tempSprite;
            newCard.GetComponent<Card>().spriteNum = tempSpriteNum; // card์— spriteNum ๋„ฃ์–ด์ฃผ๊ธฐ
            cardList.Add(newCard);  // List์— ์ƒ์„ฑํ•œ ์นด๋“œ ๋„ฃ์–ด์ฃผ๊ธฐ
        }
    }

    // ์นด๋“œ ์„ž๊ธฐ

    for (int i = 0; i < cardList.Count; i++)
    {
        int randomNum = Random.Range(0, cardList.Count);
        // swap
        Vector3 tempPosition = points[i];
        points[i] = points[randomNum];
        points[randomNum] = tempPosition;
    }

    if (scene.name == "EasyScene")
        for (int i = 0; i < cardList.Count; ++i)
            cardList[i].transform.position = points[i];
}

  • newCard.transform.parent.localScale = new Vector3(0.8f, 0.8f, 1f); ๋ถ€๋ชจ ์Šค์ผ€์ผ ๋ณ€๊ฒฝ
  • ์ด์ง€, (๋…ธ๋ง,ํ•˜๋“œ) ์นด๋“œ ๋ฐฐ์น˜์— ๋”ฐ๋ผ ๋”ฐ๋กœ ๊ตฌ์„ฑ








4. ์ด๋ฏธ์ง€๊ฐ€ 12๊ฐœ๋กœ ๋Š˜์–ด๋‚˜๋ฉด์„œ Substring ์ฝ”๋“œ

์ด๋ฏธ์ง€๊ฐ€ 1~6 ์—์„œ 1~12๋กœ ๋Š˜์–ด๋‚˜์„œ substring ์—์„œ ์ค‘๋ณต์ด ์ผ์–ด๋‚˜์„œ
์ด๋ฏธ์ง€ ํŒŒ์ผ๋“ค์ด๋ฆ„์„ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

image

Gamemanager.cs

Gamemanager.cs


 namelist[check].SetActive(false);
 check = int.Parse(info.Substring(info.Length - 1)) - 1;  // rtanx ์˜ x๋ถ€๋ถ„ ์ž๋ฅด๊ธฐ, int ๋กœ ๋ณ€ํ˜•
                                                          // ๋ฐฐ์—ด์€ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ -1
 
 namelist[check].SetActive(true);            // Active True
 StartCoroutine(nActiveFalse(check));








5. ์นด๋“œ ๋“ฑ์žฅ ํšจ๊ณผ

์นด๋“œ ๋“ฑ์žฅํšจ๊ณผ -> ์• ๋‹ˆ๋ฉ”์ด์…˜? ํ•˜๋‚˜์”ฉ? -> movetowards
์ƒ๊ฐํ•˜๋Š” ์นด๋“œ ๋“ฑ์žฅ ํšจ๊ณผ : ํŠธ๋Ÿผํ”„์นด๋“œ ์ฒ˜๋Ÿผ ํ•œ ์ ์—์„œ ๋ชจ๋“ ์นด๋“œ๊ฐ€ ๋‚˜๋ˆ ์ง€๋Š” ๊ทธ๋ฆผ.
-> ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•ด๋ณด์ž -> ๊ฒ€์ƒ‰ -> movetowards ํ˜„์žฌ์œ„์น˜์—์„œ ๋ชฉํ‘œ์œ„์น˜๊นŒ์ง€ ์ด๋™ Update ์—์„œ ์‚ฌ์šฉ
์œ„์น˜๊ฐ’์ด start์—์„œ ์ •ํ•ด์ง„๋‹ค. -> vector ๋„ list๋กœ ๊ฐ€๋Šฅํ• ๊นŒ? (๊ฐ€๋Šฅ) -> ์œ„์น˜๊ฐ’์„ vector[i] ์— ์ €์žฅ
->์ด๋™ํ•˜๋Š” ํ•จ์ˆ˜ movetowards

GameManager.cs

GameManager.cs


void Start()
{
    for (int i = 0; i < 24; ++i)
    {
        // ์นด๋“œ๋Š” 12๊ฐœ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ sprite๋Š” 6๊ฐœ
        // 2๊ฐœ์˜ ์นด๋“œ๋Š” ๊ฐ™์€ ์นด๋“œ์—ฌ์•ผ ํ•˜๋ฏ€๋กœ
        if (i % 2 == 0)     // 0, 2, 4, 6, 8, 10 ์ผ๋•Œ๋งŒ sprite๊ฐ€ ๋ฐ”๋€œ
        {
            tempSprite = sprites[i / 2];
            tempSpriteNum = i / 2;
        }

        GameObject newCard = Instantiate(card);
        newCard.transform.parent = GameObject.Find("Cards").transform;
        newCard.transform.parent.localScale = new Vector3(0.8f, 0.8f, 1f);
        newCard.transform.position = new Vector3(0, -1.5f, 1);

        float x = (i / 6) * 1.4f - 2.1f;
        float y = (i % 6) * 1.1f - 4.2f;
        points.Add(new Vector3(x, y, 1));
        

        newCard.transform.Find("Front").GetComponent<SpriteRenderer>().sprite = tempSprite;
        newCard.GetComponent<Card>().spriteNum = tempSpriteNum; // card์— spriteNum ๋„ฃ์–ด์ฃผ๊ธฐ
        cardList.Add(newCard);  // List์— ์ƒ์„ฑํ•œ ์นด๋“œ ๋„ฃ์–ด์ฃผ๊ธฐ
    }
     for (int i = 0; i < cardList.Count; i++)
    {
        int randomNum = Random.Range(0, cardList.Count);
        // swap
        Vector3 tempPosition = points[i];
        points[i] = points[randomNum];
        points[randomNum] = tempPosition;
    }  
}

void Update()
{
    if (isRunning)
    {
        float addy = transaddtxt.anchoredPosition.y;         // addtxt ์œ„์น˜
        addy += 0.5f;                                        // addtxt y๊ฐ’ ์ƒ์Šน
        transaddtxt.anchoredPosition = new Vector2(0, addy); // addtxt y๊ฐ’ ์ƒ์Šน

        //Vector3 speed = Vector3.zero;
        
        if (scene.name != "EasyScene" && !isShuffle)
        {
            for (int i = 0; i < points.Count; i++)
            {
                if (cardList[i])
                {
                    cardList[i].transform.position =
                    //Vector3.MoveTowards(cardList[i].transform.position, points[i], 0.01f);
                    //Vector3.SmoothDamp(cardList[i].transform.position, points[i], ref speed, 0.05f);
                    Vector3.Lerp(cardList[i].transform.position, points[i], 0.05f);
                    //Vector3.Slerp(cardList[i].transform.position, points[i], 0.01f);
                }
            }
        }

        if (time > 2)
        {
            isShuffle = true;
        }
    }
}

  • ํŠน์ • ์ง€์ ์œผ๋กœ ์˜ค๋ธŒ์ ํŠธ ์ด๋™
  • Vector3.MoveTowards(ํ˜„์žฌ ์œ„์น˜, ๋ชฉํ‘œ ์œ„์น˜, ์†๋ ฅ)
  • SmoothDamp (ํ˜„์žฌ์œ„์น˜, ๋ชฉํ‘œ์œ„์น˜, ์ฐธ์กฐ ์†๋ ฅ, ์†Œ์š” ์‹œ๊ฐ„)
  • Lerp (ํ˜„์žฌ ์œ„์น˜, ๋ชฉํ‘œ ์œ„์น˜, ๋ณด๊ฐ„ ํ›„ ์œ„์น˜) ๋Š” ์„ ํ˜•๋ณด๊ฐ„์„ ์ด์šฉํ•œ ์ด๋™ ํ•จ์ˆ˜
  • Slerp (ํ˜„์žฌ ์œ„์น˜, ๋ชฉํ‘œ ์œ„์น˜, ๋ณด๊ฐ„ ๊ฐ„๊ฒฉ) ์€ ๊ตฌ๋ฉด ๋ณด๊ฐ„์„ ์ด์šฉ

GIFMaker_me








6. ์ •๋ฆฌ

Coroutine ๋” ๊นŠ๊ฒŒ ์•Œ์•„๋ณด๊ธฐ.
๋‚œ์ด๋„ ๋‚˜๋ˆ„๋Š” ์ •๋‹ต์— ๊ฐ€๊นŒ์šด ๋ฐฉ๋ฒ•์€ ๋ฌด์—ˆ์ผ๊นŒ?
24์žฅ ๋ฐฐ์—ด -> ํฌ๊ธฐ ์กฐ์ • -> ์• ๋‹ˆ๋ฉ”์ด์…˜์—์„œ scale 1.3 ๊ณ ์ • -> ๋ถ€๋ชจ ์Šค์ผ€์ผ์—์„œ scale ๋ณ€ํ™” ์ด๋ฏธ์ง€๊ฐ€ 12๊ฐœ๋กœ ๋Š˜์–ด๋‚˜๋ฉด์„œ Substring ์ฝ”๋“œ -> ์ด๋ฏธ์ง€ ์ด๋ฆ„ ๋ณ€๊ฒฝ์œผ๋กœ ํ•ด๊ฒฐ
์นด๋“œ ๋“ฑ์žฅํšจ๊ณผ -> movetowards




[Unity] TIL 3


์ฐธ๊ณ  : ์œ ๋‹ˆํ‹ฐ TOP


๐Ÿ“”

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ