본문 바로가기
Unity/2D

[Unity]2D게임만들기 #4_ 플레이어 점프 구현

by Meaning_ 2021. 9. 26.
728x90
반응형

물리력에 의한 점프 


 

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
public class PlayerMove : MonoBehaviour
{
    public float maxSpeed;
    public float jumpPower;
    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;
    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        rigid.freezeRotation = true;
        spriteRenderer = GetComponent < SpriteRenderer >();
        anim = GetComponent<Animator>();
    }
 
    // 키보드에서 손을 뗐을 때 완전 stop -->멈출 때 속도 
    private void Update() //즉각적인 키 입력 ,단발적인 키 입력
    {
 
        //점프
 
        if (Input.GetButtonDown("Jump"))
        {
            rigid.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
 
        }
cs

 

 

jumpPower 변수를 설정해준다음, 버튼을 눌렀을때 점프가 되는것을 구현했다.

 

그러면 inpsector창에 jumpPower을 설정해줄수 있는 공간이 마련된다. 나는 12정도로 설정해줬다.

 

유니티에서 점프를 하려면 스페이스 바를 누르면된다. 스페이스 바를 누르면 캐릭터가 잘 점프하는 것을 볼 수 있다.

 

근데 내려올때 속도가 좀 느리다. 이유는 오르막길을 만들려고 LinearDrag를 이용해서 공기저항을 설정했기에 떨어질 때 느리게 떨어지는 것이다.

 

 

중력의 크기를 키워서 빨리 떨어지게 만들어 볼것이다. 

 

중력은 Edit ->Project Settings ->Physics 2D에서 설정가능하다. 

 

Gravity에서 y의 디폴트 값이 -9.81인데 나는 -20정도로 설정했다.

 

project setting을 싫어하는 사람들은 Rigid Body의 Gravity Scale을 이용하면되는데, 이는 오브젝트에 적용되는 중력비율을 말한다. 

디폴트 값이 1이였는데 나는 4정도로 맞춰줬다.

 

점프 - 착지 애니메이션


얘네 세개를 선택해서 Animation 폴더에 PlayerJump를 만들고 jump.anim으로 저장해준다. 

Loop를 켜면 이상할수 있어서 Loop는 꺼준다. 

Animator를 켜준후 idle과 Walk랑 연결시켜준다. 

parameter에서 bool타입의 isJumping 변수를 만들어준다. 예를들어 걷다가 점프하려면 Walk에서 파라미터의 isJumping변수가 true일 때 점프할 수 있게된다.


walk -> jump일 때 

이렇게 겹치는 구간이 생기는데

 

즉, 겹치는 경우를 다 없애주면 된다.

 

또한 걷다가 점프하는 경우, 가만히 있다 점프하는 경우는

isJumping을 true로 해줘야한다.

당연히 isWalk는 false

 

점프하다가 가만히 있는경우는 

둘다 false

 

다만, 점프하고 걸어야 되면 isJumping은 false지만 isWalk는 true가 된다!

 

다시 코드로 돌아와서 

아까 만들어준 점프 관련 코드에 노란 형광펜 친 코드를 넣어주면된다. 

 

 

점프 애니메이션이 한번만 돌고 끝나는데, 이러면 나중에 문제가 생길 수 있어서 레이 캐스트로 해결해 볼 것이다. 

레이 캐스트


RayCast

:오브젝트 검색을 위해 Ray를 쏘는 방식

 

게임오브젝트의 원점에서 내가 설정한 방향으로 ray를 날려 내가 설정한 거리 이내에 물체가 있는지 없는지 충돌감지를 해주는 기능이다! 

 

 

<참고자료>

https://chameleonstudio.tistory.com/63

 

유니티 레이캐스트 Raycast 충돌 / Ray의 모든 것

해당 티스토리 페이지는 필자가 유니티 C# 개발을 하면서 학습한 내용들을 기록하고 공유하는 페이지입니다 ! - 틀린 부분이 있거나, 수정된 부분이 있다면 댓글로 알려주세요 ! - 해당 내용을 공

chameleonstudio.tistory.com

 

우리가 Raycast를 쓰는것은 점프 애니메이션이 잘 돌아가게 하기 위함이므로 바닥과 플레이어의 충돌을 중점적으로 봐주면 되겠다-!

 

DrawRay()

: 에디터 상에서만 Ray를 그려주는 함수 

 

DrawRay(시작,방향,색깔) 순으로 입력해주면된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void FixedUpdate() //지속적인 키 입력
    {
        float h = Input.GetAxisRaw("Horizontal");
        rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
 
        //최대속도 
        if (rigid.velocity.x > maxSpeed)//오른쪽
        {
            rigid.velocity = new Vector2(maxSpeed,rigid.velocity.y);//y값을 0으로 잡으면 공중에서 멈춰버림
        }else if (rigid.velocity.x < maxSpeed*(-1))//왼쪽
        {
            rigid.velocity = new Vector2(maxSpeed*(-1), rigid.velocity.y);
        }
 
        // Landing Platform
 
        Debug.DrawRay(rigid.position, Vector3.down, new Color(010));
        // 시작,방향 색깔
    }
}
cs

--> Debug.DrawRay()가 추가된 부분이다. 

그러면 Scence창에서만 연두색 빔같은게 보인다!

 

이제 빔을 쏴볼 것인데 이때는 RayCastHit가 사용된다. 이는 Ray에 닿은 오브젝트를 뜻한다. 

RaycastHit은 draw랑 다 비슷한데  시작,방향,광선을 쏘는 길이 이다.

 

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
  void FixedUpdate() //지속적인 키 입력
    {
        float h = Input.GetAxisRaw("Horizontal");
        rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
 
        //최대속도 
        if (rigid.velocity.x > maxSpeed)//오른쪽
        {
            rigid.velocity = new Vector2(maxSpeed,rigid.velocity.y);//y값을 0으로 잡으면 공중에서 멈춰버림
        }else if (rigid.velocity.x < maxSpeed*(-1))//왼쪽
        {
            rigid.velocity = new Vector2(maxSpeed*(-1), rigid.velocity.y);
        }
 
        // Landing Platform
 
        Debug.DrawRay(rigid.position, Vector3.down, new Color(010));
        // 시작,방향 색깔
 
        RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down,1);
 
        
        //빔에 맞았는지 
        if (rayHit.collider!=null)
        {
            Debug.Log(rayHit.collider.name);
        }
    }
cs

 

ray를 플레이어가 맞은 것을 볼 수 있다. 

플레이어에서 쐈는데 플레이어가 맞았다?! 의미가 없는 로직이다.


 

빔을 쏴서 바닥이 있는지 없는지를 판단해줘야 하기에 레이어를 사용해 볼 것이다. 

 

Layer Mask

: 물리효과를 구분하는 정수 값 

 

 

인스팩터창 바로 위에 있다!

레이어는 씬의 일부를 랜더링하거나 물리적 충돌을 판정하는데 쓰인다고 한다. 태그와 레이어의 차이점은 태그의 경우 단순 tag 개체를 찾을 때 사용하는 반면 레이어의 경우 게임오브젝트를 번들로 묶는 그룹같은 것이다. 

 

<참고자료>

https://keemeesuu.github.io/2020/unity/tag,layer

 

[UNITY] Tag, Layer 사용 개념(차이점)

Layer 와 Tag는 여러 용도로 사용하지만, 그 중 그룹을 묶을때 유용하게 사용된다. 그룹을 묶는다는 것은 플레이어, 적들, 텍스쳐 등등 이다.

keemeesuu.github.io

https://notyu.tistory.com/38

 

유니티 레이어와 태그 (Layers and Tags)

1. 레이어 ( Layers ) 레이어(Layer)는 오브젝트들의 그룹을 만들고 관리하는 데 사용됩니다. 레이어는 씬의 일부분만을 렌더링 하거나, 물리적 충돌을 판정하는 데 사용됩니다. 유니티는 0-7까지의

notyu.tistory.com

 

 

 

addLayer를 누른후 8번에 Platform이라는 레이어를 직접 추가해준다.

 

 

그리고 위 사진처럼 floor에 해당하는 레이어를 다 Platform으로 바꿔준다.  --> 아까 위에서 말했던 게임 오브젝트를 그룹으로 묶는 기능으로 레이어가 사용됐다!

 

 

RaycastHit 코드에서 Layer.GetMask를 추가해준다.

GetMask()

 

: 레이어 이름에 해당하는 정수값을 리턴하는 함수 

 

이걸 사용하면 "Platform" 레이어에 해당하는 애랑만 충돌했는지 쉽게 알 수 있다. 

 

캐릭터가 위치한 곳이 14번 floor인데 

 

콘솔창에도 14번 floor에 관통되었다고 뜬다!

 

이제 플레이어가 플랫폼과 밀착하여 착지했는지를 알아볼 것이다.

 

1
2
3
4
5
6
7
8
9
10
        if (rayHit.collider!=null)
        {
            
            if (rayHit.distance < 0.5f)
            {
                //플레이어의 절반크기만큼이여야 바닥에 닿은거 
                Debug.Log(rayHit.collider.name);
            }
           
        }
cs

 

distance

:Ray에 닿았을 때 거리

 

왜 0.5보다 작아야 하는지 의문이 생길 것이다.

 

플레이어의 크기가 1cm인데 플레이어와 바닥의 충돌이 0.5보다 작아야 몸이 땅에 닿기 때문이다. 

또는 빔이 몸보다 0.5cm 아래 지점부터 쏘게되는데 빔과 floor가 충돌하는거리가 0.5보다 작아야 플레이어가 땅에 닿았다고 볼 수 있기 때문이다. 나는 후자로 이해해보았다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
if (rayHit.collider!=null)
        {
            
            if (rayHit.distance < 0.5f)
            {
 
                anim.SetBool("isJumping"false);
                //플레이어의 절반크기만큼이여야 바닥에 닿은거 
                Debug.Log(rayHit.collider.name);
            }
           
        }
cs

 

점프하고 착지했을때 아까 만들어준 애니메이터의 파라미터가 false로 바뀌어야 한다. 이제 더는 점프하는게 아니기 때문에!

 

그래서

anim.SetBool("isJumping"false);

--> 이 코드를 추가해주었다.

 

근데 이렇게 하면 내려가고 있을 때가 아니여도 계속 빔을 쏜다. 올라가거나 가만히 있을 때도 빔을 쏜다.ㅋㅋㅋ

 

그래서 rigid.velocity.y <0 일때만 빔을 쏘는 것으로 바꿔줬다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
        if (rigid.velocity.y < 0)
        {
            Debug.DrawRay(rigid.position, Vector3.down, new Color(010));
            // 시작,방향 색깔
 
            RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform"));
 
            //시작,방향,빔 길이,레이어
            //raycasthit 레이어에 해당하는 애만 구별하겠다는거
            //빔에 맞았는지 
            if (rayHit.collider != null)
            {
 
                if (rayHit.distance < 0.5f)
                {
 
                    anim.SetBool("isJumping"false);
                    //플레이어의 절반크기만큼이여야 바닥에 닿은거 
                    Debug.Log(rayHit.collider.name);
                }
 
            }
        }
cs

 

이제 올라갈 때는 더이상 빔을 쏘지 않는다! 

 

이렇게 하고 Animator를 실행해보니 한번만 점프하고 멈추는게 아니라 계속 애니메이션이 작동하는 것을 확인할 수 있었다!!

 

즉, 레이캐스트를 통해 낙하하고 플레이어가 플랫폼에 닿았을 때 isJumping 파라미터를 꺼주어서 동시에 걷는 상태나 가만히 있는 상태로 바로 이어지게 되어서 한번만 점프하고 애니메이션이 끝나는 것이 아닌 jump,walk,idle 애니메이션이 다같이 계속 작동하는 것을 확인할 수 있었다

(혹시 이렇게 이해한게 틀렸다면 댓글로 알려주세요 ..!)

 

무한 점프 막기


스페이스바를 계속 누르면 그 수만큼 점프가 되는데  두번이상 점프하는 것을 막으려면 어떻게 해야할까?

 

스페이스바를 누른 상황과 isJumping 매개변수가 false인 상황에서만 (즉 jump가 아닌 상황에서만) 점프 할수 있게 설정해주면 된다!

728x90
반응형

댓글