Skip to content

develop LightningRing

Yoo Hyeokjin edited this page Jul 6, 2023 · 2 revisions

LightningRing

목차

설명

  • 주인공 주위에 가장 많은 적을 타격하는 투사체이다. 자세한 설명은 번개반지에서 알 수 있다.
  • 번개반지를 구현할 때는 쿨타임이 지나면 instance를 생성하고 잠깐의 시간이 지나면 instance를 삭제하는 식으로 구현할 것이다.
  • 주인공 주위에 가장 많은 적의 위치를 찾아내야 하기 때문에 Physics2D.Overlap를 사용하여 일정 범위에 적의 수를 비교하여 위치를 정하여 공격하도록 구현했다.

Script

코드 설명

  • 코드를 보면 알겠지만 Weapon들은 Weapon.cs를 상속받아서 만들었고 해당 Weapon의 스텟을 WeaponTotalStats[((int)Enums.EWeaponStat.원하는 Stat)]으로 가져올 수 있다.
using UnityEngine;
using System;      // array의 IndexOf 함수
using System.Linq; // array의 Max, Min 함수 

public class LightningRing : Weapon
{
    private GameObject mNewObj;            // 생성한 instance를 저장할 변수
    private float mTimer = 0;              // 쿨타임과 지속시간을 체크할 타이머 변수       
    private bool mbExist = false;          // 생성되었는지 삭제되었는지 확인할 변수
    private Vector3[] lightningPosition;   // lightning이 떨어지는 위치를 저장하는 변수

    public override void Attack()
    {
        GameObject objPre; // SkillFiringSystem에 저장한 Weapon Prefab을 저장할 지역 변수
        if (IsEvoluction())
            objPre = SkillFiringSystem.instance.evolutionWeaponPrefabs[WeaponIndex];  // 진화 Weapon
        else
            objPre = SkillFiringSystem.instance.weaponPrefabs[WeaponIndex];           // 일반 Weapon
        mTimer += Time.deltaTime; // 게임 시간 동기화
        if (!mbExist && mTimer > WeaponTotalStats[((int)Enums.EWeaponStat.Cooldown)])
        { // KingBible이 존재하지 않고 쿨타임을 넘겼다면
            mNewObj = new GameObject("Lightnings"); // Lightnings을 담을 parent instance 생성
            mNewObj.transform.parent = GameObject.Find("SkillFiringSystem").transform; // SkillFiringSystem의 자식으로 해당 instance를 넣는다.

            lightningPosition = FindDenseClusterEnemy((int)WeaponTotalStats[((int)Enums.EWeaponStat.Amount)]); // FindDenseClusterEnemy으로 Lightning의 떨어질 위치를 계산해서 저장한다.
            for (int i = 0; i < WeaponTotalStats[((int)Enums.EWeaponStat.Amount)]; i++) // Lightnings 투사체 수를 만큼 parent instance에 추가한다.
            {
                GameObject lightning = Instantiate(objPre, GameObject.Find("Lightnings").transform); // 가져온 Prefab의 instance를 생성
                lightning.GetComponent<CircleCollider2D>().radius = 0.15f * (float)Math.Sqrt(WeaponTotalStats[((int)Enums.EWeaponStat.Area)]); // Level이 올라가면서 타격 범위가 넓어지도록 하는 코드
                lightning.transform.position = lightningPosition[i] + Vector3.up * 10; // 해당하는 위치에 Lightning을 떨어뜨린다.
            }
            mbExist = true; // KingBible이 존재함을 저장
            mTimer = 0;     // 지속시간 확인을 위한 초기화
        }
        else if (mbExist && mTimer > 0.3f)
        {
            Destroy(mNewObj); // Lightnings instance가 존재한다면 삭제
            mbExist = false;  // Lightnings 이 존재하지 않음을 저장
            mTimer = 0;       // 쿨타임 확인을 위한 초기화
        }
        if (IsEvoluction()) // 무기가 진화했다면
        {
            if (!mbExist && mTimer > WeaponTotalStats[((int)Enums.EWeaponStat.Cooldown)] / 2) 
            { // 쿨타임의 1/2 만큼 기다린 후 번개를 같은 위치에 한번 더 떨어뜨린다.
                mNewObj = new GameObject("Lightnings");
                mNewObj.transform.parent = GameObject.Find("SkillFiringSystem").transform;

                for (int i = 0; i < WeaponTotalStats[((int)Enums.EWeaponStat.Amount)]; i++)
                {
                    GameObject lightning = Instantiate(objPre, GameObject.Find("Lightnings").transform);
                    lightning.GetComponent<CircleCollider2D>().radius = 0.15f * (float)Math.Sqrt(WeaponTotalStats[((int)Enums.EWeaponStat.Area)]);
                    lightning.transform.position = lightningPosition[i] + Vector3.up * 10;
                }
                mbExist = true;
                mTimer = 0;
            }
            else if (mbExist && mTimer > 0.3f)
            {
                Destroy(mNewObj);
                mbExist = false;
                mTimer = 0;
            }
        }
    }
    public override void EvolutionProcess() // 무기 진화시 한 번 호출됨
    {

    }
    private Vector3[] FindDenseClusterEnemy(int Amount)
    { // Player 근처의 적이 가장 많이 모여있는 개체의 position을 찾는 함수다.
        Collider2D[] enemies = Physics2D.OverlapAreaAll(GameManager.instance.Player.transform.position + Vector3.left * 10 + Vector3.up * 5, GameManager.instance.Player.transform.position + Vector3.right * 10 + Vector3.down * 5, LayerMask.GetMask("Monster"));
        // Player를 기준으로 일정 네모난 공간에서 Layer가 Monster인 개체를 찾아서 enemies에 넣는다.
        Vector3[] results = new Vector3[Amount]; // Lightning이 떨어질 위치를 return할 결과를 저장하는 변수
        int[] enemiesNumber = new int[enemies.Length]; // 일정 Area에 존재하는 Enemy 객체 주위에 있는 다른 Enemy의 수를 저장하는 변수
        int count = 0; // index로 사용하기 위한 변수
        foreach (Collider2D enemy in enemies)
        { // enemies가 가지고 있는 enemy를 하나씩 순회하며 근처에 있는 다른 Enemy의 수를 저장한다.
            enemiesNumber[count++] = Physics2D.OverlapCircleAll(enemy.transform.position, 0.15f * (float)Math.Sqrt(WeaponTotalStats[((int)Enums.EWeaponStat.Area)])).Length;
            // 일정 원 범위에 있는 Enemy들을 array로 반환하기에 Length를 사용해 개수를 파악한다.
        }
        count = 0;
        results[count++] = enemies[Array.IndexOf(enemiesNumber, enemiesNumber.Max())].transform.position; // 그 중 가장 많이 모여있는 개체의 위치를 저장한다.
        enemiesNumber[Array.IndexOf(enemiesNumber, enemiesNumber.Max())] = 0; // 가장 컸던 개체의 수를 0으로 하여 다음에 탐색시 찾지 못하도록 한다.
        for(int i = 0; i < enemies.Length; i++)
        { // 존재하는 Enemy의 수만큼 탐색을 한다.
            if (count == Amount) break; // 저장한 position의 개수가 Lightning의 개수와 같아지면 탐색을 멈춘다.
            float distance = Vector3.Distance(results[count - 1], enemies[Array.IndexOf(enemiesNumber, enemiesNumber.Max())].transform.position);
            // 이전에 찾은 Enemy의 위치와 다음에 모여있는 군집의 거리를 계산한다.
            if (distance > 5f) // 각 Lightning이 뭉쳐서 떨어지면 안되기 때문에 일정 거리보다 떨어져서 떨어뜨리기 위한 코드다.
            {
                results[count++] = enemies[Array.IndexOf(enemiesNumber, enemiesNumber.Max())].transform.position;
                enemiesNumber[Array.IndexOf(enemiesNumber, enemiesNumber.Max())] = 0;
                // 전 Lightning position에서 일정 거리 떨어진 후 많이 뭉쳐있는 Enemy의 position을 저장하고 다음 탐색에 걸리지 않도록 초기화 해준다.
            }
            else // 만약 거리가 가깝다면 다음 탐색을 위해 해당 position을 초기화 한다.
            {
                enemiesNumber[Array.IndexOf(enemiesNumber, enemiesNumber.Max())] = 0;
            }
        }
        
        return results; // Lightning position을 return한다.
    }
}

Prefab

다음의 Component를 추가한다.

  • Animator
  • SpriteRenderer
  • Rigidbody2D
  • BoxCollider2D
  • KingBible.cs

다음과 같이 Prefab을 만들어 준다.

image
image

Clone this wiki locally