C#/수업내용

2020.05.27. 수업내용 - 2D Collider, Rigidbody, 이동 및 점프

dev_sr 2020. 5. 28. 00:23

 

**2D로 만들 때 카메라 Projection 꼭 ortho로 해주기

 

Rigidbody
- 보통 중력의 영향을 주기 위해서 사용(Use Gravity 활성화)
- 물리적인 제어를 구현
- Rigidbody를 사용하거나 Tranform을 쓰거나 둘중 하나를 선택해야함
- Rigidbody 2D를 쓰면 Collider도 2D로 맞춰서 써야함

 

리지드바디 - Unity 매뉴얼

Rigidbody 는 GameObject 가 물리 제어로 동작하게 합니다. 리지드바디는 힘과 토크를 받아 오브젝트가 사실적으로 움직이도록 해줍니다. 리지드바디가 포함된 모든 게임 오브젝트는 중력의 영향을 ��

docs.unity3d.com

 

Collider
-물리 충돌 처리를 위한 오브젝트 형태
-보이지 않음
-Mesh : 형태
-한 객체에 Collider를 여러개 적용시킬 수 있음
ex) 캐릭터에 콜라이더를 여러가지 붙여놓고

박스 콜라이더는 인식범위, 캡슐 콜라이더는 공격범위 등으로 설정할 수 있음
-쉬어 변환 : 회전을 하다보면(쉬어 변환이 되면) 제대로 동작하지 않는다

->반드시 제대로 동작하지 않는다는 것을 의미함
-동적 콜라이더 : rigidbody가 있는거
-정적 콜라이더 : 벽, 바닥 등 고정물체에 있는 것
-트리거 : 충돌이 일어나는 시점을 감지, OnCollisionEnter  함수를 사용하여 액션

OnCollisionEnter  (lifeCycle의 Physics의 OnCollisionXXX 중 하나)
XXX에는 Enter, Exit, Stay 가 있음

 

Enter :  충돌지점에 들어갈 때 한번 호출

Stay :  충돌지점에 머무를 때 매 프레임마다 호출

Exit :  충돌지점에서 벗어날 때 한번 호출


-Collision : 충돌을 나타내는 클래스 -> OnColliderXXX를 통해 전달되는 값의 데이터 형식

 

-Collider의 isTrigger가 활성화되면 물리적인 충돌을 무시

-OnTriggerXXX (Enter, Exit, Stay) 메서드 이용시 Collision 타입의 other값을 전달하게 됨

 

콜라이더 - Unity 매뉴얼

콜라이더(Collider) 컴포넌트는 물리 충돌 처리를 위한 오브젝트의 형태를 정의합니다. 콜라이더는 보이지 않는 요소이므로 오브젝트의 메시와 정확히 동일한 모양일 필요는 없으며, 실제로는 게�

docs.unity3d.com

 

Unity - 스크립팅 API: Collider.OnCollisionEnter(Collision)

OnTriggerEnter와는 대조적으로 OnCollisionEnter는 콜라이더가 아니라 Collision이 전달됩니다. Collision에는 접촉점, 충돌한 속도 등의 정보가 포함되어 있습니다. 이 함수의 collisionInfo를 사용하지 않으면 c

docs.unity3d.com

 

 

 

올라갈 때 속도변화 

S=(v+at)t

 

초속이 1이라고 치면


현재 속도 = (초속 + 가속도 * 시간) * 시간
현재 속도 = (1+9.8 *Time.deltaTime) * Time.deltaTime;
this.transform.translate(현재 속도);

 


내려갈 때 속도 변화
S=(v-at)t

현재 속도 = (초속 - 가속도 * 시간) * 시간
현재 속도 = (1-9.8 *Time.deltaTime) * Time.deltaTime;
this.transform.translate(현재 속도);

 

 

1. Test1 

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
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
 
public class Test1 : MonoBehaviour
{
    public Button btn;
    public GameObject heroPrefabs;
    public GameObject flagGo;
 
    private Hero hero;
    private bool isHeroDown;
    private bool isHeroExis;
    void Start()
    {
 
        this.btn.onClick.AddListener(() =>
        {
            
            if(!this.isHeroExis)
            {
                GameObject heroGo = Instantiate<GameObject>(this.heroPrefabs);
                heroGo.transform.position = new Vector3(050);
                this.hero = heroGo.GetComponent<Hero>();
 
                this.hero.Init(heroGo);
                this.isHeroExis = true;
            }
 
            this.hero.OnDownComplete = () =>
            {
                this.isHeroDown = true;   
            };
 
        });
 
    }
 
    void Update()
    {
       if(this.isHeroDown)
        {
            //캐릭터 생성 후 버튼을 또 눌렀을 때 
            //버튼 x 위치로 캐릭터가 달려가는 걸 방지
            if (!EventSystem.current.IsPointerOverGameObject())
            {
                if (Input.GetMouseButtonDown(0))
                {
                    //2D면 카메라 Projection을 꼭 ortho로 맞추기
                    //안하면 값이 말도 안되게 작게나옴
 
                    //레이캐스트 쓰면 뒤에 게임오브젝트 빈거라도 만들고 콜라이더 2D를 넣어줌
                    //콜라이더 스케일을 1920 * 1080으로 맞춰주기
                    //SpriteRenderer 컴포넌트 붙여주고 Order in layer 게임 오브젝트보다 작게 주기
 
 
                    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
 
                    RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
                    
 
                    if (hit)
                    {
                        this.flagGo.transform.position = hit.point;
                        this.hero.Move(hit.point.x);
                    }
                }
 
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    Debug.Log("스페이스 버튼 누름");
                    this.hero.Jump();
                }
            }
        }
 
 
       
    }
}
 

 

2. Hero 

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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
 
public class Hero : MonoBehaviour
{
    private Animator anim;
    private bool isGround;
    private float g = 9.8f;
    private Coroutine moveRoutine;
    private float maxHeight = 1.5f;
    private Coroutine jumpRoutine;
    private bool isJump;
    private bool isMove;
    private float delayTime;
    private bool isJumpDown;
    private float colliderHalfSize;
 
 
    public UnityAction OnDownComplete;
    public UnityAction OnMoveComplete;
    public UnityAction OnJumpComplete;
    void Start()
    {
        this.OnMoveComplete = () =>
        {
            this.Idle();
        };
        this.OnJumpComplete = () =>
        {
            if(this.isMove)
            {
                //실행하려면 스테이트머신에서 Run의 transitions 을 다 끊거나
                //Run을 지우고 새로 노드를 만들어서
                //Run애니메이션을 할당하고 이름을 Run으로 지어준다.
                //안그럼 Idle만 함
 
                //이름을 제대로 안적었을 땐 invalid layer index '-1' 이라는 문구가 나오면서 안됨
                this.anim.Play("Run");
            }
            else
            {
                this.Idle();
            }
        };
    }
 
    public void Init(GameObject model)
    {
        this.anim = model.GetComponent<Animator>();
        var ground = GameObject.Find("ground");
        this.colliderHalfSize = ground.GetComponent<BoxCollider>().size.x / 2;
 
        this.StartCoroutine(this.DownIE());
 
    }
 
    public void Idle()
    {
        this.anim.Play("Idle");
    }
 
    public void Move(float tposX)
    {
        float heroX = this.transform.position.x;
        Vector2 dir = Vector2.zero;
 
 
        if (heroX > tposX)
        {
            dir = Vector2.left;
            this.transform.localScale = new Vector3(555);
            
        }
        if (heroX < tposX)
        {
            dir = Vector2.right;
            this.transform.localScale = new Vector3(-555);
        }
 
        if(this.moveRoutine!=null)
        {
            this.StopCoroutine(this.moveRoutine);
        }
 
        this.moveRoutine = this.StartCoroutine(this.MoveIE(tposX, dir));
 
    }
 
    public void Jump()
    {
        this.anim.Play("Jump");
 
        if (this.transform.position.y < this.maxHeight)
        {
            this.isJump = false;
        }
        
        if(this.jumpRoutine!=null)
        {
            this.StopCoroutine(this.jumpRoutine);
        }
        this.jumpRoutine = this.StartCoroutine(this.JumpIE());
    }
    
    IEnumerator JumpIE()
    {
        while(true)
        {
            if (!this.isJump)
            {
                Debug.Log("올라감");
                float currentSpeed = (3.5f + this.g * Time.deltaTime) * Time.deltaTime;
                this.transform.Translate(Vector3.up * currentSpeed);
                
            }
 
            if (this.transform.position.y >= this.maxHeight)
            {
                Debug.Log("정점");
 
                //더 자연스럽게 보이기 위해 체공시간을 넣어봤는데
                //좀 더 떠있긴 함
 
                this.delayTime += Time.deltaTime;
                if(this.delayTime>=0.15f)
                {
                    this.isJumpDown = true;
                    this.delayTime = 0;
                }
                this.isJump = true;
            }
 
            if(this.isJumpDown)
            {
                Debug.Log("내려감");
 
                float currentSpeed = (3.5f - this.g * Time.deltaTime) * Time.deltaTime;
                this.transform.Translate(Vector3.down * currentSpeed);
 
            }
 
            if(this.isGround)
            {
                this.isGround = false;
                this.transform.position = new Vector3(this.transform.position.x, 0.5f, 0);
                this.OnJumpComplete();
                this.isJumpDown = false;
                break;
            }
 
 
            yield return null;
        }
    }
 
 
    IEnumerator MoveIE(float tposX, Vector2 dir)
    {
        
 
        this.anim.Play("Run");
 
        this.isMove = true;
 
        float distance = 0;
        while(true)
        {
            this.transform.Translate(dir * 2f * Time.deltaTime);
            distance = this.transform.position.x - tposX;
 
            if(distance<0)
            {
                distance *= -1;
            }
 
            if(distance<0.02f)
            {
                this.OnMoveComplete();
                this.isMove = false;
                break;
            }
            if(this.transform.position.x >= colliderHalfSize || this.transform.position.x <=-colliderHalfSize)
            {
                this.OnMoveComplete();
                this.isMove = false;
                break;
            }
            
 
            yield return null;
        }
 
        
    }
 
    IEnumerator DownIE()
    {
        Debug.Log(this.isGround);
 
        while (true)
        {
            this.transform.Translate(Vector3.down * g * Time.deltaTime);
            if (this.isGround)
            {
                this.transform.position = new Vector3(00.5f, 0);
                this.OnDownComplete();
                this.isGround = false;
                break;
            }
            yield return null;
        }
    }
 
 
    //콜라이더가 붙어있는 게임오브젝트가 가장 상위에 있어야 제대로 적용됨
    //모델에 콜라이더가 있는데 hero껍데기를 만들어서 껍데기를 부모로 설정하면
    //콜라이더 적용이 안되고 프리패스함
    //히어로 껍데기에 콜라이더가 붙어있던가 
    //히어로 껍데기를 씌우지 않고 모델에 붙어있던가 해야함
    private void OnTriggerEnter(Collider other)
    {
        
        if (other.CompareTag("ground"))
        {
            this.isGround = true;
        }
    }
}