C#/수업내용

2020.05.26. 수업내용 - 2D animator/ 2D 오브젝트 움직이기

dev_sr 2020. 5. 26. 22:45

 

1. 새로운 애니메이션 만들기

 

window -> Asset에 Animation 폴더를 하나 만들고

캐릭터가 선택된 상태에서
Window->animation -> createNewClip -> 폴더 선택 후 이름 저장

 

 

 

점 3개가 나열된 버튼을 누르면 시간이나 프레임단위로 변경할 수 있다.

 

 

 

모델에서 Animator를 더블클릭하면 StateMachine 이 나오는데

주황색 State(node)가 기본으로 설정된 애니메이션이고

회색인 다른 애니메이션에서 마우스 우클릭으로 Set as Layer Default State 를 누르면 

플레이 시 자동으로 실행되는 애니메이션으로 설정할 수 있다.

 

 

State : 애니메니션의 한 상태인 노드(걷기, idle, run등..)
StateMachine : State들이 연결된 노드들
현재 상태에서 캐릭터가 넘어갈 수 있는 다음 상태에 대한 옵션을 state transitions 이라고 한다.
(statemachine에서 화살표로 나타냄)

 

Mechanim(애니메이션 시스템, 애니메이터) - Animator를 이용하는 시스템
인간형 애니메이션 리타겟팅에 주안점

Legacy(애니메이션) - 애니메이터를 사용하지 않는 애니메이션 방식

https://docs.unity3d.com/kr/530/Manual/MecanimFAQ.html - 애니메이션과 에니메이터의 차이

 

 

2. 연습 예제

 

배경화면을 그대로 Hierarchy에 넣고 Box Collider 2d를 넣어준다

RayCast도 2d에 맞춰 작성해준다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
 
public class Test : MonoBehaviour
{
 
    public Hero hero;
 
    private void Start()
    {
 
 
    }
 
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
 
 
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 
            //콜리더 박스를 2d로 설정하면 raycastHit도 2d로 설정한다.
            RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, 1000);
 
            if (hit)
            {
                var pos = hit.point;
 
                //Debug.Log(pos);
                this.hero.Move(pos);
            }
 
 
 
        }
 
    }
}
 

 

 

 

실행 순서가 헷갈려서 번호 찍어봄

 

*Space.World / Space.Self 차이

space.world 로컬좌표 대신에 월드 좌표를 축으로 사용하겠다

space.self는 자기 자신이 바라보는 지점을 축으로 사용 (default 로 설정되어있음)

 

*coroutine 에서 반복문을 실행할때는 

yield return null;

를 반복문 밖에 두지 말기 (유니티가 멈춘다)

 

*this.StartCoroutine을 하면 Coroutine 값이 반환되는데 그걸 변수에 담을 수 있고

Coroutine 메서드를 통해 변수에 담긴 Coroutine을 관리할 수 있음

this.routine = this.StartCoroutine(this.MoveImpl(pos));

this.StopCoroutine(this.routine);

 

*어느 시점에서 캐릭터의 localScale의 x값에 -1 이나 1값을 주면 수평으로 플립된다.

this.model.transform.localScale = new Vector3(-111);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Hero : MonoBehaviour
{
    public GameObject model;
    private Animator anim;
    private Coroutine routine;
    void Start()
    {
       
        this.anim = this.model.GetComponent<Animator>();
 
    }
 
    public void Idle()
    {
        Debug.Log(6);
        this.anim.Play("idle");
    }
 
    public void Move(Vector2 pos)
    {
        //실행순서
        Debug.Log(1);
        this.anim.Play("run");
 
        Debug.LogFormat("{0} {1}"this.transform.position.x, pos.x);
 
        //캐릭터 뒤집기
        //local scale x에 -1, 1값을 주면 플립된다.
        if(this.transform.position.x > pos.x)
        {
            this.model.transform.localScale = new Vector3(111);
        }
        else
        {
            this.model.transform.localScale = new Vector3(-111);
        }
 
 
        if (this.routine != null)
        {
            //기존 코루틴은 종료
            //안하면 클릭할수록 빨라짐 
            Debug.Log(7);
            this.StopCoroutine(this.routine);
        }
 
        //새로운 코루틴 시작
        Debug.Log(2);
        this.routine = this.StartCoroutine(this.MoveImpl(pos));
    }
   
 
    IEnumerator MoveImpl(Vector3 pos)
    {
        //Vector2 값을 Vector3값으로 바꾸면 
        //z에 0이 들어간다
        Debug.Log(pos);
        Debug.Log(3);
        while (true)
        {
            //Debug.Log(4);
            var distance = Vector2.Distance(this.transform.position, pos);
            
            //같은 벡터값끼리 빼야한다
            //벡터 2끼리, 벡터 3끼리
            Vector2 dir = pos-this.transform.position;
 
            if (distance <= 0.02f)
            {
                Debug.Log(5);
                break;
            }
 
            //space.world 로컬좌표 대신에 월드 좌표를 축으로 사용하겠다
            //space.self는 자기 자신이 바라보는 지점을 축으로 사용 (default)
            this.transform.Translate(dir.normalized * 1f * Time.deltaTime,Space.World);
            //리턴을 while문 밖에서 하면 유니티 멈춤 
            yield return null;
 
        }
 
        this.Idle();
        
    }
}