아카이브

[개발일지] Undead Survivor 3일차 본문

2D 콘텐츠 제작

[개발일지] Undead Survivor 3일차

timbercat 2023. 9. 15. 18:21

몬스터 만들기

Enemy 설정

Enemy.cs

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

public class Enemy : MonoBehaviour
{
    public float speed;
    public Rigidbody2D target;

    bool isLive = true;

    Rigidbody2D rigid;
    SpriteRenderer spriter;

    // Start is called before the first frame update
    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriter = GetComponent<SpriteRenderer>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if (!isLive)
            return;

        Vector2 dirVec = target.position - rigid.position;
        Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
        rigid.MovePosition(rigid.position + nextVec);
        rigid.velocity = Vector2.zero;
    }

    void LateUpdate()
    {
        //목표의 x축 값과 자신의 x축값을 비교하여 작으면 true가 되도록 설정
        spriter.flipX = target.position.x < rigid.position.x;
    }
}

Reposition.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem.Switch;

public class Reposition : MonoBehaviour
{
    Collider2D coll;

    void Awake()
    {
        coll = GetComponent<Collider2D>();
    }

    void OnTriggerExit2D(Collider2D collision)
    {
        if (!collision.CompareTag("Area")) //Area태그가 아니면 실행하지 않는다
            return;

        //거리를 구하기 위해 플레이어 위치와 타일맵 위치를 미리 저장
        Vector3 playerPos = GameManager.instance.player.transform.position;
        Vector3 myPos = transform.position;
        //X축과 Y축 각각의 거리, 플레이어 위치 - 타일맵 위치
        float diffX = Mathf.Abs(playerPos.x - myPos.x); //Mathf.Abs(): 절대값 함수
        float diffY = Mathf.Abs(playerPos.y - myPos.y);

        Vector3 playerDir = GameManager.instance.player.inputVec;
        //3항 연산자 (조건) ? (true일 때 값) : (false일 때 값)
        float dirX = playerDir.x < 0 ? -1 : 1;
        float dirY = playerDir.y < 0 ? -1 : 1;
        
        //switch ~ case: 값의 상태에 따라 로직을 나눠주는 키워드
        switch (transform.tag)
        {
            case "Ground":
                if(diffX > diffY) //두 오브젝트 거리 사이에서, x축이 y축보다 크면 수평이동
                {
                    transform.Translate(Vector3.right * dirX * 40);
                } 
                else if (diffX < diffY) //x축이 y축보다 작으면 수직이동
                {
                    transform.Translate(Vector3.up * dirY * 40);
                }
                break;
            case "Enemy":
                if (coll.enabled)
                { 
                    //플레이어의 이동방향에 따라 맞은 편에서 등장하도록 이동
                    transform.Translate(playerDir * 20 + new Vector3(Random.Range(-3f, 3f), 0f));
                }
                break;
        }
    } 
}

오브젝트 풀링

프리팹 폴더 생성 후 Enemy A 와 Enemy B를 넣어준다.

오브젝트 풀 만들기

PoolManager 오브젝트와 스크립트를 만든다. 

using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolManager : MonoBehaviour
{
    //프리팹들을 보간할 변수
    public GameObject[] prefabs;

    //풀 담당을 하는 리스트
    List<GameObject>[] pools;

    void Awake()
    {
        pools = new List<GameObject>[prefabs.Length];

        for(int index = 0; index < pools.Length; index++)
        {
            pools[index] = new List<GameObject>();
        }
    }
    public GameObject Get(int index)
    {
        GameObject select = null;

        // 선택한 풀의 비활성화 된 게임 오브젝트 접근
        foreach(GameObject item in pools[index])
        {
            if (!item.activeSelf)
            {
                // 발견하면 select 변수에 할당
                select = item;
                select.SetActive(true);
                break;
            }
        }

        // 못 찾았으면
        if (!select)
        {
            // 새롭게 생성하고 select 변수에 할당
            select = Instantiate(prefabs[index], transform);  //Instantiate: 원본 오브젝트 복제하여 장면에 생성
            pools[index].Add(select);
        }

        return select;
    }
}

풀링 사용해보기 

플레이어의 자식으로 Spowner 오브젝트, 스크립트를 만든다

GameManager에 PoolManager 추가

GameManager.cs

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

public class GameManager : MonoBehaviour
{
    public static GameManager instance; //static: 정적으로 사용하겠다는 키워드. 바로 메모리에 얹어버림
    public PoolManager pool;
    public Player player;

    void Awake()
    {
        //Awake 생명주기에서 인스턴스 변수를 자기자신 this로 초기화
        instance = this;
    }
}

Spawner.cs

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

public class Spawner : MonoBehaviour
{
    void Update()
    {
        if (Input.GetButtonDown("Jump"))
        {
            GameManager.instance.pool.Get(0);
        }
    }
}

Enemy 스크립트에서 스스로 타겟을 초기화하는 코드 추가

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

public class Enemy : MonoBehaviour
{
    public float speed;
    public Rigidbody2D target;

    bool isLive = true;

    Rigidbody2D rigid;
    SpriteRenderer spriter;

    // Start is called before the first frame update
    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        spriter = GetComponent<SpriteRenderer>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if (!isLive)
            return;

        Vector2 dirVec = target.position - rigid.position;
        Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
        rigid.MovePosition(rigid.position + nextVec);
        rigid.velocity = Vector2.zero;
    }

    void LateUpdate()
    {
        //목표의 x축 값과 자신의 x축값을 비교하여 작으면 true가 되도록 설정
        spriter.flipX = target.position.x < rigid.position.x;
    }

    void OnEnable()
    {
        target = GameManager.instance.player.GetComponent<Rigidbody2D>();
    }
}

스페이스바를 누르면 몬스터 생성

주변에 생성하기

스포너의 자식으로 Point 오브젝트를 만든다

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

public class Spawner : MonoBehaviour
{
    public Transform[] spawnPoint;

    float timer;

    void Awake()
    {
        spawnPoint = GetComponentsInChildren<Transform>();
    }
    void Update()
    {
        timer += Time.deltaTime;

        if(timer > 0.2f)
        {
            Spawn();
            timer = 0;
        }
    }

    void Spawn()
    {
        GameObject enemy = GameManager.instance.pool.Get(Random.Range(0, 2));
        enemy.transform.position = spawnPoint[Random.Range(1, spawnPoint.Length)].position;
    }
}