아카이브

[개발일지] Undead Survivor 5일차 본문

2D 콘텐츠 제작

[개발일지] Undead Survivor 5일차

timbercat 2023. 9. 19. 10:17

자동 원거리 공격 구현

Enemy 레이어 추가 후 프리팹에 지정

몬스터 스캔을 담당할 스크립트 추가

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Scanner : MonoBehaviour
{
    //범위, 레이어, 스캔 결과 배열, 가장 가까운 목표를 담을 변수 생성
    public float scanRange;
    public LayerMask targetLayer;
    public RaycastHit2D[] targets;
    public Transform nearestTarget;

    void FixedUpdate() //스캔을 하기위한 로직
    {
        //CircleCastAll: 원형의 캐스트를 쏘고 모든 결과를 반환하는 함수
        //1. 캐스팅 시작 위치 2. 원의 반지름 3. 캐스팅 방향 4. 캐스팅 길이 5.대상 레이어
        targets = Physics2D.CircleCastAll(transform.position, scanRange, Vector2.zero, 0, targetLayer);
        nearestTarget = GetNearest();

    }

    //가장 가까운 것을 찾는 함수 추가
    Transform GetNearest()
    {
        Transform result = null;
        float diff = 100;

        foreach(RaycastHit2D target in targets) {
            Vector3 myPos = transform.position;
            Vector3 targetPos = target.transform.position;
            float curDiff = Vector3.Distance(myPos, targetPos);

            if (curDiff < diff)
            {
                diff = curDiff;
                result = target.transform;
            }
        }

        return result;
    }
}

플레이어 오브젝트에 Scanner 스크립트 추가 후 설정

총알 생성하기

Bullet 1프리팹, Weapon 1오브젝트 설정

풀 매니저에 Bullet 1프리팹 추가

Weapon.cs와 Player.cs에 코드 추가

scanner 추가

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Weapon : MonoBehaviour
{
    public int id;
    public int prefabId;
    public float damage;
    public int count;
    public float speed;

    float timer;
    Player player;

    void Awake()
    {
        player = GetComponentInParent<Player>(); //부모의 컴포넌트 가져오기
    }

    void Start()
    {
        Init();
    }

    // Update is called once per frame
    void Update()
    {
        switch (id)
        {
            case 0:
                transform.Rotate(Vector3.back * speed * Time.deltaTime);
                break;
            default:
                timer += Time.deltaTime;

                if(timer > speed)
                {
                    timer = 0f;
                    Fire();
                }
                break;
        }

        // Test
        if (Input.GetButtonDown("Jump"))
        {
            LevelUp(20, 5);
        }
    }

    public void LevelUp(float damage, int count)
    {
        this.damage = damage;
        this.count += count;

        if(id ==0)
            Batch();
    }

    public void Init()
    {
        switch (id)
        {
            case 0:
                speed = 150;
                Batch();
                break;
            default:
                speed = 0.3f;
                break;
        }
    }

    void Batch()
    {
        for(int index = 0; index < count; index++)
        {
            Transform bullet;

            if(index < transform.childCount)
            {
                bullet = transform.GetChild(index); //인덱스가 childCount 범위 내라면 GetChild 함수로 가져오기
            }
            else
            {
                //기존 오브젝트 먼저 활용하고 모자란 것은 풀링에서 가져오기
                bullet = GameManager.instance.pool.Get(prefabId).transform; //가져온 오브젝트의 Transform을 지역변수로 저장
                bullet.parent = transform;
            }

            bullet.localPosition = Vector3.zero;
            bullet.localRotation = Quaternion.identity;

            Vector3 rotVec = Vector3.forward * 360 * index / count;
            bullet.Rotate(rotVec);
            bullet.Translate(bullet.up * 1.5f, Space.World);
            bullet.GetComponent<Bullet>().Init(damage, -1); //-1 은 무한으로 관통하는 근접공격
        }
    }

    void Fire()
    {
        if (!player.scanner.nearestTarget)
            return;

        Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
        bullet.position = transform.position;
    }
}

총알 발사

Bullet 1 프리팹에 Rigidbody 부착

Gravitiy 0으로 설정

Bullet 스크립트에 코드 작성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    public float damage;
    public int per;

    Rigidbody2D rigid;

    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
    }

    public void Init(float damage, int per, Vector3 dir)
    {
        this.damage = damage;
        this.per = per;

        if(per > -1) {
            rigid.velocity = dir * 15f; //속력을 곱해서 총알이 날아가는 속도 증가
        }
    }

    void OnTriggerEnter2D(Collider2D collision)
    {
        if (!collision.CompareTag("Enemy") || per ==-1)
            return;

        per--;

        if(per == -1) { 
            rigid.velocity = Vector2.zero;
            gameObject.SetActive(false);
        }
    }
}

Weapon.cs에 코드 추가

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Weapon : MonoBehaviour
{
    public int id;
    public int prefabId;
    public float damage;
    public int count;
    public float speed;

    float timer;
    Player player;

    void Awake()
    {
        player = GetComponentInParent<Player>(); //부모의 컴포넌트 가져오기
    }

    void Start()
    {
        Init();
    }

    // Update is called once per frame
    void Update()
    {
        switch (id)
        {
            case 0:
                transform.Rotate(Vector3.back * speed * Time.deltaTime);
                break;
            default:
                timer += Time.deltaTime;

                if(timer > speed)
                {
                    timer = 0f;
                    Fire();
                }
                break;
        }

        // Test
        if (Input.GetButtonDown("Jump"))
        {
            LevelUp(10, 1);
        }
    }

    public void LevelUp(float damage, int count)
    {
        this.damage = damage;
        this.count += count;

        if(id ==0)
            Batch();
    }

    public void Init()
    {
        switch (id)
        {
            case 0:
                speed = 150;
                Batch();
                break;
            default:
                speed = 0.3f;
                break;
        }
    }

    void Batch()
    {
        for(int index = 0; index < count; index++)
        {
            Transform bullet;

            if(index < transform.childCount)
            {
                bullet = transform.GetChild(index); //인덱스가 childCount 범위 내라면 GetChild 함수로 가져오기
            }
            else
            {
                //기존 오브젝트 먼저 활용하고 모자란 것은 풀링에서 가져오기
                bullet = GameManager.instance.pool.Get(prefabId).transform; //가져온 오브젝트의 Transform을 지역변수로 저장
                bullet.parent = transform;
            }

            bullet.localPosition = Vector3.zero;
            bullet.localRotation = Quaternion.identity;

            Vector3 rotVec = Vector3.forward * 360 * index / count;
            bullet.Rotate(rotVec);
            bullet.Translate(bullet.up * 1.5f, Space.World);
            bullet.GetComponent<Bullet>().Init(damage, -1, Vector3.zero); //-1 은 무한으로 관통하는 근접공격
        }
    }

    void Fire()
    {
        if (!player.scanner.nearestTarget)
            return;

        //총알이 나아갈려고 하는 방향 계산
        Vector3 targetPos = player.scanner.nearestTarget.position;
        Vector3 dir = targetPos - transform.position;
        dir = dir.normalized;

        Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
        //위치, 회전 결정
        bullet.position = transform.position;
        bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir); //FromToRotation() : 지정된 축을 중심으로 회전하는 함수
        //Bullet 스크립트에 전달
        bullet.GetComponent<Bullet>().Init(damage, count, dir);
    }
}