[Unity] 플레이어를 향해 총알을 날려보자

ChangBeom·2024년 9월 10일
0

Unity

목록 보기
3/8


내가 현재 공부할 겸(?) 개발하고 있는 게임은 Dodge기반 게임이다. 그래서 오늘은 사방에서 플레이어를 향해 날라오는 총알을 구현할 것이다.

[1. 총알 발사하기]

 총알을 발사하는 방법은 여러가지가 있을 수 있는데 오늘은 2가지 방법을 소개한다.

[1.1 첫번째 방법]

 첫번째 방법은 플레이어와 총알을 발사하는 위치에 따라 속력이 변하는 스크립트이다.


//	Bullet.cs

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

public class Bullet : MonoBehaviour
{
    Vector3 playerPos;
    Vector3 bulletPos;
    Vector3 newPos;

    public float speed = 0.01f;

    void Start()
    {
        playerPos = GameObject.Find("Player").transform.position;
        bulletPos = transform.position;

        newPos = (playerPos - bulletPos) * speed;

        Destroy(gameObject, 5f);
    }
    void FixedUpdate()
    {
        transform.position = transform.position + newPos;
    }
}

 간단하게 설명하면 플레이어 위치와 총알 위치를 통해 이동간격을 정하고 매 프레임마다 조금씩 움직이는 로직이다. speed가 0.01f로 설정되어 있으면 매프레임 총알이 플레이어를 향해 1%씩 움직인다는 뜻이다.
 이 로직은 장점이자 단점이 거리에 상관없이 총알이 플레이어에 닿는 시간이 일정하다는 것이다. 따라서 총알이 발사되는 위치가 플레이어로부터 멀수록 총알의 속도가 빠르다는 것이다.
 이 게임의 특성상 화면 밖에서 총알이 날라오는 경우도 있는데, 위와 같은 방법으로 구현하면 너무 빨라서 피하기 힘들다는 이유로 이 방법이 아닌 다른 방법을 통해 구현하려고 한다.

[1.2 두번째 방법]

 두번째 방법은 훨씬 간단한 방법이다. 플레이어가 있는 방향에 일정한 속력으로 총알을 발사하는 방법이다.


//	Bullet.cs

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

public class Bullet : MonoBehaviour
{
    public float speed;

    void Start()
    {
        GetComponent<Rigidbody2D>().AddForce(transform.right * speed, ForceMode2D.Impulse);

        Destroy(gameObject, 5f);
    }
}

 두번째 방법에서 Bullet 스크립트에선 총알이 생성될 때 총알에 힘을 가해주는 것뿐이다. 이 방법에선 AddForce를 사용해야하므로 Bullet 오브젝트에 반드시 <Rigidbody2D>컴포넌트가 존재해야한다.

 이 스크립트만 봤을 때 AddForce의 방향이 right가 아니라 플레이어방향으로 설정해야 하는거 아니야? 라는 의문이 들 수 있다. 이제 이 궁금증을 해결하기 위해 총알을 생성하는 스크립트를 살펴보자.


//	BulletSpawner.cs

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

public class EnemyController : MonoBehaviour
{
    private Transform target;
    
    void Start()
    {
        target = GameObject.FindWithTag("Player").gameObject.transform;
    }

    
    void Update()
    {
        TargetRotaion();

        BulletSpawn();
    }

    void TargetRotaion()
    {
        Vector3 dir = target.transform.position - transform.position;

        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;

        transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    }

    void BulletSpawn()
    {
        //총알 생성
    }
}

 위 스크립트는 총알을 생성하는 오브젝트에 컴포넌트로 들어가있는 스크립트이다. TargetRotation() 함수가 총알을 생성하는 오브젝트가 항상 플레이어를 바라보게하는 함수이다. 조금 더 세부적으로 설명하면 플레이어와 총알의 위치를 토대로 기울기를 구하고, 기울기로 바라보는 방향의 각도를 구해서 그 각도만큼 회전시키는 방법이다.

이를 통해 총알을 생성하는 오브젝트는 항상 플레이어를 바라보는 방향으로 회전하기 때문에 총알을 생성하기만 하면 플레이어를 향해 날라가는 것이다.

[총알 생성 주기]

 총알을 발사하는 것을 설명하는 과정에서 BulletSpawner.cs 스크립트를 보여줬는데, 이 스크립트에는 당연히 총알을 생성하는 함수가 존재한다. BulletSpawn() 함수를 어떻게 구현할지 고민해봤는데 적당히 랜덤한 주기마다 총알을 발사하면 좋을 것 같다고 생각했다. 그래서 아래와 BulletSpawner.cs를 완성하게 되었ㄷ.


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

public class EnemyController : MonoBehaviour
{
    public GameObject bulletPrefab;

    public float spawnRateMin;
    public float spawnRateMax;
    private float spawnRate;
    private float timeAfterSpawn;

    private Transform target;
    
    void Start()
    {
        target = GameObject.FindWithTag("Player").gameObject.transform;

        timeAfterSpawn = 0f;

        spawnRate = Random.Range(spawnRateMin, spawnRateMax);
    }

    
    void Update()
    {
        TargetRotaion();

        BulletSpawn();
    }

    void TargetRotaion()
    {
        Vector3 dir = target.transform.position - transform.position;

        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;

        transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    }

    void BulletSpawn()
    {
        timeAfterSpawn += Time.deltaTime;

        if (timeAfterSpawn >= spawnRate)
        {
            timeAfterSpawn = 0f;

            GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);

            spawnRate = Random.Range(spawnRateMin, spawnRateMax);
        }
    }
}

 구현 방식에 대해 설명하자면 Time.deltaTime을 이용해서 실시간으로 시간을 체크해서 총알을 스폰할 시간이 되면 총알을 발사하는 방식이다. 총알을 스폰할 시간은 Random.Range를 사용해서 지정한 최소, 최대값 내의 랜덤한 시간으로 설정했다.

[완성]

 위에서 구현한 모든 스크립트를 게임에 적용해 완성한 모습이다.

0개의 댓글