분류 전체보기에 해당하는 글 16

유니티 이동 컴포넌트 (Mover)

C#/Unity|2019. 9. 14. 18:46

일반적으로 유니티에서 게임오브젝트를 이동시키는 방법은 Rigidbody를 이용한 물리 법칙을 통한 계산이나 Transform에 관련된 함수를 사용하는 것이다. 이는 Platformer 장르나 물리법칙이 적용된 게임에는 적합하나 RTS나 Defense장르에서 사용하기는 부적합하다. 그래서 목표지까지 이동이나 다른 GameObject를 따라가는 로직을 구현하기 위해 컴포넌트를 제작했다.

ToGoal함수를 이용해 목표지(Vector)까지 이동가능하며 ToFollow함수를 이용해 적을 따라가게 할 수 있다.

[DisallowMultipleComponent]
public class Mover : MonoBehaviour {
    public enum MoveType {
        None, Goal, Follow
    }
    public enum EndEvent {
        None, DestoryGameObject, DestroyComponent, DeactiveGameObject
    }

    public float speed;
    public float stopDistance = 0.1f;
    public MoveType moveType;
    public EndEvent endEvent;

    public Vector3 destination;
    public GameObject target;

    private List<Vector3> nextGoals = new List<Vector3>();
    private event Action OnCompleted;
    private event Action OnFailed;


    public bool IsMoving() {
        return moveType != MoveType.None;
    }

    public Mover SetSpeed(float _speed) {
        speed = _speed;
        return this;
    }
    public Mover SetEndEvent(EndEvent _endEvent) {
        endEvent = _endEvent;
        return this;
    }

    public void ToGoal(Vector3 _destination, Action completeAct = null) {
        destination = _destination;
        OnCompleted += completeAct;
        moveType = MoveType.Goal;
    }

    public void ToGoal(List<Vector3> desList, Action completeAct = null) {
        if(desList.Count == 0)
            return;
        ToGoal(desList[0], completeAct);
        desList.RemoveAt(0);
        nextGoals = desList;
    }

    public void ToFollow(GameObject _target) {
        ToFollow(_target, null, null);
    }
    public void ToFollow(GameObject _target, Action completeAct) {
        ToFollow(_target, completeAct, null);
    }
    public void ToFollow(GameObject _target, Action completeAct, Action failAct) {
        OnCompleted += completeAct;
        OnFailed += failAct;
        target = _target;
        moveType = MoveType.Follow;
    }



    public void Stop() {
        ResetState();
    }

    private void Update() {
        if(moveType == MoveType.None)
            return;

        if(moveType == MoveType.Goal) {//목표지점까지 이동
            transform.position = Vector3.MoveTowards(transform.position, destination, speed * Time.deltaTime);

            if(Vector3.Distance(transform.position, destination) < stopDistance) {
                if(nextGoals.Count == 0) {
                    transform.position = destination;
                    OnCompleted?.Invoke();
                    ResetState();
                    ExcuteEndEvent();
                    return;
                } else {
                    destination = nextGoals[0];
                    nextGoals.RemoveAt(0);
                    return;
                }
            }
        } else if(moveType == MoveType.Follow) {//목표 타겟한테 이동
            if(target == null) {
                OnFailed?.Invoke();
                ResetState();
                ExcuteEndEvent();
                return;
            }
            transform.position = Vector3.MoveTowards(transform.position, target.transform.position, speed * Time.deltaTime);
            if(Vector3.Distance(transform.position, target.transform.position) < stopDistance) {
                transform.position = target.transform.position;
                OnCompleted?.Invoke();
                ResetState();
                ExcuteEndEvent();
            }
        }
    }


    private void ResetState() {
        moveType = MoveType.None;
        OnFailed = null;
        OnCompleted = null;
    }

    private void ExcuteEndEvent() {
        if(endEvent == EndEvent.DestroyComponent) {
            Destroy(this);
        } else if(endEvent == EndEvent.DestoryGameObject) {
            Destroy(gameObject);
        } else if(endEvent == EndEvent.DeactiveGameObject) {
            gameObject.SetActive(false);
        }
    }
}

'C# > Unity' 카테고리의 다른 글

유용한 Unity & C# 관련 링크  (0) 2020.01.19
유니티 이동 컴포넌트 (Mover)  (0) 2019.09.14
유니티 클릭 컴포넌트 (Clickable)  (0) 2019.09.14
유니티 Android native 사운드 적용  (0) 2019.09.14

댓글()

유니티 클릭 컴포넌트 (Clickable)

C#/Unity|2019. 9. 14. 18:32

유니티 게임오브젝트의 클릭은 OnMouseUp이나 OnMouseDown같은 콜백함수로 구현되어있다.

하지만 Double Click이나 Long Click같은 로직은 코루틴을 이용해서 구현해야 하는데 

쉽게 사용하기 위해 컴포넌트 방식으로 구현해 보았다. (2D 기반이며 Collider가 있어야한다)

내부로직은 코루틴으로 작동하며 event를 등록하거나 Regist함수를 호출함으로서 사용가능하다.

개선사항은 Clickable 컴포넌트간의 우선순위 설정이 필요할 수도 있겠다. 

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

[DisallowMultipleComponent]
[RequireComponent(typeof(Collider2D))]
public class Clickable : MonoBehaviour {
    public static float DOUBLE_INTERVAL=0.2f;
    public static float LONG_INTERVAL=0.8f;

    public bool isOnce = true;
    public bool isDouble;
    public bool isLong;

    public event Action OnOnceClicked;
    public event Action OnDoubleClicked;
    public event Action OnLongClicked;

    private int downCount;
    private float clickTime;

    private Coroutine doubleCoroutine;
    private Coroutine longCoroutine;


    public Clickable RegistInOnce(Action act) {
        isOnce = true;
        OnOnceClicked += act;
        return this;
    }
    public Clickable RegistInDouble(Action act) {
        isDouble = true;
        OnDoubleClicked += act;
        return this;
    }
    public Clickable RegistInLong(Action act) {
        isLong = true;
        OnLongClicked += act;
        return this;
    }
    public Clickable ClearInOnce(Action act) {
        OnOnceClicked = null;
        return this;
    }
    public Clickable ClearInDouble(Action act) {
        OnDoubleClicked = null;
        return this;
    }
    public Clickable ClearInLong(Action act) {
        OnLongClicked = null;
        return this;
    }

    private void OnMouseDrag() {
        clickTime += Time.deltaTime;
    }
    private void OnMouseUp() {
        clickTime = 0f;
    }

    private void OnMouseDown() {
        clickTime = 0f;
        downCount++;

        if(isOnce && !isDouble && !isLong) {
            OnOnceClicked?.Invoke();
            return;
        }
        if(isDouble && doubleCoroutine == null) {
            doubleCoroutine = StartCoroutine(CoWaitDouble());
        }
        if(isLong && longCoroutine == null) {
            longCoroutine = StartCoroutine(CoWaitLong());
        }
    }

    private IEnumerator CoWaitDouble() {
        float startTime = Time.time;
        int curCount = downCount;
        while(true) {
            if(curCount < downCount) {
                OnDoubleClicked?.Invoke();
                break;
            }

            if(startTime + DOUBLE_INTERVAL < Time.time) {
                if(longCoroutine == null) {
                    OnOnceClicked?.Invoke();
                }
                break;
            }
            yield return null;
        }
        doubleCoroutine = null;
    }
    private IEnumerator CoWaitLong() {
        float startTime = Time.time;
        while(true) {
            if(!Input.GetMouseButton(0)) {
            	if (startTime+DOUBLE_INTERVAL<Time.time) {
                    OnOnceClicked?.Invoke();
                }
                break;
            }

            if(startTime + LONG_INTERVAL < Time.time) {
                OnLongClicked?.Invoke();
                break;
            }

            yield return null;
        }
        longCoroutine = null;
    }
}

'C# > Unity' 카테고리의 다른 글

유용한 Unity & C# 관련 링크  (0) 2020.01.19
유니티 이동 컴포넌트 (Mover)  (0) 2019.09.14
유니티 클릭 컴포넌트 (Clickable)  (0) 2019.09.14
유니티 Android native 사운드 적용  (0) 2019.09.14

댓글()

Effective C#

Common/Books|2019. 9. 14. 16:54

이 책은 C#을 가장 효과적으로 사용 할 수 있게 도와주는 중급서이다.

따라서 독자층을 C#을 이미 안다고 가정하고 썼기 때문에 기본 문법에 대한 것은 작성 되어 있지 않다. 

책의 구성은 각 항목별로 TIP이 나눠져있다. 도움이 되었던 부분만 따로 작성하도록하겠다.


4. string.Format()을 보간문자열로 대체하라.

 string.Format("The value of pi is {0},Math.PI);  (X)

 $"The value of pi is {Math.PI}";  (O)

-가독성이 향상되고 생산성이 올라간다.


8.이벤트 호출 시에는 null 조건 연산자를 사용하라.

 if(handler!=null)

handler.Invoke();  (X)

 handler?.Invoke();  (O)

-멀티 쓰레드 상황에서도 안전하며 작성할 코드의 양도 줄어든다.


29.컬렉션을 반환하기보다 이터레이터를 반환하는 것이 낫다.

 List<char> GetAlphabet() (X)

 IEnumerable<char> GenerateAlphabet()  (O)

-컬렉션보다 이터레이터가 Linq 사용이나 성능 측면에서 낫다. (yield관련 글에서 작성)

'Common > Books' 카테고리의 다른 글

클린 코드  (0) 2019.09.17
Effective C#  (0) 2019.09.14
객체지향의 사실과 오해  (0) 2019.09.13
실용주의 프로그래머  (0) 2019.09.13

댓글()