Unity 입문 TopDown Shooting - 공격 시스템 구현

Amberjack·2024년 1월 18일
0

Unity

목록 보기
11/44
post-custom-banner

먼저 핵심 내용을 살펴보자!

🖨️ 프리팹(Prefab)

  • 프리팹은 Unity 게임 엔진에서 사용되는 게임 오브젝트를 재사용 가능하고 관리하기 쉽게 만들기 위한 템플릿.
  • 프리팹을 사용하면 게임 오브젝트와 그에 관련된 컴포넌트 및 설정을 미리 정의하고, 여러 장면이나 게임에서 재사용할 수 있다.
  • 프리팹은 인스턴스화를 통해 실제 게임 오브젝트로 변환될 수 있으며, 이 때 모든 프로퍼티와 컴포넌트 설정이 복사된다.
  • 프리팹의 변경사항은 모든 인스턴스에 즉시 반영되므로, 일관성을 유지하고 일괄적인 업데이트를 쉽게 할 수 있다.
  • 프리팹은 레벨 디자인, 재사용 가능한 게임 요소(캐릭터, 아이템, 장애물 등)의 생성, 프로토타이핑 등에 주로 사용된다.

🖨️ Instantiate 함수

  • Instantiate 함수는 Unity에서 제공하는 메서드로, 주어진 원본 개체의 복사본을 새로 생성하고 이를 반환한다.
  • 이 함수는 주로 게임 오브젝트를 동적으로 게임세계에 추가할 때 사용한다.
  • Instantiate 함수는 원본 개체의 모든 컴포넌트와 프로퍼티를 복사하여 새 게임 오브젝트를 생성한다.
  • 이 함수를 통해 생성된 게임 오브젝트는 독립적이며, 원본 개체에 대한 변화는 이에 영향을 주지 않는다.
  • Instantiate 함수는 원본 게임 오브젝트, 위치 및 회전 정보를 인자로 받을 수 있다.

🏹 공격 시스템과 총알 만들기!!

Entities 밑에 TopDownShooting.cs를 생성하자.

public class TopDownShooting : MonoBehaviour
{
    private TopDownCharacterController _controller;

    [SerializeField] private Transform projectileSpawnPosition;
    
    // Vector2.right : 벡터를 계속 새로 생성하지 말고 기본값 Vector2.right를 재사용하기 위한 코드
    private Vector2 _aimDirection = Vector2.right;      

    private void Awake()
    {
        _controller = GetComponent<TopDownCharacterController>();
    }
}

일단 여기까지 작성하고 TopDownCharacterController.cs로 와서 OnAttackEvent를 추가하자.

public class TopDownCharacterController : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent;
    public event Action<Vector2> OnLookEvent;
    public event Action OnAttackEvent;

    private float _timeSinceLastAttack = float.MaxValue;    // 마지막으로 공격했던 시간
    protected bool IsAttacking {  get; set; }
    
    // 하위 클래스에서 상속받아서 사용할 수 있도록
	protected virtual void Update()
	{
    	HandleAttackDelay();
	}

	private void HandleAttackDelay()
	{
    	// 공격 딜레이
    	if(_timeSinceLastAttack <= 0.2f)        // 이후 수정
    	{
        	_timeSinceLastAttack += Time.deltaTime;
    	}
    	// 공격 딜레이가 초과되었고 공격을 했다면
    
    	if (IsAttacking && _timeSinceLastAttack > 0.2f)
    	{
        	// 공격 딜레이 초기화.
        	_timeSinceLastAttack = 0;
        	CallAttackEvent();
    	}
	}

    public void CallMoveEvent(Vector2 direction)
    {
        OnMoveEvent?.Invoke(direction);
    }

    public void CallLookEvent(Vector2 direction)
    {
        OnLookEvent?.Invoke(direction);
    }

    public void CallAttackEvent()
    {
        OnAttackEvent?.Invoke();
    }
}

이후 OnAttackEvent를 받아오기 위해 PlayerInputcontroller.cs의 OnFire를 수정해주자.

public void OnFire(InputValue value)
{
    IsAttacking = value.isPressed;      // 공격 키가 입력이 되면
}

이후 TopDownShooting.cs에서 이벤트를 구독하자.

public class TopDownShooting : MonoBehaviour
{
    private TopDownCharacterController _controller;

    [SerializeField] private Transform projectileSpawnPosition;
    private Vector2 _aimDirection = Vector2.right;      // Vector2.right; 벡터를 계속 새로 생성하지 말고 기본값 Vector2.right를 재사용하기 위한 코드

    private void Awake()
    {
        _controller = GetComponent<TopDownCharacterController>();
    }

    // Start is called before the first frame update
    void Start()
    {
        _controller.OnAttackEvent += OnShoot;
        _controller.OnLookEvent += OnAim;
    }

    private void OnAim(Vector2 newAimDireciton)
    {
        _aimDirection = newAimDireciton;
    }

    private void OnShoot()
    {
        CreateProjectile();
    }

    private void CreateProjectile()
    {
        Debug.Log("Fire");      // 구독 확인용.
    }
}

Input에서 Event를 콜 하면, 구독되어 있는 곳에 전부 뿌려준다.

이후 플레이어에게 TopDownShooting.cs를 연결해주고 확인해보자!

정상적으로 작동하는 모습!

🎯 화살 생성하기

화살 스프라이트를 생성한 후, Order in Layer를 6으로 맞추자.

이후, Create Empty를 해서 이름을 Arrow로 수정한다. 생성한 화살 스프라이트를 Arrow 밑으로 넣어준다.

그리고 화살이 현재 위쪽을 바라보고 있으므로 Rotation의 Z축을 -90으로 변경해준다.

🖨️ 화살 프리팹 시키기

먼저 Prefabs 폴더를 생성하자. 그 밑에 Projectiles 폴더를 생성하자.

이후 만든 Arrow를 Projectiles 폴더에 옮긴다.

옮기면 Arrow가 파랑색으로 변하는 것을 확인할 수 있는데, 이것이 프리팹이 된 것이다. 이제 프리팹에 있는 Arrow가 원본이 되었기 때문에, 하이라키에 있는 Arrow는 삭제해도 된다.

이제 테스트로 화살이 생성되는지 확인해보자.

// TopDownShooting.cs

private void CreateProjectile()
{
    // 임시로 화살이 생성되는지만 확인하는 코드
    // Instantiate의 기본 오버라이딩은 Instantiate(복제할 게임 오브젝트, 복제할 부모 오브젝트) 로 정의되어 있기 때문에
    // Instantiate(복제할 게임 오브젝트, 생성할 위치, Rotation); -> Instantiate에서 position 값으로 생성하기 위해서는 해당 오버라이딩을 사용해야 한다.
    Instantiate(testPrefab, projectileSpawnPosition.position, Quaternion.identity);     // Quaternion.identity : Vector3 (0, 0, 0)과 같다.
}

확인해보자!!!

화살이 생성되는 모습! ▼

post-custom-banner

0개의 댓글