TIL

[멋쟁이사자처럼 부트캠프 TIL 회고]

Cadi 2025. 2. 18. 17:15

오늘의 목표

1. 하트 만들기 (어제 클리어)

2. 패널 새로운 방식으로 동작시키기

3. 퀴즈 카드 애니메이션 만들기

 

 


02. 패널 새로운 방식으로 동작시키기 

 

저번주에 다른 방식으로 고쳤긴 했지만, 새로운 방식으로 동작시키는 것을 보여주셨다. 

똑같은 동작이지만 안에 든 코드는 정말 다르다. 

게임을 만드는 것은 참 신기한게 '결과'만 보인다. 코딩이 원래 그런가 ? 잘 동작하면 더 고치지 않는 것을 이제

조금은 이해할 수 있을것 같은 기분이다. 

 

 

저번에는 temp를 이용해서  참조 주소를 변경해준 뒤 포지션을 바꿔주었다. 

 

이번에는 Queue를 만들어 퀴즈카드들을 관리할 것이다. 

 

*SetAsLastSibling : 특정 오브젝트를 부모 오브젝트의 자식 목록에서 맨 마지막 순서로 재배치

-> 가장 나중에 그려지게 됨. 

 

 

  public void AddQuizCardObject(QuizData? quizData, bool isInit = false)
    {

        GameObject tempObject = null;
        // _quizCardQueue에 이미 Quiz Card Object가 있었다면,
        // 1. 해당 오브젝트를 Deque 하고,
        if (_quizCardQueue.Count > 0 && !isInit)
        {
            // 나온 퀴즈 카드(사라져야 할)
            tempObject = _quizCardQueue.Dequeue();
        }

        if (_quizCardQueue.Count > 0)
        {
            // 2. 가장 첫 번째 오브젝트를 Peek 해서 사이즈와 위치 조절하고
            var firstQuizCardObject = _quizCardQueue.Peek();
            firstQuizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 0);
            firstQuizCardObject.transform.localScale = Vector3.one;
            firstQuizCardObject.transform.SetAsLastSibling();
            firstQuizCardObject.GetComponent<QuizCardController>().SetVisible(true);
        }
        
        // 3. 새로운 quizCardObject를 Enqueue 함
        if (quizData.HasValue)
        {
            var quizCardObject = ObjectPool.Instance.GetObject();
            quizCardObject.GetComponent<QuizCardController>().SetQuiz(quizData.Value, OnCompletedQuiz);
            quizCardObject.GetComponent<QuizCardController>().SetVisible(false);
            quizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 160);
            quizCardObject.transform.localScale = Vector3.one * 0.9f;
            quizCardObject.transform.SetAsFirstSibling();
            _quizCardQueue.Enqueue(quizCardObject);
        }
        
        if (tempObject != null) 
            ObjectPool.Instance.ReturnObject(tempObject);
    }

 

quizData를 Nullable로 받아준다. 

나중에 퀴즈 리스트에서 데이터를 가져올텐데, null을 가져온다는 것은 그 스테이지에는 더 이상 퀴즈가 남아있지 않다는 뜻을 표현해주기 위해서이다. 

 

isInit은 처음 불러오는 것인지, 다음 버튼을 눌러서 가져올 것인지 판별해준다. 

 

이해하기 위해선 넣는 부분(3) 부터 보면 편하다.

  // 3. 새로운 quizCardObject를 Enqueue 함
        if (quizData.HasValue)
        {
            var quizCardObject = ObjectPool.Instance.GetObject();
            quizCardObject.GetComponent<QuizCardController>().SetQuiz(quizData.Value, OnCompletedQuiz);
            quizCardObject.GetComponent<QuizCardController>().SetVisible(false);
            quizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 160);
            quizCardObject.transform.localScale = Vector3.one * 0.9f;
            quizCardObject.transform.SetAsFirstSibling();
            _quizCardQueue.Enqueue(quizCardObject);
        }

 

 

오브젝트풀에서 하나를 가져온 뒤, 매개변수로 받아온 퀴즈데이터를 이용해 퀴즈를 설정해준다.

사이즈와 위치도 조정해주고 제일 먼저 그려지게 한다.(뒤로 그려질 것)

그리고 퀴즈카드풀에 넣는다. 

 

 

이제 꺼내써야 하는데, 바로 꺼내써 버리면 첫 번째 카드가 들어가자마자 Dequeue될 것이므로, isInit 즉 처음에 두개 넣을거에요 ! 라고 선언해준 부분에서는 Dequeue를 하지 않도록 한다.

GameObject tempObject = null;
        
        // 1. 해당 오브젝트를 Deque 하고,
        if (_quizCardQueue.Count > 0 && !isInit)
        {
            tempObject = _quizCardQueue.Dequeue();
        }
 if (_quizCardQueue.Count > 0)
        {
            // 2. 가장 첫 번째 오브젝트를 Peek 해서 사이즈와 위치 조절하고
            var firstQuizCardObject = _quizCardQueue.Peek();
            firstQuizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 0);
            firstQuizCardObject.transform.localScale = Vector3.one;
            firstQuizCardObject.transform.SetAsLastSibling();
            firstQuizCardObject.GetComponent<QuizCardController>().SetVisible(true);
        }

 

첫 번째 오브젝트도 참조값을 꺼내와서 위치와 그려질 순서를 조정한다. 

 

   if (tempObject != null) 
            ObjectPool.Instance.ReturnObject(tempObject);

그리고 마지막으로 , 꺼낸 (사라져야 할 ) 카드는 다시 오브젝트풀에 넣어준다. 

 

03. 퀴즈 카드 애니메이션 만들기

 

냅다 코드 전문 올려버리기 ~ 

public void AddQuizCardObject(QuizData? quizData, bool isInit = false)
{
    // _quizCardQueue에 이미 Quiz Card Object가 있었다면,

    GameObject tempObject = null;
    if (_quizCardQueue.Count > 0 && !isInit)
    {
        tempObject = _quizCardQueue.Dequeue();
    }

    if (tempObject != null)
        tempObject.transform.DOMoveY(-50f, 1f).SetEase(Ease.InBack).OnComplete(() =>
        {
            ObjectPool.Instance.ReturnObject(tempObject);
            if (_quizCardQueue.Count > 0)
            {
                // 2. 가장 첫 번째 오브젝트를 Peek 해서 사이즈와 위치 조절하고
                var firstQuizCardObject = _quizCardQueue.Peek();
                firstQuizCardObject.GetComponent<RectTransform>().DOAnchorPos(new Vector2(0,0), 1f)
                    .SetEase(Ease.Linear);
                firstQuizCardObject.transform.DOScale(Vector3.one, 1f).SetEase(Ease.Linear);
                firstQuizCardObject.transform.SetAsLastSibling();
                firstQuizCardObject.GetComponent<QuizCardController>().SetVisible(true);
            }

            // 3. 새로운 quizCardObject를 Enqueue 함
            if (quizData.HasValue)
            {
                var quizCardObject = ObjectPool.Instance.GetObject();
                quizCardObject.GetComponent<QuizCardController>().SetQuiz(quizData.Value, OnCompletedQuiz);
                quizCardObject.GetComponent<QuizCardController>().SetVisible(false);
                quizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 160);
                quizCardObject.transform.localScale = Vector3.one * 0.9f;
                quizCardObject.transform.SetAsFirstSibling();
                _quizCardQueue.Enqueue(quizCardObject);
            }
        });
    else
    {
        if (_quizCardQueue.Count > 0)
        {
            // 2. 가장 첫 번째 오브젝트를 Peek 해서 사이즈와 위치 조절하고
            var firstQuizCardObject = _quizCardQueue.Peek();
            firstQuizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 0);
            firstQuizCardObject.transform.localScale = Vector3.one;
            firstQuizCardObject.transform.SetAsLastSibling();
            firstQuizCardObject.GetComponent<QuizCardController>().SetVisible(true);
        }

        // 3. 새로운 quizCardObject를 Enqueue 함
        if (quizData.HasValue)
        {
            var quizCardObject = ObjectPool.Instance.GetObject();
            quizCardObject.GetComponent<QuizCardController>().SetQuiz(quizData.Value, OnCompletedQuiz);
            quizCardObject.GetComponent<QuizCardController>().SetVisible(false);
            quizCardObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 160);
            quizCardObject.transform.localScale = Vector3.one * 0.9f;
            quizCardObject.transform.SetAsFirstSibling();
            _quizCardQueue.Enqueue(quizCardObject);
        }
    }
}
private void SetQuizCardPanelActive(QuizCardPanelType quizCardPanelType)
{
    switch (quizCardPanelType)
    {
        case QuizCardPanelType.Front:
            if (incorrectBackPanel.activeSelf)
            {
                currentRotationPanel = this.GameObject();
                currentRotationPanel.transform.DORotate(new Vector3(0, 90f, 0), 0.3f, RotateMode.Fast).SetEase(Ease.InSine).OnComplete((() =>
                {
                    currentRotationPanel.transform.DORotate(new Vector3(0, -90f, 0), 0.3f,RotateMode.Fast).SetEase(Ease.InSine).OnComplete(
                        () =>
                        {
                            PanelRotationZero();

                            frontPanel.SetActive(true);
                            correctBackPanel.SetActive(false);
                            incorrectBackPanel.SetActive(false);
            
                            correctBackPanel.GetComponent<RectTransform>().anchoredPosition = _correctBackPanelPosition;
                            incorrectBackPanel.GetComponent<RectTransform>().anchoredPosition = _incorrectBackPanelPosition;
                        });
               
                }));
            }
            else
            {
                PanelRotationZero();

                frontPanel.SetActive(true);
                correctBackPanel.SetActive(false);
                incorrectBackPanel.SetActive(false);
            
                correctBackPanel.GetComponent<RectTransform>().anchoredPosition = _correctBackPanelPosition;
                incorrectBackPanel.GetComponent<RectTransform>().anchoredPosition = _incorrectBackPanelPosition;
            }
            
            break;
        case QuizCardPanelType.CorrectBackPanel:
            currentRotationPanel = this.GameObject();
            currentRotationPanel.transform.DORotate(new Vector3(0, 90f, 0), 0.3f, RotateMode.Fast).SetEase(Ease.InSine).OnComplete((() =>
            {
                currentRotationPanel.transform.DORotate(new Vector3(0, -90f, 0), 0.3f,RotateMode.Fast).SetEase(Ease.InSine).OnComplete(
                    () =>
                    {
                        PanelRotationZero();
                        frontPanel.SetActive(false);
                        correctBackPanel.SetActive(true);
                        incorrectBackPanel.SetActive(false);
                        correctBackPanel.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
                        incorrectBackPanel.GetComponent<RectTransform>().anchoredPosition = _incorrectBackPanelPosition;
                    });
               
            }));
            
            break;
        case QuizCardPanelType.InCorrectBackPanel:
            currentRotationPanel = this.GameObject();
            currentRotationPanel.transform.DORotate(new Vector3(0, 90f, 0), 0.3f, RotateMode.Fast).SetEase(Ease.InSine).OnComplete((() =>
            {
                currentRotationPanel.transform.DORotate(new Vector3(0, -90f, 0), 0.3f,RotateMode.Fast).SetEase(Ease.InSine).OnComplete(
                    () =>
                    {
                        PanelRotationZero();

                        frontPanel.SetActive(false);
                        correctBackPanel.SetActive(false);
                        incorrectBackPanel.SetActive(true);
            
                        correctBackPanel.GetComponent<RectTransform>().anchoredPosition = _correctBackPanelPosition;
                        incorrectBackPanel.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
                        Debug.Log(incorrectBackPanel.GetComponent<RectTransform>().anchoredPosition);
                    });
               
            }));
            break;
    }    
}
public void PanelRotationZero()
{
   this.GameObject().transform.rotation = Quaternion.Euler(0f, 0f, 0f);
}
private void InitQuizCards(int stageIndex)
{
    _quizDataList = QuizDataController.LoadQuizData(stageIndex);

    AddQuizCardObject(_quizDataList[0], true);
    AddQuizCardObject(_quizDataList[1], true);

    // _firstQuizCardObject = ObjectPool.Instance.GetObject();
    // _firstQuizCardObject.GetComponent<QuizCardController>()
    //     .SetQuiz(_quizDataList[0], 0, OnCompletedQuiz);
    //
    // _secondQuizCardObject = ObjectPool.Instance.GetObject();
    // _secondQuizCardObject.GetComponent<QuizCardController>()
    //     .SetQuiz(_quizDataList[1], 1, OnCompletedQuiz);
    //
    // SetQuizCardPosition(_firstQuizCardObject, 0);
    // SetQuizCardPosition(_secondQuizCardObject, 1);
    //
    // // 마지막으로 생성된 퀴즈 인덱스
    // _lastGeneratedQuizIndex = 1;
}
private void OnCompletedQuiz(int cardIndex)
{
    if (cardIndex < _quizDataList.Count - 2)
    {
        AddQuizCardObject(_quizDataList[cardIndex + 2]);
    }
    else
    {
        AddQuizCardObject(null);
        if (cardIndex == _quizDataList.Count - 1)
        {
            // TODO: 스테이지 클리어
            _lastStageIndex++;

            // 새로운 스테이지 시작
            if (_lastStageIndex < Constants.MAX_STAGE_COUNT)
                StartCoroutine(OnCompleteOneSecond());
                
        }
    }
}

 

보면 알겠지만 참 좋지 않은 방법으로 노가다를 했다. 

분명...쉽게 만들고 줄이는 방법이 있을테지만 생각나지 않아..

그냥 넘어가던 것을 무조건 일이 DoTween이 진행되고 되도록 했다. 

차라리 Sequence라도 써볼걸 ㅎㅎㅎㅎㅎ

심지어 스테이지 클리어는 시간을 맞춰서 해버렸다. Oncomplete함수가 DoTween 내장함수라 ㅎㅎㅎ

 

 

놀라운 사실 : 깃으로 따로 저장하려다가 파일 날림

오히려 좋다 ! 새로 깔끔하게 만들어야지 


 

강사님 코드 (진행중)

강사님은 이번엔 또 새로운 방식으로 추가해 주실것이라고 하셨다.

상태패턴느낌으로  !

 

간단하게 인터페이스와 상속 개념을 설명해주셨다. 

저 세 가지를 동시에 처리하고 싶은데, 이 상태로는 안된다. (SetState의 매개변수로 넣고 싶은데)

그래서 저 세가지의 공통점을만들어야 한다. 

 

이런 식으로 부모 클래스를 넣어주면 자식 클래스들을 모두 할당할 수 있다. 

혹은 인터페이스도 가능하다. 

 

 

 

 

 

부모의 생성자를 호출하는 것 . 

확실히 모르겠어서 따로 공부할 예정이다.

 

 

오늘의 목표

1. 코테 1레벨 3페이지

2. Task / await  - async 개념 정리