Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

codingfarm

5. 2d 플랫포머 - 내리막 길 본문

Unity3d

5. 2d 플랫포머 - 내리막 길

scarecrow1992 2020. 8. 2. 20:32

이젠 내리막길을 따라 내려가도록 해보자

사실 지금까지의 프로젝트에서도 각도가 낮은 내리막길에 대해서는 길을따라 내려가는듯이 보인다.

하지만 경사가 심해지면 캐릭터가 허공에 뜨는듯한 모습을 볼 수 있다.

이를 해결하기 위한 추가적인 조치를 하겠다

 

우선 Controller2D의 Move함수 내부를 확인하자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public void Move(Vector3 velocity) {
        UpdateRaycastOrigins ();
        collisions.Reset ();
        collisions.velocityOld = velocity;
 
        if (velocity.y < 0) {
            DescendSlope(ref velocity);
        }
        if (velocity.x != 0) {
            HorizontalCollisions (ref velocity);
        }
        if (velocity.y != 0) {
            VerticalCollisions (ref velocity);
        }
 
        transform.Translate (velocity);
    }
cs

충돌판정이전에 DescendSlope라는 함수가 추가된게 보인다 확인해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    void DescendSlope(ref Vector3 velocity) {
        float directionX = Mathf.Sign (velocity.x);
        Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomRight : raycastOrigins.bottomLeft;
        RaycastHit2D hit = Physics2D.Raycast (rayOrigin, -Vector2.up, Mathf.Infinity, collisionMask);
 
        if (hit) {
            float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
            if (slopeAngle != 0 && slopeAngle <= maxDescendAngle) {
                if (Mathf.Sign(hit.normal.x) == directionX) {
                    if (hit.distance - skinWidth <= Mathf.Tan(slopeAngle * Mathf.Deg2Rad) * Mathf.Abs(velocity.x)) {
                        float moveDistance = Mathf.Abs(velocity.x);
                        float descendVelocityY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;
                        velocity.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign (velocity.x);
                        velocity.y -= descendVelocityY;
 
                        collisions.slopeAngle = slopeAngle;
                        collisions.descendingSlope = true;
                        collisions.below = true;
                    }
                }
            }
        }
    }
cs

3. 수직방향을 감지하는 ray들 중에서 제일 아래에 있으며 이동방향에 맞추어 좌표를 얻는다.(rayOrigin)

4. 그리고 raycast를 통해 장애물이 있는지를 점검한다

7. 만약 장애물이 감지되었다면 hit.normal과 Vector2.up를 통해 장애물의 각도를 감지한다.

8. 각도가 0이 아니라면(평평하지 않다면) 그리고 내려갈 수 있는 각도라면 if문에 진입한다.

10. hit.distance - skinWidth를 $x$축 이동속도에 $\tan \theta$를 곱해서 이에 대응하는 y축 속도와 비교한다.

만약 후자가 더 크다면 그만큼 캐릭터가 빗면을 따라 이동하게끔 velocity를 수정해주고 여러가지 상태값들 설정해준다

 

 

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
    void VerticalCollisions(ref Vector3 velocity) {
        float directionY = Mathf.Sign (velocity.y);
        float rayLength = Mathf.Abs (velocity.y) + skinWidth;
 
        for (int i = 0; i < verticalRayCount; i ++) {
            Vector2 rayOrigin = (directionY == -1)?raycastOrigins.bottomLeft:raycastOrigins.topLeft;
            rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
            RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);
 
            Debug.DrawRay(rayOrigin, Vector2.up * directionY * rayLength,Color.red);
 
            if (hit) {
                velocity.y = (hit.distance - skinWidth) * directionY;
                rayLength = hit.distance;
 
                if (collisions.climbingSlope) {
                    velocity.x = velocity.y / Mathf.Tan(collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign(velocity.x);
                }
 
                collisions.below = directionY == -1;
                collisions.above = directionY == 1;
            }
        }
 
        if (collisions.climbingSlope) {
            float directionX = Mathf.Sign(velocity.x);
            rayLength = Mathf.Abs(velocity.x) + skinWidth;
            Vector2 rayOrigin = ((directionX == -1)?raycastOrigins.bottomLeft:raycastOrigins.bottomRight) + Vector2.up * velocity.y;
            RaycastHit2D hit = Physics2D.Raycast(rayOrigin,Vector2.right * directionX,rayLength,collisionMask);
 
            if (hit) {
                float slopeAngle = Vector2.Angle(hit.normal,Vector2.up);
                if (slopeAngle != collisions.slopeAngle) {
                    velocity.x = (hit.distance - skinWidth) * directionX;
                    collisions.slopeAngle = slopeAngle;
                }
            }
        }
    }
cs

 

25번째 줄에서 새로운 제어문이 생겼다.

캐릭터가 오르막길에 있을때 진입하는 if문으로

좌/우 방향으로 제일 아래쪽의 raycast를 보낸 후 충돌이 발생할 경우

이번타임에 분석한 바닥의 각도와 기존에 얻었던 각도가 다르다면

$x$출 속도와 경사면 각도를 수정한다.

 

 

 

'Unity3d' 카테고리의 다른 글

시간  (0) 2022.02.21
생성  (0) 2022.02.21
이동  (0) 2022.02.21
Ray  (0) 2022.02.21
코루틴  (0) 2022.02.20
Comments