미니 RPG 만들기(2)_Enemy/마우스 커서

개발조하·2024년 1월 3일
0

Unity

목록 보기
24/30
post-thumbnail

1. Enemy (Knight)

1.1 Enemy 설정

  1. Knight 에셋 다운
  2. Project 창 정리
  3. Knight 프리팹화
  4. Knight용 Animator 생성
  5. Animator에 Animation 설정

1.2 Stat 설정

  • Contents 폴더 생성 후 Stat.cs 생성

❌ Data.contents.cs에서 이미 Stat 클래스명을 사용하고 있기 때문에 중복된다는 오류 메시지가 뜬다.
-> Data.contents.cs의 Stat 클래스를 Data라는 별도의 네임스페이스 안에 넣어 중복을 피한다.
-> 기존에 Stat클래스를 참조하던 다른 코드들도 수정

public class Stat : MonoBehaviour
{
    [SerializeField] protected int _level;
    [SerializeField] protected int _hp;
    [SerializeField] protected int _maxHp;
    [SerializeField] protected int _attack;
    [SerializeField] protected int _defense;
    [SerializeField] protected float _moveSpeed;

    public int Level { get { return _level; } set {  _level = value; } }
    public int Hp{ get { return _hp; } set { _hp = value; } }
    public int MaxHp { get { return _maxHp; } set { _maxHp = value; } }
    public int Attack { get { return _attack; } set { _attack = value; } }
    public int Defense { get { return _defense; } set { _defense = value; } }
    public float MoveSpeed { get { return _moveSpeed; } set { _moveSpeed = value; } }

    private void Start()
    {
        _level = 1;
        _hp = 100;
        _maxHp = 100;
        _attack = 10;
        _defense = 5;
        _moveSpeed = 5.0f;
    }
}

ㄴ 프로퍼티를 사용할건데 굳이 필드 변수를 만들어준 이유?
-> 인스펙터창에서 변수와 값을 확인하려고.

  • Player용 Stat을 별도로 만들어준다.
    공용으로 사용하는 Stat.cs를 상속 받는 PlayerStat.cs 생성
public class PlayerStat : Stat
{
    protected int _exp;
    protected int _gold;
    
    public int Exp { get { return _exp; } set { _exp = value; } }
    public int Gold { get { return _gold; } set { _gold = value; } }

    private void Start()
    {
        _level = 1;
        _hp = 100;
        _maxHp = 100;
        _attack = 10;
        _defense = 5;
        _moveSpeed = 5.0f;
        _exp = 0;
        _gold = 0;
    }
}
  • 컴포넌트 연결
    PlayerStat.cs -> UnityChan
    Stat.cs -> Knight

❌ 기존에 PlayerController.cs에서 사용하던 _speed 변수는 이제 필요없다. Stat.cs에서 _moveSpeed로 스피드값을 줄 것이기 때문.

2. 마우스 커서 설정

2.1 일반 시, 공격 시 커서 상태 변화

  1. 커서 에셋 다운 및 설정
    커서 에셋을 받은 후, Texture Type을 Cursor로 지정한다.

  2. PlayerController.cs에 UpdateMouseCursor() 추가
    커서가 땅을 가리킬 때와 적을 가리킬 때의 이미지를 변경한다.

💡SetCursor(Texture2D texture, Vector2 hotspot, CursorMode cursorMode);

  • hotspot : 텍스처 왼쪽 상단의 오프셋

2.2 타게팅 락온 기능

  • 땅을 클릭한 상태로 커서를 움직이면 Player가 커서를 따라서 이동
  • 적을 클릭한 상태로 커서를 움직이면 Player가 마우스 커서가 아닌 적을 향해 이동
    (ex.리니지1, 디아블로 3)
  1. Define.cs MouseEvent 수정
    -> PointerUp과 Click을 마우스를 누르고 있는 시간(_pressedTime)으로 구분

  2. InputManager.cs

  3. PlayerController.cs

    int _mask = (1 << (int)Define.Layer.Ground) | (1 << (int)Define.Layer.Monster);
    GameObject _lockTarget;
    void OnMouseEvent(Define.MouseEvent evt)
    {
        if (_state == PlayerState.Die)
            return;

        RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        bool raycastHit = Physics.Raycast(ray, out hit, 100.0f, _mask);
        //Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);

        switch(evt)
        {
            case Define.MouseEvent.PointerDown:
                {
                    if (raycastHit)
                    {
                        _destinationPos = hit.point;
                        _state = PlayerState.Moving;

                        if (hit.collider.gameObject.layer == (int)Define.Layer.Monster)
                        {
                            _lockTarget = hit.collider.gameObject;
                        }
                        else
                        {
                            _lockTarget = null;
                        }
                    }
                }
                break;
            case Define.MouseEvent.Press:
                {
                    if(_lockTarget != null)
                    {
                        _destinationPos = _lockTarget.transform.position;
                    }
                    else if(raycastHit)
                    {
                        _destinationPos = hit.point;
                    }
                }
                break;
        }
    }

2.3 CursorController.cs 생성

현재 마우스 클릭 상태에 따른 Cursor의 상태 변화에 관한 코드까지 PlayerController.cs에서 관리하고 있다. 이를 CursorController.cs에서 관리하도록 수정하자.

  • PlayerController.cs에 있던 UpdateMouseCursor() -> CursorController.Update()로 이동
public class CursorController : MonoBehaviour
{
    int _mask = (1 << (int)Define.Layer.Ground) | (1 << (int)Define.Layer.Monster);

    Texture2D _attackIcon;
    Texture2D _handIcon;

    enum CursorType
    {
        None,
        Attack,
        Hand,
    }

    CursorType _cursorType = CursorType.None;

    void Start()
    {
        _attackIcon = Managers.Resource.Load<Texture2D>("Textures/Cursor/Attack");
        _handIcon = Managers.Resource.Load<Texture2D>("Textures/Cursor/Hand");
    }

    void Update()
    {
        //마우스를 누르고 있는 상태면 커서 상태 변화 X
        if (Input.GetMouseButton(0))
            return;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 100.0f, _mask))
        {
            if (hit.collider.gameObject.layer == (int)Define.Layer.Monster)
            {
                if (_cursorType != CursorType.Attack)
                {
                    Cursor.SetCursor(_attackIcon, new Vector2(_attackIcon.width / 5, 0), CursorMode.Auto);
                    _cursorType = CursorType.Attack;
                }
            }
            else
            {
                if (_cursorType != CursorType.Hand)
                {
                    Cursor.SetCursor(_handIcon, new Vector2(_handIcon.width / 3, 0), CursorMode.Auto);
                    _cursorType = CursorType.Hand;
                }
            }
        }
    }
}
  • GameScene.cs에 'CursorController.cs' 컴포넌트 부착

📄참고자료
[인프런] c#과 유니티로 만드는 MMORPG 게임 개발 시리즈_3. 유니티 엔진
Unity Documentation_Cursor.SetCursor

profile
Unity 개발자 취준생의 개발로그, Slow and steady wins the race !

0개의 댓글