/ UNITY

미니게임 제작 05

앞으로는 간단한 게임들을 만들어보며 추가적인 기능에 대해 공부를 해보려한다. 간단한 것부터 만들기 시작하여 만든 결과물을 레퍼런스 하여 덩치를 조금씩 키워나가는 과정을 밟아보자. 지식이 많지 않아 부족할 수 있지만, 하는데까지 해보겠다.

EnemySpawner를 만든 목적은 랜덤한 위치에 적이 나타나게 하기 위함이다. 그렇다면 이제 Enemy 오브젝트를 만들어 플레이어를 향해 이동하게끔 만들어보겠다. 그리고 프리팹화 시켜 랜덤하게 생성하게 할 것이다.

game_35

Enemy 오브젝트의 inspactor창은 다음과 같다. 몬스터가 플레이어에게 쉽사리 밀려나면 안되므로 무게를 300으로 설정했다.

game_36

Enemy 오브젝트의 스프라이트는 다음과 같다. 이 이미지는 오픈소스였던 것으로 기억한다.

이제 오브젝트를 만들었으니, 플레이어에게 가까이 다가가도록 스크립트를 짜보겠다.

game_37

Enemy 스크립트를 생성했다.

로직을 생각해보자.

  1. 플레이어 위치를 찾는다.

  2. 자신으로부터 플레이어로의 벡터를 구한다.

  3. 일정한 속력으로 플레이어에게 이동한다.

여기에 추가하여, 플레이어로의 방향에 따라 스프라이트를 좌우반전 시켜주면 될 것 같다. idle 애니메이션 정도도 추가하면 조금 더 느낌이 날 듯 하다.

플레이어 위치는 TransForm을 통해 받아올 수 있을 것이다.

벡터를 구하는 부분은 토막 정보 글에 있던, 벡터의 차를 이용하여 Enemy 오브젝트로부터 플레이어 위치로의 벡터를 구하면 될 것이다.

속력은 public으로 하여 Enemy가 여러 종류가 있을 경우 각 Enemy에 따라 속도를 다르게 해보자.

벡터의 차, 플레이어의 위치 - Enemy의 위치 가 Enemy로부터 플레이어까지 거리와 방향 벡터가 된다.

Enemy.cs

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

public class Enemy : MonoBehaviour
{

    // 플레이어 위치
    public Transform playerTransform;
    // Enemy 위치
    Transform enemyTransform;
    Rigidbody2D enemyRigidbody;
    public int speed;
    void Start()
    {
        enemyTransform = GetComponent<Transform>();
        enemyRigidbody = GetComponent<Rigidbody2D>();
    }


    void Update()
    {
        MoveSet();
    }

    Vector2 vec;

    void FixedUpdate()
    {
        Move();
    }
    void MoveSet()
    {
        // 플레이어로의 방향 벡터 구하기
        vec = playerTransform.position - enemyTransform.position;

        // 벡터를 단위벡터화 시킨다.
        vec.Normalize();
    }

    void Move()
    {
        enemyRigidbody.velocity = vec * speed;
    }
}
  1. line 9 ~ 13 : 변수 생성 부분
    • 9 : 플레이어 TransForm를 저장할 변수
    • 11 : Enemy TransForm을 저장할 변수
    • 12 : Enemy RigidBody를 저장
    • 13 : speed 설정
    • 14 : Vector 값 저장할 변수
  2. line 15 ~ 19 : 초기화 부분
    • enemyTransform과 enemyRigidbody를 GetComponent를 통해 초기화시켜준다.
  3. line 30 ~ 37 : 플레이어로의 방향벡터를 구해서 단위벡터화시키는 메서드

  4. line 39~42 : 위에서 구한 벡터에 Speed를 곱해 이동시키는 메서드

이제 Enemy 오브젝트에 Player TransForm을 할당해주면 된다. 하지만 여기서 문제가 생겼다. Enemy는 Prefab으로 저장했고, 에셋화 되지 않은 Player 게임 오브젝트는 할당해줄 수 없었다. 일단 테스트는 해봐야 했기 때문에 게임을 실행시킨 후 생성된 clone 오브젝트에 Player 오브젝트를 넣어봤다.

game_38

일단 플레이어를 추적하는 것은 잘 되는 모양이다. 주변에 있는 다른 오브젝트가 움직이지 않는 것이 보이듯이, 해당 오브젝트들이 생성되자마자 플레이어 오브젝트의 위치를 찾을 수 있게 해야할 것 같다.

처음에는 Find를 통해 부여해줄까 생각했지만, 자원소모가 만만치 않을 것 같았다. 그렇다면 EnemySpawner에서 부여를 해서 생성할 수는 없을까? EnemySpawner는 Player의 TransForm 컴포넌트를 이미 가지고 있으니 말이다.

찾은 방법은 다음과 같다.

Enemy.cs

// 초기화 메서드
public void init(Transform playerTransform)
{
   this.playerTransform = playerTransform;
}

Enemy 스크립트에는 다음과 같이 초기화 메서드를 생성한다.

EnemySpawner.cs

void Spawn()
{
    Vector2 spawnPos = GetRandomPoint(playerTransform.position, maxDist);
    GameObject selectedEnemy = enemys[Random.Range(0, enemys.Length)];
    GameObject enemy = Instantiate(selectedEnemy, spawnPos, Quaternion.identity);
    Enemy es = enemy.GetComponent<Enemy>();
    es.init(playerTransform);
}

EnemySpawner에는 다음과 같이 Enemy 스크립트를 읽어와서, EnemySpawner가 가지고있는 playerTransform를 init 메서드를 통해 넘겨주도록 한다.

game_39

생성되자마자 플레이어를 잘 추적해서 따라오는 모습이다. 이제 플레이어의 위치에 따라서 Enemy가 바라보는 방향을 바꿔보자.

// 플레이어 위치
public Transform playerTransform;
// Enemy 위치
Transform enemyTransform;
Rigidbody2D enemyRigidbody;
SpriteRenderer rend;
public float speed = 3f;
Vector2 vec;
bool rotation;

선언부는 2개의 변수가 추가되었다. 스프라이트를 좌우반전 시킬 SpriteRenderer 변수, 그리고 플레이어의 위치에 따라 바뀔 bool 변수 rotation이다.

void MoveSet()
{
    // 플레이어로의 방향 벡터 구하기
    vec = playerTransform.position - enemyTransform.position;
    if (vec.x > 0)
    {
        rotation = true;
    }
    else
    {
        rotation = false;
    }
    // 벡터를 단위벡터화 시킨다.
    vec.Normalize();
}

MoveSet 메서드에서 변경된 사항이다. vec의 x가 바라보는 방향에 따라서 rotation의 값을 조정한다.

void Move()
{
    enemyRigidbody.velocity = vec * speed;
    if (!rotation)
    {
        rend.flipX = true;
    }
    else
    {
        rend.flipX = false;
    }
}

Move 메서드에서 변경된 부분이다. rotation bool 변수를 읽어와 그 상태에 따라 flipX를 활성화/비활성화 시킨다.

Enemy.cs

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

public class Enemy : MonoBehaviour
{



    // 플레이어 위치
    public Transform playerTransform;
    // Enemy 위치
    Transform enemyTransform;
    Rigidbody2D enemyRigidbody;
    SpriteRenderer rend;
    public float speed = 3f;
    Vector2 vec;
    bool rotation;
    // 초기화 메서드
    public void init(Transform playerTransform)
    {
        this.playerTransform = playerTransform;
    }

    void Start()
    {
        enemyTransform = GetComponent<Transform>();
        enemyRigidbody = GetComponent<Rigidbody2D>();
        rend = GetComponent<SpriteRenderer>();
    }

    void Update()
    {
        MoveSet();
    }

    void FixedUpdate()
    {
        Move();
    }
    void MoveSet()
    {
        // 플레이어로의 방향 벡터 구하기
        vec = playerTransform.position - enemyTransform.position;
        if (vec.x > 0)
        {
            rotation = true;
        }
        else
        {
            rotation = false;
        }
        // 벡터를 단위벡터화 시킨다.
        vec.Normalize();
    }

    void Move()
    {
        enemyRigidbody.velocity = vec * speed;
        if (!rotation)
        {
            rend.flipX = true;
        }
        else
        {
            rend.flipX = false;
        }
    }
}

변경된 전체 소스코드이다.

game_40

플레이어의 방향으로 Enemy이 바라보는 방향이 바뀌는 것을 확인할 수 있다.

그런데 또 문제가 생겼다. 몬스터끼리 오브젝트가 겹쳐지는 현상이다.

다음에는 위의 현상을 해결하고, Enemy에 간단한 애니메이션을 추가해보자.