본문 바로가기
# 게임/# Unity

사다리 만들기

by 쁘레레레레레 2020. 7. 29.

몇일전부터 틈틈히 사다리를 만들려고 애썼다.

 

원래 코드

    private void climb()
    {
        rb2D.gravityScale = 0.0f;
        movement.y = Input.GetAxisRaw("Vertical");
        Vector3 moveVelocity = new Vector3(0, 0, 0);
        if (movement.y > 0 && onLadder)
        {
            moveVelocity = Vector3.up;
            animator.SetInteger(animationState, (int)CharacterStates.climb);
        }
        else if (movement.y < 0 && onLadder)
        {
            moveVelocity = Vector3.down;
            animator.SetInteger(animationState, (int)CharacterStates.climb);
        }
        else
        {
            moveVelocity = Vector3.zero;
            animator.SetInteger(animationState, (int)CharacterStates.idle);
        }
        transform.position += moveVelocity * movementSpeed * Time.deltaTime;
    }

그간 GetAxisRaw에 대해 잘 알지 못했다. 단순히 Horizontal은 좌,우 Vertical은 상,하에 쓰이는 거구나 정도만 알고 있었는데

이번에 제대로 알게되었다.

 

이건 예전글에도 올라와있는 상태인데, https://atli-yeondi.tistory.com/31

 

유니티 개발일지 + Procedural Dungeon Generation in Unity #3

이전 글 : Procedural Dungeon Generation in Unity #2 https://atli-yeondi.tistory.com/30 Procedural Dungeon Generation in Unity #2 이전 글 : https://atli-yeondi.tistory.com/29 Procedural Dungeon Gener..

atli-yeondi.tistory.com

이때도 원인은 알고 있었다. if문과 같이 input.getKeyDown(KeyCode.W)를 써서 그런건데

이 문제를 어느정도 인지하고 있었고

그 코드를 위에도 나와있는

    private void climb()
    {
        rb2D.gravityScale = 0.0f;
        movement.y = Input.GetAxisRaw("Vertical");
        Vector3 moveVelocity = new Vector3(0, 0, 0);
        if (movement.y > 0 && onLadder)
        {
            moveVelocity = Vector3.up;
            animator.SetInteger(animationState, (int)CharacterStates.climb);
        }
        else if (movement.y < 0 && onLadder)
        {
            moveVelocity = Vector3.down;
            animator.SetInteger(animationState, (int)CharacterStates.climb);
        }
        else
        {
            moveVelocity = Vector3.zero;
            animator.SetInteger(animationState, (int)CharacterStates.idle);
        }
        transform.position += moveVelocity * movementSpeed * Time.deltaTime;
    }

이 코드를 작성했었다.  게임에서 중력은 작용하고 있었고 캐릭터를 위로 올려주려면 그에 맞는 값과 위로 작용하는 힘이 필요하다는걸 인지했고  사다리를 오르다 중간에 멈추는 경우를 생각해 사다리에 콜라이더를 부착해 트리거를 체크하고 bool을 넣어 참일경우  캐릭터의 리지드바디 중력값을 0으로 변경했었다.

 

그리고 지금 코드는 이렇다.

    public bool onLadder;
    public float climbSpeed;
    private float climbDirection;
    private float gravityStore;

	void Update()
    {
    	if(onLadder)
        	{
            	rb2D.gravityScale = 0f;

            	climbDirection = climbSpeed * Input.GetAxisRaw("Vertical");

            	rb2D.velocity = new Vector2(rb2D.velocity.x, climbDirection);
            	Debug.Log(rb2D.velocity);
        	}

        	if(!onLadder)
        	{
            	rb2D.gravityScale = gravityStore;
        	}
	}
    
    
    
    /// Ladder.cs
        private MovementController player;

    void Start()
    {
        player = GameObject.Find("Player").GetComponent<MovementController>();
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Player")
        {
            player.onLadder = true;
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if(collision.gameObject.tag == "Player")
        {
            player.onLadder = false;
        }
    }

대강 설명을 하자면 이렇다.

캐릭터의 움직임을 관장하는 코드에 4개의 변수를 선언했다.

1. bool onLadder = 캐릭터가 사다리와 겹쳐있나 판단하는 코드

2. float climbSpeed = 사다리를 오르는 속도, 기존에 movementSpeed가 있으나 사다리 속도는 개별로 주고 싶어서 따로 관리했다.

3. float climbDirection= 스피드 값에 위인지 아래인지 판단하는 값만 곱해서 상 하 방향을 결정해주는 변수이다.

4. float gravityStore = 직역 그대로이다. 중력값을 저장해놓은 변수이다. 이는 단순히 0,1로 직접 꽂아줘도 좋지만 상황이 어떻게 변할지 모르기에  특정 장소에서 중력값을 건드릴 수 있기에 혹시몰라 따로 선언했다.

 

모든 변수를 선언한 후 Start쪽에서 리지드바디의 gravityScale을 gravityStore에 저장해주었다.

이후에 Ladder.cs에서 캐릭터 값을 불러와서  만일 사다리 오브젝트가 캐릭터와 겹쳐서 onTrigger된다면 플레이어를 움직이는 movementController로 가서 onLadder값을 true로 만들어주고

 

onLadder = true가 되면

다음 update함수에서부터 if(onLadder)가 참이되어 바디의 중력값을 0으로 만든다.

그리고 getAxisRaw에 대한 설명인데, 일단 아는 정도를 말해두자면

GetAxisRaw("Horizontal")의 경우 왼쪽을 누를경우 -1이 리턴되고 오른쪽은 1이 리턴된다.

GetAxisRaw("Vertical")의 경우 아래쪽을 누를경우 -1, 위쪽은 1이 리턴된다.

 

내 경우는 ClimbSpeed를 0.7로 설정했기에 climbDirection = 0.7 * 1 혹은 -1이 들어가고

그 값을 바디의 velocity값 중 수직인 상하값 y에만 대입해 위를 누를경우 0.7이니 위로 올라가고

아래를 누를경우 -0.7이니 밑으로 내려가게 된다.

 

그리고 만일 캐릭터가 사다리와 더이상 겹치지 않을경우 Ladder.cs에서 onTriggerExit2D가 실행되고

Player.onLadder = false가 되어  gravityStore에 저장된 값이 다시 바디의 중력값으로 돌아가게 된다.

 

 

영상을 보면 캐릭터가 사다리에 살짝 겹쳐있는데 그 때 오른쪽에 onLadder값이 체크되고 RigidBody2D에서 gravityScale이 0으로 변하게 되는걸 볼 수 있다. 그리고 다시 떨어지면 1로 복구된다.

완성된 코드다. 여기에 오르고 내리는 애니메이션만 추가하면 된다.

 

기존 climb코드와 바뀐코드의 차이점은 

기존 코드에선 transform.position에 값을 더해준 반면

이번엔 rigidBody에 velocity쪽에 값을 더해주었다.

 

코드를 바꾼이유는 완성된 짤과 같이 사다리가 땅에서 떨어져있어 점프해서 타게되면 따로 위로 이동하는 값을 넣어주지 않아도 자동으로 위로 올라가는 경우도 있었고 어떠한 경우에 의해서 갑자기 아래로 값이 확 떨어져서 추락하는 경우가 있었다. 그래서 바디에 값을 주어보니 저렇게 매끄럽다.