프로젝트해요/게임_개발

[Unity] #6. 슈팅 게임 제작(2)

yenas0 2023. 7. 4. 09:59
반응형



1. 적 생성하기
2. 적 자동생성
3. 충돌처리 & 범위 제한


 


1. 적 생성하기


이번에는 적을 만들어 보도록 하자
 


큐브모양 오브젝트를 하나 더 생성한뒤 오브젝트 이름을 Enemy로 변경하고 스크립트도 생성하여 적용한다. 

 


 
enemy 오브젝트가 나를 향해 내려와야 하므로 아래방향으로 움직이는 스크립트를 작성한다.

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

public class Enemy : MonoBehaviour
{
    public float speed = 5;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 dir = Vector3.down;  //down은 (0,-1,0)을 나타냄. 즉 -y축방향으로 이동

        transform.position += dir * speed * Time.deltaTime;
    }
}

 
 

위의 코드를 실행하면 다음과 같은 결과가 나오게 된다.
 

 
 
 
 
 
 
다음은 총알과 적이 충돌 했을 때 충돌처리를 하는 스크립트를 작성해보도록한다.
 
 
Enemy 오브젝트에
[Add Component] - [Rigidbody] 를 설정한다.

 
 

 
생성한 뒤 Use Gravity를 비활성화 시킨다.
이 버튼을 활성화 할 시 빠른 속도로 물체가 떨어지게 된다.

 





다음으로는 Enemy 스크립트에  충돌 시 충돌한 물체 두개가 모두 파괴되는 코드를 작성한다.

void OnCollisionEnter(Collision other)
    {
        Destroy(other.gameObject);
        Destroy(gameObject);
    }






위 코드를 추가하여 다음과 같은 코드가 완성된다.
 

 



 
실행하면 다음과 같이 충돌 했을 시에 물체가 사라진다.
 

 
 




 2. 적 자동생성

다음으로는 자동으로 적을 생성하도록 만들어 볼 것이다.
 
 
먼저 총알과 동일하게 복제해서 사용할 것이고
적을 처음부터 화면에 띄우지 않기 위해서 Prefabs파일에 넣어두고
Hierarchy 창에서는 삭제하도록 한다.

 
 
위처럼 복제해서 사용할 때, 무한으로 복제가 되는 경우가 있다. 이런 경우를 막기 위해서 빈 오브젝트를 생성하여 관리하도록 한다.

오브젝트의 이름은 EnemyManager로 설정한다.
이 오브젝트는 Enemy를 관리하는 오브젝트로 사용한다.

이 위치를 y축방향 +6정도로 설정하여 화면에는 보이지 않는 곳에서 적이 생성될 수 있도록 설정한다.

 
스크립트도 생성한 뒤 적용해준다.

 


 
다음과 같이 EnemyManager 스크립트에 작성한다.

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

public class EnemyManager : MonoBehaviour
{
    float currentTime;

    public float createTime = 1;

    public GameObject enemyFactory;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        currentTime += Time.deltaTime;

        if (currentTime > createTime)
        {
            GameObject enemy = Instantiate(enemyFactory);

            enemy.transform.position = transform.position;

            currentTime = 0;
        }
    }
}

 
 


 
이 적들을 5개정도 복제하여 다른위치에서 떨어지도록 만들어보자.

Crtl + D 를 눌러 복제한 뒤 각 EnemyManager의 위치를 마음대로 조정해준다.
 


 
 
실행하면 다음과 같은 결과가 나온다.

 
실행한결과를 보면 모두 같은 코드를 그냥 적용한 것이라 똑같이 물체가 떨어지게 된다.
 
 





 
그래서 랜덤하게 적이 나올 수 있도록 스크립트를 수정해야 한다.

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

public class EnemyManager : MonoBehaviour
{
    float currentTime;

    public float createTime = 1;

    public GameObject enemyFactory;

    float minTime = 1;
    float maxTime = 5;

    // Start is called before the first frame update
    void Start()
    {
        createTime = Random.Range(minTime, maxTime);
    }

    // Update is called once per frame
    void Update()
    {
        currentTime += Time.deltaTime;

        if (currentTime > createTime)
        {
            GameObject enemy = Instantiate(enemyFactory);

            enemy.transform.position = transform.position;

            currentTime = 0;

            createTime = Random.Range(minTime, maxTime);
        }
    }
}

 
 

 
minTim 으로 최소시간과 maxTime으로 최대시간을 설정한 뒤 Start함수와 Update함수에 minTime부터 maxTime까지의 범위로 랜덤값을 생성하고 이를 createTime 변수에 넣는다.

이렇게 하면 5개의 오브젝트가 모두 랜덤한 값을 받아 서로 다른시간 간격을 두고 적을 생성하게 된다.

 
 




다음으로는 적이 플레이어를 향해 날아오도록 만들어 보도록한다.
 
 
 
Enemy 스크립트를 다음과 같이 수정한다.

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

public class Enemy : MonoBehaviour
{
    public float speed = 5;

    Vector3 dir;

    // Start is called before the first frame update
    void Start()
    {
        int randValue = Random.Range(0, 10); //0부터 9까지의 값만 나온다

        if(randValue < 3)
        {
            GameObject target = GameObject.Find("Player");

            dir = target.transform.position - transform.position; //적과 플레이어 거리 벡터 계산
            dir.Normalize(); //단위벡터로 바꿈
        }
        else
        {
            dir = Vector3.down;
        }
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += dir * speed * Time.deltaTime;
    }

    void OnCollisionEnter(Collision other)
    {
        Destroy(other.gameObject);
        Destroy(gameObject);
    }
}

 
 
 
실행하면 다음과 같이 적이 -y축 방향으로만 나오는 것이 아니라 Player방향으로도 생성되어 나온다.

 



 

3. 충돌처리 & 범위 제한 

 
이제 범위 밖으로 나간 오브젝트에 대해 충돌 처리를 해보자
 
 
큐브를 하나 더 생성하여 DestroyZone_U라고 이름을 설정한 뒤 Position과 Scale을 변경한다. 

그리고 Is Trigger 메뉴를 활성화 시킨다.
(ontriggerenter 메서드를 사용하기 위해서 반드시 활성화 되어야 한다.)

 




그리고 앞선 Enemy와 동일하게 Rigidbody를 적용시킨다.
DestoryZone의 경우 떨어지면 안되는 오브젝트이기 때문에
Is Kinematic 메뉴도 활성화 시켜준다.

 
 
 

그리고 DestroyZone 오브젝트에 적용할 스크립트를 생성하고 적용시킨다

 
 
 
 

 
위쪽뿐만 아니라 아래, 좌, 우도 생성하여준다

 
 



DestroyZone 스크립트에 다음과 같은 코드를 작성한다.

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

public class DestroyZone : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnTriggerEnter(Collider other)
    {
        Destroy(other.gameObject); //충돌한 모든 오브젝트를 삭제함
    }
}

 
 
 
하지만 위의 코드에서는 문제가 있다.

현재 DestroyZone 네개는 꼭짓점을 공유하고 있기 때문에 충돌로 인식되어 실행 시 DestroyZone이 삭제되게 된다.

이 부분을 막기 위해서는 예외적으로 충돌로 인식하지 않도록 설정해야 한다.
 
 
 
DestroyZone 오브젝트에 Add Layer를 해준다

 

 
 


 
다음으로 [Edit] - [Project Settings] - [Physics] 에서 DestroyZone의 체크박스를 해제한다.

 




 
마찬가지로 Bullet과 Bullet, Player와 Player, Enemy와 Enemy도 충돌하였을 때 없어지지 않도록 해준다.
 

 

 






 
위와 같이 체크하여 player와 destroyZone이 충돌하였을 때에도 지워지지 않도록 설정한다.
 
실행하면 다음과 같이 DestroyZone에 맞은 오브젝트들은 지워지게 된다.

 




 이제는 적도 생긴 슈팅게임을 만들 수 있다^_^
그리고 destroyzone으로 범위까지 한정되게 해놓으니 범위밖으로 나가려는 적이나 총알이 사라져서 메모리도 아낄수 있어서 좋다.
 근데 스크립트도 많고 오브젝트도 늘어나니 헷갈림.,,

반응형