개발/개발일지

Tales Saga Chronicle Blast 개발일지 17 - 스킬 구현, UI 추가, 적 개체 소환 구현, 코드 명명 규칙 적용 등

메피카타츠 2023. 3. 21. 02:05

이번에 추가한 이미지는 이 2종이다. 위는 아리스의 헤일로 이미지, 아래는 게임 화면을 나타낼 Bar 모양 Sprite다.

 

이외에는 기획했던 것처럼 오른쪽엔 점수와 남은 목숨을, 왼쪽에는 미도리의 일러스트를 추가했다.

왼쪽의 일러스트는 스토리에서 사용한 것을 가져와서 적을 처치하면 웃으며 점프하는 부분까지 추가했다.

 

 

또, 오브젝트 풀링 기법을 적용하여 적을 소환하는 기능을 추가했는데, 헤일로 이미지에도 같은 기술을 적용하다보니 구현이 비슷한 부분들이 많아 하나의 함수로 통합했다.

private GameObject GetFrefab(string name)
    {
        if(name == "MidoriHalo")
        {
            if (_midoriHaloQueue.Count > 0)
            {
                return _midoriHaloQueue.Dequeue();
            }
            else
            {
                return CreateNewMidoriHalo();
            }
        }
        else if(name == "MidoriBullet")
        {
            if (_midoriBulletQueue.Count > 0)
            {
                return _midoriBulletQueue.Dequeue();
            }
            else
            {
                return CreateNewMidoriBullet();
            }
        }
        if (name == "PinkEnemy")
        {
            if (_pinkEnemyQueue.Count > 0)
            {
                return _pinkEnemyQueue.Dequeue();
            }
            else
            {
                return CreateNewEnemy(name);
            }
        }
        else if (name == "GreenEnemy")
        {
            if (_greenEnemyQueue.Count > 0)
            {
                return _greenEnemyQueue.Dequeue();
            }
            else
            {
                return CreateNewEnemy(name);
            }
        }
        else if (name == "PurpleEnemy")
        {
            if (_purpleEnemyQueue.Count > 0)
            {
                return _purpleEnemyQueue.Dequeue();
            }
            else
            {
                return CreateNewEnemy(name);
            }
        }
        else if (name == "YellowEnemy")
        {
            if (_yellowEnemyQueue.Count > 0)
            {
                return _yellowEnemyQueue.Dequeue();
            }
            else
            {
                return CreateNewEnemy(name);
            }
        }
        else
        {
            Debug.Log("GetFrefab 이름 오류");
            return null;
        }
    }

 

추가로 미도리의 스킬을 구현했다.

private IEnumerator MidoriSkill()
    {
        _isActivatingSkill = true;

        int aliveEnemyCount = _aliveEnemyParent.transform.childCount;

        List<float> distanceList = new List<float>();
        float distance;

        int[] minIndexArray = new int[5];
        GameObject[] midoriHaloArray = new GameObject[5];

        // 살아있는 적 개체들의 거리를 List에 저장
        for(int i=0; i<aliveEnemyCount; i++)
        {
            GameObject enemy = _aliveEnemyParent.transform.GetChild(i).gameObject;

            distance = Vector2.Distance(enemy.GetComponent<RectTransform>().anchoredPosition, midoriAirplane.GetComponent<RectTransform>().anchoredPosition);

            distanceList.Add(distance);
        }


        audioManager.PlaySFX("MidoriSkill");
        // 가장 거리가 가까운 적 5명의 index를 저장
        for(int i=0; i<5; i++)
        {
            minIndexArray[i] = distanceList.IndexOf(distanceList.Min());
            distanceList[minIndexArray[i]] = distanceList.Max() + 1; // 제일 가까운 적에게 최댓값 + 1 을 덧씌워서 2, 3번째로 가까운 적을 차례로 찾도록 함
            Debug.Log(minIndexArray[i]);
        }

        // 가장 거리가 가까운 적 최대 5명에게 헤일로를 씌움
        for(int i=0; i< distanceList.Count; i++)
        {
            midoriHaloArray[i] = GetFrefab("MidoriHalo");
            midoriHaloArray[i].SetActive(true);
            midoriHaloArray[i].transform.SetParent(_aliveEnemyParent.transform.GetChild(minIndexArray[i]));
            midoriHaloArray[i].GetComponent<RectTransform>().anchoredPosition = new Vector2(0, 0);
            midoriHaloArray[i].GetComponent<Image>().DOFade(1, 1);
        }

        yield return new WaitForSeconds(1);
        
        // 가장 거리가 가까운 적 5명에게 총알을 발사하며 씌워진 헤일로 없애기
        for(int i=0; i<5; i++)
        {
            // 씌운 헤일로가 있을 때만 동작
            if (midoriHaloArray[i] != null)
            {
                midoriHaloArray[i].GetComponent<Image>().DOFade(0, 1);
                midoriHaloArray[i].transform.SetParent(_aliveEnemyParent.transform.GetChild(minIndexArray[i]));
            }

            StartCoroutine(ShootMidoriBullet(_aliveEnemyParent.transform.GetChild(minIndexArray[i]).GetComponent<RectTransform>().anchoredPosition));

            yield return new WaitForSeconds(0.2f);
        }

        // 헤일로 반환
        for(int i=0; i< distanceList.Count; i++)
        {
            midoriHaloArray[i].transform.SetParent(haloParent.transform);
            _midoriHaloQueue.Enqueue(midoriHaloArray[i]);
        }

        _isActivatingSkill = false;
    }

 

 

 

스킬을 사용하면 소리와 함께 가장 가까운 적 5명을 스캔하고, 스캔한 적에게 미도리의 헤일로 이미지를 띄운다.

이후 헤일로가 사라지며 총알을 1발씩 총 5발 발사한다.

5명보다 적은 경우, 가까운 적 순서로 추가 총알을 발사한다. / 예) 적이 세 명인 경우 거리 순으로 1, 2, 3, 1, 2

 

이를 위해 총알이 적 방향으로 날아갈 때 적이 위치한 방향을 향하도록 해야했는데, 이런 기능을 하는 함수가 있긴 했으나 3D를 기준으로 되어있어서 2D에서도 정상적으로 작동시키기 위해 작업이 필요했다.

// mainObject가 direct을 바라보도록 회전
    private void LookRotation2D(GameObject mainObject, Vector2 direction)
    {
        Vector3 vectorToTarget = direction - mainObject.GetComponent<RectTransform>().anchoredPosition;
        vectorToTarget.z = 0;
        float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg - 90;
        mainObject.transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    }

그래서 이 함수를 만들어서 사용했다. 검색해서 찾은 내용을 내 상황에 맞게 수정했는데, 회전할 객체를 기준으로 목표까지의 Vector 값을 가져와서 Atan2 함수를 이용해 해당 위치까지의 각도를 라디안 단위로 계산하고, 여기에 Mathf.Rad2Deg를 곱해서 각도로 변환해주는 것 같다. -90은 안 하는 경우도 많던데 나의 경우는 해야 제대로 작동되었다.

 

 

그리고 코드의 명명 규칙을 만들어서 가독성을 좋게 하기로 했다.

멤버 변수는 변수 이름 앞에 _를, 상수는 이름 앞에 s_를 붙이는 등을 적용했다.

그리고 Button의 이름이 뒤죽박죽이라 이름 뒤에 Btn을 붙이는 등으로 통일했다.

C#에 관해서는 마이크로소프트의 가이드를 참조했으나, 유니티에서 변수나 함수 등의 이름을 짓는 규칙에 대해서도 찾아봤으나 이렇다 싶은 좋은 자료는 찾아보지 못했다.

그래도 내 나름대로의 규칙을 만들어 적용하고 깔끔하게 코드를 작성하는 습관을 들이는 것이 좋을 것 같았고, 이렇게 하면서 포트폴리오 등에서도 언급할 수 있을 것 같았다.

 

오늘까지 완성한 부분은 다음과 같다.

점점 이것저것 하나씩 추가되다보니 조금씩 게임다운 느낌이 나는 것 같다.

 

내일 목표는 아래와 같다.

1. 스킬로 적을 처치할 때 일부 경우에서 적이 정상적으로 사망 처리가 되지 않는 버그 수정하기

2. 적이 죽을 때 폭발하는 이미지 등 찾기

3. 공격, 스킬 아이콘 표시하고 쿨타임 가시화하기

4. 스킬 쿨타임 중 사용시 유저에게 알려주는 기능 추가(텍스트 혹은 경고음 등으로)

5. 적에게 닿으면 아군 비행기 폭발하는 기능 구현

 

 

오늘 작성한 것은 총 3일치의 개발 일지인데, 블로그에 글은 안올렸지만 매일 꾸준히 깃에 커밋은 했다. 또, 매일 도트 리소스를 찍는 것을 목표로 하긴 했으나 지금 당장 그릴만한 리소스가 없어서 이 목표는 당분간 보류해야겠다. 그리고 주말 동안 이것저것 많이 찾아보고 고민도 많이 했다.

고민한 내용을 간략히 적자면, 나는 게임 개발하는 것이 즐겁고, 앞으로도 계속 이 일을 하고 싶다. 혼자서 게임을 만드는 것은 어렵기 때문에 함께 게임을 만들 수 있고 경력과 경험을 쌓을 수 있는 회사에 들어갈 필요가 있다. 이를 위해 여러 기술들을 적용하고, 코드 퀄리티에 신경쓰면서 이런 것들을 기록하고 어필하여 매력적인 포트폴리오를 만들어야 한다. 또한, 3D 게임을 다뤄본 적이 거의 없다시피 하기 때문에 이런 것도 다룰 수 있는 기회가 필요하다. 이를 위해 강의를 하나 샀다. 가격은 좀 비싸긴 하지만 지금의 나에게 딱 필요한 강의라고 생각해서 구입했다. 현재 만드는 게임을 완성하고 이를 포트폴리오로 한 번 도전해보고, 안되면 3D 게임도 만들어서 도전해보고, 그래도 안 된다면... 인디게임을 만들면서 출시도 해보고 경험을 쌓아나가야겠다. 그러면서 많은 기술들을 활용해보고, 지식들도 쌓이면 음... 매력적인 개발자가 되지 않을까? 아마 기회가 있을 것이다. 그러기 위해서라도 열심히 해야겠다.