ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 플레이어를 추적하는 몬스터 만들기
    쾌락없는 책임 (공부)/Unity 2020. 11. 27. 22:08
    반응형

    <이전에 만들었던건 왜 문제인가?>

     이전에 만든 추적 시스템은 Monster 오브젝트에 콜라이더를 2개 넣었고 한 콜라이더는 추적 범위를 나타내는 trigger였습니다. 여기서 바로 문제가 발생하는데 추적을 위해 만든 콜라이더에도 공격이 적용되어서 몬스터랑 멀리 떨어져 있는데도 데미지가 들어가는 오류가 있었습니다. 


    <이전에 만든 미친 코드>

    // 플레이어를 쫒아다니는 몬스터 구현 
    // 몬스터용 콜라이더랑 감지용 원형 콜라이더(이건트리거) 
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class AttackingMonster : MonoBehaviour {
        Rigidbody2D rigid;
        SpriteRenderer spriteRenderer;
        public int moveDir;    // Moving direction, Random
        public Transform target; //target = player
    
        void Awake() {
            rigid = GetComponent<Rigidbody2D>();
            spriteRenderer = GetComponent<SpriteRenderer>();
            monsterAI();
        }
    
        void Update() {
            if (rigid.velocity.x > 0.1f) {
                spriteRenderer.flipX = true;
            } else {
                spriteRenderer.flipX = false;
            }
        }
    
        void FixedUpdate() {
            rigid.velocity = new Vector2(moveDir, rigid.velocity.y);   // no jump monster
        }
    
        void monsterAI() {
            moveDir = Random.Range(-1, 2);   // -1<= ranNum <2
            Invoke("monsterAI", 3);
        }
    
        private void OnTriggerEnter2D(Collider2D collision) {
            // find player
            if (collision.gameObject.tag == "Player") {
                CancelInvoke("monsterAI");   // 이 부분에서 함수를 바로 취소하지 못해 왔다갔다 하면 딜레이가 조금 있다.
                if(target.position.x > transform.position.x) {
                    moveDir = 3;     // speed up
                } else if (target.position.x < transform.position.x) {
                    moveDir = -3;
                }
            }
        }
        private void OnTriggerExit2D(Collider2D collision) {
            if (collision.gameObject.tag == "Player")
                monsterAI();    // return to normal
        }
    
    }
    

    <어디를 개선해야 하는가>

     - 이전에 gameobject로 타겟을 받아오면 캐릭터가 달리질 시 기능이 작동하지 않을 수 있다.

        > 그래서 player 태그인 물체를 추적하게끔 만들어야 합니다.

     - 추적범위를 다른 오브젝트로 만들어야 합니다.

       > 정확히는 trigger인 monster레이어가 아니어야 플레이어의 공격을 받지 않습니다.

     

     

     

    <해결방안>

    1. 몬스터에 자식 오브젝트로 빈 오브젝트를 만든 뒤 여기에 trigger인 콜라이더를 하나 만듭니다.

      - 이 콜라이더가 플레이어 추적 범위가 됩니다

    하이어라키에서 이런 모습

    2. OntriggerEnter2D를 이용해서 플레이어가 들어오는걸 감지하고 플레이어 포지션을 받아온다

        받아온 플레이어의 포지션이 몬스터 기준으로 오른쪽이면 몬스터의 속도를 3으로(오른쪽으로 움직이게) 왼쪽이면 -3으로 속도를 설정

     

    위 2가지를 통해 플레이어를 추적하는 코드를 작성했습니다.

     

    <핵심>

    1. 몬스터의 움직임은 -1, 0, 1 세가지 값중 한개를 랜덤으로 가지고 있으며 이와 관련한 스크립트는 상위 오브젝트에 있다.

       - 따라서 범위로 지정한 GameObject, 즉 하위 오브젝트에서는 상위 오브젝트의 변수에 접근해야 한다.

          - 이때 사용한 기능이 유니티의 transform.parent.GetComponent<>() 이다.

     

    2. 몬스터의 스크립트는 코루틴으로 작성했다.

     

    <코드>

    -몬스터의 스크립트

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class MonsterMove : MonoBehaviour {
        Rigidbody2D rigid;
        SpriteRenderer spriteRenderer;
        public int moveDir;    // Moving direction, Random
    
        void Awake() {
            rigid = GetComponent<Rigidbody2D>();
            spriteRenderer = GetComponent<SpriteRenderer>();
        }
        void Start(){
            StartCoroutine("monsterAI");
        }
        void Update() {
            if (rigid.velocity.x > 0.1f) {
                spriteRenderer.flipX = true;
            } else {
                spriteRenderer.flipX = false;
            }
        }
    
        void FixedUpdate() {
            rigid.velocity = new Vector2(moveDir, rigid.velocity.y);   // no jump monster
        }
    
        IEnumerator monsterAI() {
            moveDir = Random.Range(-1, 2);   // -1<= ranNum <2
            yield return new WaitForSeconds(5f);
            StartCoroutine("monsterAI");
        }
    
        public void startMove(){
            StartCoroutine("monsterAI");
        }
    
        public void stopMove(){
            StopCoroutine("monsterAI");
        }
    
    }
    

    - 하위 오브젝트 ( 몬스터 아래 빈 오브젝트의 콜라이더용 스크립트)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerChase : MonoBehaviour
    {
        private void OnTriggerEnter2D(Collider2D collision) {
            // find player
            if (collision.gameObject.tag == "Player") {
                transform.parent.GetComponent<MonsterMove>().stopMove();
                Vector3 playerPos = collision.transform.position;
                if(playerPos.x > transform.position.x) {
                    transform.parent.GetComponent<MonsterMove>().moveDir = 3;     // speed up
                } else if (playerPos.x < transform.position.x) {
                    transform.parent.GetComponent<MonsterMove>().moveDir = -3;
                }
            }
        }
        private void OnTriggerExit2D(Collider2D collision) {
            if (collision.gameObject.tag == "Player")
                transform.parent.GetComponent<MonsterMove>().startMove();
        }
    }
    

    <무엇이 부족한가>

    1. 다른 스크립트의 코루틴 함수에 접근하는 법은 없는가

     - 현재 코루틴을 다른 스크립트에서 간접적으로 접근하고 있는데 직접적으로 실행할 수는 없는지 궁금하다

     

    2. parent로 받아온 스크립트를 변수화 할 수는 없는가

     - 하위 오브젝트의 스크립트의 코드가 너무 더럽다. 자료구조적으로 변수 하나를 아끼게 된다고 하는데 가독성이 너무 떨어져 오히려 유지보수에 좋지 못할 듯 하다.

     

     

     

    2020.11.27 첫 작성

    반응형

    댓글

Designed by Tistory.