본문 바로가기

종스크롤 슈팅게임(1942)

4. 적 전투기 총알 & 플레이어 피격 이벤트 구현

먼저 적 전투기 생성 위치를 더 추가해보도록 하겠습니다.

스폰포인트 좌우 2개씩 추가

좌우 각 2개씩 4개가 추가되어 스폰포인트는 총 9개가 되었습니다. GameManager 스크립트에 있는 배열을 갱신해줍니다.

 

이어서, GameManager 스크립트에서 스폰 포인트 선택 난수 로직을 수정합니다. 

난수 0~4 사이 출력 -> 0~8 사이 출력으로 수정

    void spawnEnemy() {
        int ranPoint = Random.Range(0, 9);
    }

 

그 다음으로 양 옆에서 나오는 전투기들의 방향을 수정해 보겠습니다.

    void spawnEnemy() {
        //Enemy Spawn
        int ranEnemy = Random.Range(0, 3);
        int ranPoint = Random.Range(0, 9);
        GameObject enemy = Instantiate(enemyObjs[ranEnemy], spawnPoint[ranPoint].position, spawnPoint[ranPoint].rotation);
        Enemy enemyScript = enemy.GetComponent<Enemy>();
        Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
        if (ranPoint == 5 || ranPoint == 7)//왼쪽에서 스폰
        {
            enemy.transform.Rotate(new Vector3(0, 0, 45)); //45도 회전
            rigid.velocity = new Vector2(enemyScript.speed, -1); //남동쪽으로 이동
        }
        else if (ranPoint == 6 || ranPoint == 8)//오른쪽에서 스폰
        {
            enemy.transform.Rotate(new Vector3(0, 0, -45)); //45도 회전
            rigid.velocity = new Vector2(enemyScript.speed * -1, -1); //남서쪽으로 이동
        }
        else { //탑에서 스폰
            rigid.velocity = Vector2.down * enemyScript.speed;
        }
    }

 

 

이제 적 전투기가 총알을 쏘도록 구현해보겠습니다.

먼저, 플레이어 Bullet 프리펩을 복사 수정해 적 전투기용 Bullet 프리펩을 만들겠습니다. 

총알 프리펩 하나를 Ctrl + D를 눌러 복사

잘 보면 복사한 프리펩의 인스펙터에서는 이름 수정이 되지 않는 걸 볼 수 있습니다. 따라서 Open Prefab 클릭

프리펩 창이 뜨는데, 인스펙터에서 이름을 수정하고, 스프라이트를 바꿔줍니다.

프리펩 창은 자동저장이 되므로 프리펩 창을 나가더라도 변경사항이 적용됩니다. 

Enemy Bullet A
Enemy Bullet B

위처럼 Enemy Bullet A 타입과 B타입을 만들어줍니다.

 

그리고 아래 변수를 추가하고, 적 전투기 각각에 Enemy Bullet 2종을 맵핑해줍니다.

public float maxShotDelay;
public float curShotDelay;
public string enemyName;

//Bullets & Player
public GameObject bulletObjA;
public GameObject bulletObjB;

위 사진 속 Enemy Name이 S와 L인 적 전투기만 총알을 쏘게 구현하겠습니다.

    void Update(){
    	fire();
        reload();
    }
    
    void fire()
    {
        if (curShotDelay < maxShotDelay)
        {
            return;
        }

        if (enemyName == "S")
        {
            GameObject bullet = Instantiate(bulletObjA, transform.position + new Vector3(0, -0.7f, 0), transform.rotation);
            Rigidbody2D rigid = bullet.GetComponent<Rigidbody2D>();
            Vector3 dirVec = player.transform.position - transform.position; //플레이어 위치 - 적 전투기 위치
            rigid.AddForce(dirVec.normalized * 5, ForceMode2D.Impulse); //normalized로 dirVec을 단위 값(1)로 변환 
        }
        else if (enemyName == "L") {
            GameObject bulletL = Instantiate(bulletObjB, transform.position + new Vector3(-0.2f, -0.7f, 0), transform.rotation);
            GameObject bulletR = Instantiate(bulletObjB, transform.position + new Vector3(0.2f, -0.7f, 0), transform.rotation);
            Rigidbody2D rigidL = bulletL.GetComponent<Rigidbody2D>();
            Rigidbody2D rigidR = bulletR.GetComponent<Rigidbody2D>();
            Vector3 dirVecL = player.transform.position - transform.position;
            Vector3 dirVecR = player.transform.position - transform.position;
            rigidL.AddForce(dirVecL.normalized * 5, ForceMode2D.Impulse);
            rigidR.AddForce(dirVecR.normalized * 5, ForceMode2D.Impulse); 

        }

        curShotDelay = 0;
    }
    
        void reload()
    {
        curShotDelay += Time.deltaTime;
    }

이때 적 전투기의 총알이 플레이어의 위치 좌표를 읽고 그 위치로 쏘아져야 하는데, 그러기 위해선 플레이어의 위치정보가 필요합니다. Enemy 스크립트에 Player를 맵핑하면 될 것 같지만, 프리펩(적 전투기)은 하이라키의 게임 오브젝트에는 접근하지 못하고, 같은 프리펩만 접근 할 수 있으므로 Enemy 스크립트에 바로 Player를 맵핑할 수 없습니다. 따라서 GameManager 스크립트에 Player를 맵핑 하고(게임 매니저 오브젝트는 인스턴스화 되어있기 때문에 접근 가능), 적 전투기가 생성될 때 Enemy 스크립트의 Player 변수에 GameManager의 Player변수를 복사해주겠습니다.

GameManager 스크립트에 변수 추가 후 맵핑

    void spawnEnemy() {
        //Enemy Spawn
        int ranEnemy = Random.Range(0, 3);
        int ranPoint = Random.Range(0, 9);
        GameObject enemy = Instantiate(enemyObjs[ranEnemy], spawnPoint[ranPoint].position, spawnPoint[ranPoint].rotation);
        Enemy enemyScript = enemy.GetComponent<Enemy>();
        enemyScript.player = player; //적 전투기 생성 시, 플레이어 오브젝트 정보를 복사해 넘겨줌
        Rigidbody2D rigid = enemy.GetComponent<Rigidbody2D>();
.
.
.
    }

Enemy 스크립트에도 player를 담을 변수 추가

Enemy 스크립트

 

마지막으로, 플레이어 피격 이벤트를 구현하겠습니다.

Player 스크립트에 GameManager 변수를 추가하고 맵핑합니다.

Player 스크립트

public GameManager gm; 

	void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Border")
        {
			...	
        }
        else if (collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyBullet") {
            gameObject.SetActive(false); //플레이어 비활성화
            gm.respawnPlayer(); //맵핑한 GameManager의 함수 호출
        }
    }

OnTriggerEnter2D에 적 전투기 또는 적 총알과 콜라이더 충돌했을 때 로직을 작성합니다.

플레이어가 비활성화가 되면 그 아래 로직이 정상적으로 작동하지 않으므로, GameManager에 대신 작성해서 호출하는 방식으로 구현합니다.

GameManager 스크립트에 아래 코드 추가

    public void respawnPlayer() {
        Invoke("respawnPlayerExe", 2f);
    }

    void respawnPlayerExe()
    {
        player.transform.position = Vector3.down * 3.5f; //플레이어 리스폰 위치
        player.SetActive(true); //플레이어 활성화
    }

결과