본문 바로가기

GAME

[Unity2D]플레이어 이동/점프

728x90

 

전 게시글에서 이어서 작성해서 스프라이트는 동일합니다.

[유니티 기초 - B15] 2D플레이어 이동 구현하기

[유니티 기초 - B16] 2D플레이어 점프 구현하기

 

이동 구현하기 

일단 이동을 구현하기위해 맵 크기를 늘려줬습니다.

 

 

<물리이동>

 

단순이동 

스크립트 폴더를 만들고 그 안에 캐릭터 걷기를 위한 스크립트

PlayerMove.cs 를 만들어 줍니다.

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

public class PlayerMove : MonoBehaviour
{
    Rigidbody2D rigid; //물리이동을 위한 변수 선언 

    private void Awake() {
        
        rigid = GetComponent<Rigidbody2D>(); //변수 초기화 

    }

    // Update is called once per frame
    void FixedUpdate()
    {
        float h = Input.GetAxisRaw("Horizontal");   
        rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);

    }
}

스크립트를 캐릭터에게 넣어준 뒤 실행하면 캐릭터가 양옆으로 이동하는 모습을 볼 수 있습니다

 

 

최대속력 정하기

위와 같은 코드는 AddForce라는 함수를 이용하여 1초에 50회이상 실행되므로 

1초동안 방향키를 누르고있으면 캐릭터에 그만큼 힘이 더해져 무한으로 가속도가 증가하게됩니다

게임은 이런식으로 작동하지 않으므로 최대 가속도를 부여해야합니다

public float maxSpeed; //최대 속력 변수 

    void FixedUpdate()
    {
    	//Move by Key
        float h = Input.GetAxisRaw("Horizontal");   
        rigid.AddForce(Vector2.right * h, ForceMode2D.Impulse);

		//Max speed Right
        if(rigid.velocity.x > maxSpeed)  //오른쪽으로 이동 (+) , 최대 속력을 넘으면 
            rigid.velocity= new Vector2(maxSpeed, rigid.velocity.y); //해당 오브젝트의 속력은 maxSpeed 
        
        //Max speed left
        else if(rigid.velocity.x < maxSpeed*(-1)) // 왼쪽으로 이동 (-) 
            rigid.velocity =  new Vector2(maxSpeed*(-1), rigid.velocity.y); //y값은 점프의 영향이므로 0으로 제한을 두면 안됨 

    }

maxSpeed라는 최대 속력을 부여하여 오른쪽, 왼쪽에 대하여 이 속력을 넘었을 경우 

속도를 최대 속력으로 지정해주는 코드 

이때, y값과는 관계없으므로 그에 대해 제한을 두면안됨 

 

public으로 선언했으므로 유니티 화면 내에서 지정가능 

3으로 제한을 두면 속력이 3이상으로 가속되지 않습니다. (너무 느려서 4로했습니다)

 

이동가능

 

 

맵 Floor의 물리적 성질 

맵 바닥의 마찰력등등이 이동에 영향을 주기 때문에 조절해주어야 합니다.

Physical Material 폴더를 만들어 Physical Material2D을 만들고 이름을 Platform으로 지정해주었습니다.

rigidbody를 2D를 사용했으면 이것도 2D를 사용해야함 

 

2D는 생각보다 간단한데 마찰력/탄성력 두개입니다.

나중에 오르막지형을 구현하려면 마찰력을 0으로 해야한다네요 

 

이제 모든 지형에 적용시켜줍니다 

 

원하는 지형을 전부 선택한 후에 

 

Box Collider 2D -> Material에 만든 Physical Material을 드래그해주시면 한번에 여러개에 적용이 동시에 가능합니다

 

이렇게 되면 마찰력이 0이 되므로 한번의 힘이 주어지면 끝없이 밀려나게 됩니다 (물리시간에 .. 배웠던것 같네요)

이제 이것을 막아 주어야 합니다

 

 

플레이어 저항 설정( 지나치게 밀려나지 않게 하기 )

플레이어 자체의 (공기)저항을 이용하여 이 현상을 막아봅시다 

플레이어의 Rigidbody2D를 이용합니다.

Linear Drag : 공기 저항, 이동 시 속도를 느리게 해줌 

1 정도로 잡으면 적당히 공기저항을 받게되므로 전처럼 많이 밀려나지는 않습니다

(이는 y축으로의 공기저항 또한 받게되므로,  점프 구현시에도 영향을 미쳐 너무 크게 잡으면 점프 후 착지가 느려지니 주의 )

 

공기 저항을 받아도 미세하게 밀려나는 현상을 

키보드에서 손을 때면 급격하게 속력이 줄어들도록 만들어봅시다

즉, " 키보드에서 손을 땔 때(ButtonUp) 속도 = 멈출 때 속도 "를 지정해주는 코드를 넣어봅시다  

 

버튼에서 손을 때는 등의 단발적인 키보드 입력은 Update에 사용해야 누락 될 가능성이 낮다고 합니다.

    void Update(){

        // 버튼에서 손을 떄는 등의 단발적인 키보드 입력은 FixedUpdate보다 Update에 쓰는게 키보드 입력이 누락될 확률이 낮아짐

        //Stop speed 
        if(Input.GetButtonUp("Horizontal")){ // 버튼에서 손을 때는 경우 
            // normalized : 벡터 크기를 1로 만든 상태 (단위벡터 : 크기가 1인 벡터)
            // 벡터는 방향과 크기를 동시에 가지는데 크기(- : 왼 , + : 오)를 구별하기 위하여 단위벡터(1,-1)로 방향을 알수 있도록 단위벡터를 곱함 
            rigid.velocity = new Vector2( 0.5f * rigid.velocity.normalized.x , rigid.velocity.y);
        }

    }

방향키 입력에서 손을 땔 때 ,  속도를 급격하게 0.5로 줄이도록 합시다 ( 소수는 항상 f를 써야함)

이때, 오른쪽은 +0.5 , 왼쪽은 -0.5가 되어야하므로 각각 1과 -1을 곱해주어야합니다.

이를 알 기 위하여 현재의 속도를 rigid.velocity.x로 가져올 수 있고, 그럼아마 -4 ~ 4 이내의 크기를 가질탠데

이를 1로 만들어주기 위하여 단위벡터를 구하는 normalized를 사용합니다.

 

 

이를 실행하면 이제 캐릭터가 밀려나지않고 바로 멈추는 것을 볼 수 있습니다.

 

* 넘어짐 방지

또한 플레이어의 rigidbody2D에서 Constraints Z 로테이션을 막아주지 않으면 캐릭터가 넘어질 수 있으니 제한을 걸어주세요 

오브젝트 회전을 얼리는 옵션

 

 

 

애니메이션 

이제 걸을때 Idle 애니메이션이 아닌 Walk애니메이션이 실행되도록 해봅시다 

 

플레이어 오브젝트 반대로 돌리기 

그런데 왼쪽으로 걸을 때, 오른쪽으로 걸을 때의 애니메이션이 반대방향입니다 

플레이어의 Sprite Renderer 컴포넌트에서 Flip에 체크를 해주시면 

반대로 돌아가는 것을 볼 수 있습니다 (마찬가지로 Y는 거꾸로 돌아감)

애니메이션을 2개 그릴 필요가 없네요

 

오브젝트가 반대로 돌아가는 것을 방향키를 눌렀을 때 돌아가도록 코드를 작성해 봅시다 

SpriteRenderer컴포넌트 변수를 만들어 주어야 합니다 - > 초기화는 이제 기본

만든후 Flip X를 체크(bool) 로 만들어주어야 합니다.

 

    SpriteRenderer spriteRenderer; //방향전환을 위한 변수 
    
        private void Awake() {
        spriteRenderer = GetComponent<SpriteRenderer>(); // 초기화 
    }
    
        void Update(){

        // 물리 현상이 아니므로 Update에 넣어야함 


        //Direction Sprite
        if(Input.GetButtonDown("Horizontal")) // 방향키 입력이 들어오면 실행 
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1; // -1 (왼쪽이면, flipX true(체크))

    }

 

 

Walk애니메이션 적용

Animator를 켭시다( 여기서 원하는 오브젝트명을 클릭하면 해당하는 오브젝트의 애니메이터가 켜짐)

 

Idle에서 오른쪽 마우스를 클릭 -> Make Transition 

Idle에서 어떤 상태변화를 일으키는지 알려주는 연결입니다 

Walk와 연결해줍시다 

 

Parameters를 클릭하여 걷고있는 상태인지 아닌지 true false로 나타내는

bool형 변수 isWalking을 추가해봅시다

Idle상태에서 Walk상태로 간다는 것은 isWalking 변수가 true가 되었다는 것을 의미합니다 

끄덕

 

Insepctor에서 Condition이 없는 상태인데 +를 눌러서 추가해줍니다 

 

애니메이션을 자연스럽게 움직이게 겹쳐주는건데 도트는 뚝딱..뚝딱 움직여서 0으로 아예 없애주시고

Has Exit Time: 애니메이션이 끝날 때 상태를 유지 -> 체크해제 ( 이동이 멈췄는데 Idle상태로 돌아가지 않고 걷는모션)

 

 

반대로 걷다가 Idle로 돌아가는 상태에 대해서도

Condition 추가 ( 이때는 walking상태가 아니게 되므로 isWalking = false)

Has Exit TIme체크 해제

겹치는 구간 제거 

 

 

이제 스크립트를 이용해서 

걷고있을때 isWalking 변수를 true로, 멈추면 false로 만들어 주도록 합시다.

에니메이터 변수를 만들고 초기화 해야 사용할 수 있겠죠

   Animator animator; //애니메이터 조작을 위한 변수 
   
   
       private void Awake() {
        animator = GetComponent<Animator>();
    }
    
    
    
    void Update(){
        
        if(rigid.velocity.normalized.x==0) //속도가 0 == 멈춤 
            animator.SetBool("isWalking",false); //isWalking 변수 : false 
        else// 이동중 
            animator.SetBool("isWalking",true);
    }

 

움짤을 올리고싶은데.. 머신러닝 올릴 때 파워포인트하는거에 힘을 다써서... 의미없는 사진을 첨부

ㅎㅎ 제가 안그리니까 너무 귀엽고 고퀼이고 좋네요

 

이제 이동이 되는데 

속도 == 0 일 때 애니메이션이 바뀌는 걸로 하니까 멈춰도 조금 걷다가 Idle애니메이션으로 돌아가는 모습을 볼 수 있습니다.

이런건 속도를 굳이 =0 으로 하지않고 , 0.3 등 적당히 작은 수로 변경해주시면 해결됩니다

이때 그럴 경우 -0.3 ~ 0.3 사이이므로 속도를 절댓값을 씌워주시는게 좋습니다. 

        if(Mathf.Abs(rigid.velocity.x) < 0.3) //속력이 절댓값 0.3이하가 되면 Idle애니메이션으로 돌아감
            animator.SetBool("isWalking",false); //isWalking 변수 : false 
        else// 이동중 
            animator.SetBool("isWalking",true);

절댓값 함수는 Mathf.Abs(값) 입니다. 

이렇게 되면 당연히 normalized는 빼주셔야합니다. 단위벡터라 -1,1 만 가능하니까요 

이렇게 되니 더 부드러운 애니메이션이 가능해 졌습니다.

 

 

플레이어 오브젝트에 적용되는 전체코드 

PlayerMove.cs

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

public class PlayerMove : MonoBehaviour
{
    public float maxSpeed; //최대 속력 변수 
    Rigidbody2D rigid; //물리이동을 위한 변수 선언 
    SpriteRenderer spriteRenderer; //방향전환을 위한 변수 
    Animator animator; //애니메이터 조작을 위한 변수 

    private void Awake() {
        
        rigid = GetComponent<Rigidbody2D>(); //변수 초기화 
        spriteRenderer = GetComponent<SpriteRenderer>(); // 초기화 
        animator = GetComponent<Animator>();
    }


    void Update(){

        // 버튼에서 손을 떄는 등의 단발적인 키보드 입력은 FixedUpdate보다 Update에 쓰는게 키보드 입력이 누락될 확률이 낮아짐

        //Stop speed 
        if(Input.GetButtonUp("Horizontal")){ // 버튼에서 손을 때는 경우 
            // normalized : 벡터 크기를 1로 만든 상태 (단위벡터 : 크기가 1인 벡터)
            // 벡터는 방향과 크기를 동시에 가지는데 크기(- : 왼 , + : 오)를 구별하기 위하여 단위벡터(1,-1)로 방향을 알수 있도록 단위벡터를 곱함 
            rigid.velocity = new Vector2( 0.5f * rigid.velocity.normalized.x , rigid.velocity.y);
        }

        //Direction Sprite
        if(Input.GetButtonDown("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;

        
        if( Mathf.Abs(rigid.velocity.x) < 0.2) //속도가 0 == 멈춤 
            animator.SetBool("isWalking",false); //isWalking 변수 : false 
        else// 이동중 
            animator.SetBool("isWalking",true);
    }

    // Update is called once per frame
    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); //해당 오브젝트의 속력은 maxSpeed 
        
        else if(rigid.velocity.x < maxSpeed*(-1)) // 왼쪽으로 이동 (-) 
            rigid.velocity =  new Vector2(maxSpeed*(-1), rigid.velocity.y); //y값은 점프의 영향이므로 0으로 제한을 두면 안됨 

    }
}

 

 

점프 구현하기

점프도 이동과 비슷한 순서? 방식으로 구현합니다.

 

단순점프 

점프 또한 스페이스 바를 단발적으로 누르는 것 이므로 Update에 구현해줍니다

마찬가지로 힘을 받는 addForce함수와 jumpPower변수를 이용합니다

이동과 다른점은 up(y축 위쪽으로의 이동)

    public float jumpPower;
    
    
     void Update(){

        // 버튼에서 손을 떄는 등의 단발적인 키보드 입력은 FixedUpdate보다 Update에 쓰는게 키보드 입력이 누락될 확률이 낮아짐


        //Jump
        if(Input.GetButtonDown("Jump"))
            rigid.AddForce(Vector2.up* jumpPower , ForceMode2D.Impulse);


       }

이제 스페이스 바를 누르면 점프가 가능합니다

 

 

중력 적용하기

아까 공기저항을 줬더니 위로 올라가는 속력과 점프후 떨어지는 속력이 다릅니다.

점프 후 떨어질때 공기 저항을 받아 더 느리게 떨어지게 되는데 이는 중력을 적용하면 더 빠르게 떨어지게 할 수 있습니다.

 

중력을 크게하는 법

Edit -> Project Settings -> Physics2D -> Gravity 

y값을 크게 (절댓값이 크게) 수정해주시면 더 빠르게 떨어집니다

 

또한 rigidbody2D에서 오브젝트에 적용되는 중력 비율을 늘려줄수도 있습니다

rigidbody2D -> Gravity Scale (1이 100%)

저는 4로 늘려주었는데요

이렇게 되면 떨어지는 속도는 빨라지지만 점프높이도 낮아집니다

그러니 jumpPower을 적절하게 늘려서 조절해주시면 

적절한 높이의 점프를 빠른속도로 떨어지게 가능합니다 

 

저는 JumpPower = 12 , Gravity Scale = 4, Gravity Y = -9.81 로 했습니다.

 

 

 

 

애니메이션

 

애니메이션 만들기 

이렇게 3개의 텍스쳐로 이루어진 점프모션을 드래그해서 애니메이션을 만들어 줍시다 

 

애니메이션 폴더 안에 Jump라는 이름으로 save

 

*참고 : 점프는 Loop꺼주셔야합니다 (반복하면 이상한모양됨)

 

 

 

애니메이션  설정

Idle / Walk / Jump 3가지가 모두 전환되는 것이 가능해야합니다

isJumping이라는 변수를 bool형으로 생성해줍니다 

 

마찬가지로 모든 연결 6개에 대하여 동일하게

Condition 에 isJumping 추가 

Has Exit TIme체크 해제

겹치는 구간 제거 

3가지를 완료해줍시다. 

물론 각각 6가지에 isWalking / isJumping상태도 true /false를 적절하게 입력해주셔야 합니다

관계를 이제 충분히 파악할 수 있으니 이것은 알아서 설정 하도록...합니다 

 

스크립트 수정

 

점프하고 있을때 isJumping 변수를 true로, 바닥에 착지하면 false로 만들어 주도록 합시다.

        //Jump
        if(Input.GetButtonDown("Jump")){
            rigid.AddForce(Vector2.up* jumpPower , ForceMode2D.Impulse);
            animator.SetBool("isJumping",true);
        }

아까 만들어 둔 Jump함수에서 isJumping을 true로 변경하는 코드를 한 줄 추가해줍니다.

 

바닥에 착지해야 false이므로 else문으로 구현하기 어렵습니다

레이케스트 라는 것을 이용합니다

 

레이케스트 RayCast

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

 

어떤 방식인지 설명하면, 스크립트에 빔을 쏘는 함수를 사용하면

해당 스크립트가 적용된 오브젝트의 중앙에서 설정한 방향으로 빔을 쏩니다 

예시로 플레이어 스크립트에서 빔을 쏘도록 했을때 모습입니다.

초록색 선이 보이실 탠데 저 선이 빔입니다

해당 빔이 어떤 Object의 경계인 Collider와 충돌하면, 충돌한 오브젝트를 알려주는 것이 RaycastHit2D입니다.

그렇다면 플레이어에서 빔을 쏴서 바닥 맵의 Collider와 닿게될 경우 바닥에 닿았는지 판정할 수 있을 것입니다.

 

그럼 먼저 플레이어 중앙에서 빔을 쏘는 스크립트를 작성합시다

FixedUpdate() 에 작성해야함 

Debug.DrawRay(rigid.position, Vector3.down, new Color(0,1,0)); 
//빔을 쏨(Debug. : 게임 창 상에 보이지 않음 ) 매개변수 : 빔 시작위치, 빔의 방향, 빔의 색 

rigid.poisiton을 통해 오브젝트의 포지션에서부터 아래방향으로  초록빔을 쏘는 함수를 사용했습니다. 

실행해 보면 Scene상에서는 확인되지만 Game창에서는 확인할 수 없는 초록선이 생겨납니다 

 

Scene / Game

 

이제 빔과 닿은 오브젝트를 알려주는 클래스 : RayCastHit2D 를 사용해서 

어떤 오브젝트와 닿았는지 정보를 가져오면, (마찬가지로 FixedUpdate에 써야함)

        RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1);
        //빔시작위치, 빔의방향 , 1:distance , Ray에 닿은 오브젝트 클래스 
    
        //rayHit는 여러개 맞더라도 처음 맞은 오브젝트의 정보만을 저장(?) 
        if(rayHit.collider != null){ //빔을 맞은 오브젝트가 있을때  -> 맞지않으면 collider도 생성되지않으므로 
            Debug.Log(rayHit.collider.name); //맞은 오브젝트의 이름을 출력 
        }

콘솔창에 오브젝트의 이름을 출력하는 코드를 작성해보았습니다. 

 

실행해보면 한가지 문제점이 발견됩니다.

RayCastHit2D는 처음 빔을 맞은 오브젝트의 정보만을 저장하는데

플레이어 오브젝트 중앙에서 나간 빔을 가장 먼저 맞는 collider는 플레이어(Char)입니다.

콘솔창에 Char이 뜨는 것을 확인할 수 있습니다.

 

우리가 원하는것은 일단 플레이어는 제외하고 다른 것 이므로 플레이어의 collider를 무시하는 방법에 대해 설명하도록 하겠습니다.

 

 

Layer레이어

바로 Layer을 사용하는 것 입니다.

LayerMask : 물리 효과를 구분하는 정수값(Tag와 비슷한 식별자인데 조금 특별함)

다른레이어끼리 부딪히지 않게 설정이 가능함 

 

 

Platform이라는 레이어를 새로 추가합니다

그 후 바닥맵에 해당하는 모든 오브젝트의 레이어를 Platform으로 변경해줍니다.

마찬가지로 shift를 이용해 전부 선택한다음 바꾸어주면됨

 

그다음 코드에 매개변수를 하나 추가해주면


        RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform"));
        //빔의 시작위치, 빔의 방향 , 1:distance , ( 빔에 맞은 오브젝트를 특정 레이어로 한정 지어야할 때 사용 ) // RaycastHit2D : Ray에 닿은 오브젝트 클래스 
    
      

매개변수를 하나 추가해주었습니다.

빔에 맞은 오브젝트 중 특정 레이어만을 판단하겠다는 의미입니다.

우리는 Platform레이어를 가진 오브젝트만 탐지하기로 코딩을 완료했고 실행해보면

 

움직이면 플레이어가 아닌 다양한 맵의 이름이 나오는 것을 확인 할 수 있습니다.

 

이제 바닥에 완전히 밀착되었을 때를 측정해봅시다

        //Landing Paltform
        Debug.DrawRay(rigid.position, Vector3.down, new Color(0,1,0)); //빔을 쏨(디버그는 게임상에서보이지 않음 ) 시작위치, 어디로 쏠지, 빔의 색 

        RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform"));
        //빔의 시작위치, 빔의 방향 , 1:distance , ( 빔에 맞은 오브젝트를 특정 레이어로 한정 지어야할 때 사용 ) // RaycastHit2D : Ray에 닿은 오브젝트 클래스 
    
        //rayHit는 여러개 맞더라도 처음 맞은 오브젝트의 정보만을 저장(?) 
        if(rigid.velocity.y < 0){ // 뛰어올랐다가 아래로 떨어질 때만 빔을 쏨 
            if(rayHit.collider != null){ //빔을 맞은 오브젝트가 있을때  -> 맞지않으면 collider도 생성되지않음 
                if(rayHit.distance < 0.5f) 
                    animator.SetBool("isJumping",false); //거리가 0.5보다 작아지면 변경

            }
        }

 

rayHit의 거리를 0.5 이하로 두는데요 이는 빔의 길이가 1이고 중앙으로 부터 나오며 캐릭터의 크기또한 1이기 때문에

캐릭터의 중앙에서 발밑까지가 0.5이기 때문입니다.

 

그리고 아래로 내려갈때만 빔을 측정하는 것이 좋은데 위로 올라갈때도 빔을 쏘면 올라가는 순간에도 거리가 0.5이하가 되어 모션이 보이지 않게됩니다 

 

무한점프 막아주기(점프1회로 제한)

미리 만들어둔 isJumping이 false일 때만 점프가 가능하다고 하면 1회점프를 구현할 수 있겠네요

animator.getBool("bool형 변수명") 을 통해 isJumping변수를 가져옵니다

        //Jump
        if(Input.GetButtonDown("Jump") && !animator.GetBool("isJumping")){
            rigid.AddForce(Vector2.up* jumpPower , ForceMode2D.Impulse);
            animator.SetBool("isJumping",true);
        }

 

 

 

이제 캐릭터의 점프와 이동을 완성했습니다.

 

PlayerMove.cs 전체코드

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

public class PlayerMove : MonoBehaviour
{
    public float maxSpeed; //최대 속력 변수 
    public float jumpPower;
    Rigidbody2D rigid; //물리이동을 위한 변수 선언 
    SpriteRenderer spriteRenderer; //방향전환을 위한 변수 
    Animator animator; //애니메이터 조작을 위한 변수 

    private void Awake() {
        
        rigid = GetComponent<Rigidbody2D>(); //변수 초기화 
        spriteRenderer = GetComponent<SpriteRenderer>(); // 초기화 
        animator = GetComponent<Animator>();
    }


    void Update(){

        // 버튼에서 손을 떄는 등의 단발적인 키보드 입력은 FixedUpdate보다 Update에 쓰는게 키보드 입력이 누락될 확률이 낮아짐


        //Jump
        if(Input.GetButtonDown("Jump") && !animator.GetBool("isJumping")){
            rigid.AddForce(Vector2.up* jumpPower , ForceMode2D.Impulse);
            animator.SetBool("isJumping",true);
        }

        //Stop speed 
        if(Input.GetButtonUp("Horizontal")){ // 버튼에서 손을 때는 경우 
            // normalized : 벡터 크기를 1로 만든 상태 (단위벡터 : 크기가 1인 벡터)
            // 벡터는 방향과 크기를 동시에 가지는데 크기(- : 왼 , + : 오)를 구별하기 위하여 단위벡터(1,-1)로 방향을 알수 있도록 단위벡터를 곱함 
            rigid.velocity = new Vector2( 0.5f * rigid.velocity.normalized.x , rigid.velocity.y);
        }

        //Direction Sprite
        if(Input.GetButtonDown("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;

        
        //Animation
        if( Mathf.Abs(rigid.velocity.x) < 0.2) //속도가 0 == 멈춤 
            animator.SetBool("isWalking",false); //isWalking 변수 : false 
        else// 이동중 
            animator.SetBool("isWalking",true);
    }

    // Update is called once per frame
    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); //해당 오브젝트의 속력은 maxSpeed 
        
        else if(rigid.velocity.x < maxSpeed*(-1)) // 왼쪽으로 이동 (-) 
            rigid.velocity =  new Vector2(maxSpeed*(-1), rigid.velocity.y); //y값은 점프의 영향이므로 0으로 제한을 두면 안됨 


        //Landing Paltform
        Debug.DrawRay(rigid.position, Vector3.down, new Color(0,1,0)); //빔을 쏨(디버그는 게임상에서보이지 않음 ) 시작위치, 어디로 쏠지, 빔의 색 

        RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("Platform"));
        //빔의 시작위치, 빔의 방향 , 1:distance , ( 빔에 맞은 오브젝트를 특정 레이어로 한정 지어야할 때 사용 ) // RaycastHit2D : Ray에 닿은 오브젝트 클래스 
    
        //rayHit는 여러개 맞더라도 처음 맞은 오브젝트의 정보만을 저장(?) 
        if(rigid.velocity.y < 0){ // 뛰어올랐다가 아래로 떨어질 때만 빔을 쏨 
            if(rayHit.collider != null){ //빔을 맞은 오브젝트가 있을때  -> 맞지않으면 collider도 생성되지않음 
                if(rayHit.distance < 0.5f) 
                    animator.SetBool("isJumping",false); //거리가 0.5보다 작아지면 변경

            }
        }
    }
}

 

 

 

+) 2020.08.07 추가

플레이어 이동애니메이션에 버그가 발생 

void Update(){} 함수 내의 코드를 아래와 같이 수정해주면 해결된다고 합니다 

//입력키가 아래로 눌리는 것이 다른 키와 중첩되면 인식되지 않을 수 있음
		//Direction Sprite
        if(Input.GetButtonDown("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;


//Down을 제거해서 그냥 버튼입력으로 수정
        //Direction Sprite
        if(Input.GetButton("Horizontal"))
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;

Input.GetButtonDown("Horizontal") -> Input.GetButton("Horizontal")

 

 

<참고영상>

youtu.be/Z4iULRbiSTg

youtu.be/2SikOdH7xvQ

 

728x90