ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스파르타 3D 숙련주차 개인과제
    스파르타 게임 개발 2024. 6. 12. 22:05

     

    Alt F4 같은 게임을 만들라고 한다.

     

    먼저 플레이어의 움직임을 하기 전에 맵을 만들어야 해서 유튜브에 나온 터레인 좀 끄적여봤다. 

    생각보다 쉽지 않았다. 그래서 대충 하고 끝냈다. 나에겐 시간이 얼마 없었다. 

     

    그리고 플레이어 오브젝트를 만들고 움직임을 구현 했다. 플레이어는 이동과 점프를 할 수 있다. 

     

    3D 강의에서 인풋시스템에 Invoke Unity를 사용해서 움직임을 구현 하였으므로 그 방식을 사용 했다. 

     

    public void OnMoveInput(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Performed)
        {
            CharacterManager.Instance.Player.inputDirectMove = context.ReadValue<Vector2>();
        }
        else if (context.phase == InputActionPhase.Canceled)
        {
            CharacterManager.Instance.Player.inputDirectMove = Vector2.zero;
        }
        CharacterManager.Instance.Player.CalCulDirecMove(ref CharacterManager.Instance.Player.inputDirectMove, ref CharacterManager.Instance.Player.playerDirectMove);
    }

     

    일단 이런 식으로 인풋이 입력 됐을 때 싱글턴으로 만들어둔 클래스의 값이 바뀌게 해놓았다. 

     

    그리고 if문 밑에 코드가 하나 있는 걸 볼 수 있는데, 3D는 2D와 달리 wasd로 움직임을 구현 하려면 z축을 이용 해야 한다. 

    그래서 인풋으로 x,y 의 값을 받아오고 그걸로 z축과 y축을 계산 해서 움직임을 구현 해야 하는데 그걸 계산 하게 하는 함수다. 

     

    처음에 매개변수에 ref를 사용하지 않고 그냥 넣었는데, 나는 싱글턴이라 값이 바로 바뀔 줄 알았는데 값은 바뀌지 않았다. 그 이유는 Vector는 어쨋든 Struct로써 값형인데, 이 값형들은 매개변수로 참조가 될 때 싱글턴이여도 값을 복사해서 넘기기 때문에 필드의 값은 바뀌지 않는 다고 한다. 

     

    그래서 ref를 사용 하여 함수를 만들었다. 

     

    난 이 때 함수를 만들 때 ref를 사용해서 만들면 성능적인 문제가 있지 않을까 생각 했는데, 아니라고 한다. 오히려 성능이 좋아질 수가 있다고 한다. 

     

    주소를 계산 하는 건 더 느리다라고 생각을 했었는데, 오히려 주소를 박아두면 그 주소만 계속 참조를 한다고 하셨나, 어쨋든 성능적인 문제는 상관이 없고, 오히려 더 좋아질 수가 있다고 하셨다. 

     

    public void CalCulDirecMove(ref Vector2 vector2, ref Vector3 vector3) 
    {
        vector3 = transform.forward * vector2.y + transform.right * vector2.x;
    }

     

    CalCulDirecMove의 함수. 매개변수로 받은 vector3의 값을 바꾸는 함수이다. 

    CharacterManager.Instance.Player에 만들어둔 필드의 변수를 바꾸게 만들고 움직임을 처리하는 곳에서 이 변수를 참조하게 만들었다.

     

    처음에 ref를 안 써서 튜터님께 함수 안 된다고 물어보러 가니까 왜 이런 식으로 만들었냐고 물으시길래 객체지향적? 이렇게 만들면 언젠간 다른 데서도 쓸 수 있지 않냐고 물으니까 나보고 챌린저냐고 물어보셨다. 기분이 좋았다. 난 스댕이다.(스텐다드)

     

        private void FixedUpdate()
        {
                ApplyMove(playerDirectMove);
        }

    요런 식으로, 이 FixedUpdate가 사용 된 곳은 PlayerController라는 클래스로 Player라는 클래스를 상속 받았다. 

    그래서 변수를 바로 사용 할 수 있는 모습이고 Player는 싱글턴으로 되어 있는 상태인데, Gpt 선생님께 여쭤보니 싱글턴인 클래스를 상속 받아도 상관은 없다고 했는데 여러 객체가 생성 되지 않게 주의를 해야 한다고 한다. 

     

    그래서 앞으로 계속 코드를 작성 하는 거에 대해서 고민을 많이 했지만, 어쨋든 이번 과제에서는 기능을 많이 구현 하지 못 하였다. 

     

    그리고 카메라의 시점변경(마우스 회전 할 때 화면 회전 되게 하는 거)나 점프는 강의 내용에서 썻던 방법이고 코드를 작성 한 방식은 움직임과 비슷하다. 

     

    그 다음은 스텟인데 나는 스테미나와 체력 두 가지만 만들었다.

     

    오른 쪽 밑을 보면 스텟 UI이긴 한데 ㅋㅋ 

     

    아무튼 움직이면 스테미나가 닳고, 가만히 있으면 회복 되게 하고 싶었다. 

     

    이 때 나는 싱글턴에 만들어둔 Vector3 변수를 활용 하고자 했다. 인풋시스템을 사용한 움직임을 구현 할 때는 배운대로 한다면 변수의 값을 계속 참조해서 움직임을 하니 이것을 활용해서 가만히 있을 때를 적용 시켰다. 

     

    Vector3의 값이 0,0,0이면 가만히 있는 것이니

     

    if(CharacterManager.Instance.Player.inputDirectMove == noMove) 

    이런 식으로 if조건문을 사용해서 스테미나가 닳게 했다. (noMove는 Vector.zero로 선언 되어 있는 변수다)

     

    그리고 플레이어는 점프도 할 수 있는데 점프 할 때는 스테미나가 더 크게 떨어지게 하고 싶었다. 그래서 플레이어 싱글턴에 변수를 하나 만들고 그게 점프를 작동 해서 true가 되면 스테미나가 감소 하게 했다. 그런데 공중에서 계속 스페이스바를 누를 경우에 스테미나가 계속 닳아서 아래와 같이 코드를 작성 했다.

     

    if (CharacterManager.Instance.Player.jumping) // 점프 할 때 스테미나 감소
    {
        CharacterManager.Instance.Player.conditionController.stamina.Subtract(5);
        CharacterManager.Instance.Player.jumping = false; // 공중에서 스페이스바 눌러도 체력감소 안 되게 적용
    }

     

    bool형 변수를 저렇게 사용 하면 좋지 않다고 했지만,(의미와 같게 하는 게 좋다. Jump == true면 점프를 한 상황이여야 한다.) 굳이 변수를 하나 더 만드는 것보단 주석을 하나 달아서 코드를 사용 하는 게 좋다고 판단 했다. 

     

    그리고 점프를 하면 스테미나가 5 닳게 했는데 5이하로 떨어져도 점프를 하길래 이 부분을 보완 해주었다. 

     

    스테미나가 5이상이여야 점프를 하게끔, 그거는 점프를 실행 하는 함수에서 if조건문을 하나 더 달아서 해결했다. 

    스테미나의 스텟이 5이상이면 코드가 실행 되게끔. 

     

    그리고 개인과제 한 게 이게 끝이긴 한데, 한 개가 더 있다. 

     

    그건 점프대인데, 과제 내용에서 점프대를 만들어서 점프대를 사용 하면 캐릭터가 높게 점프를 하는 것인데, 나는 이걸 Collider를 활용 해서 점프대와 닿을 경우에 점프의 파워 변수가 크게 증가 하게 하는 걸로 구현을 하고 싶었다. 

     

    처음에 OnCollisionEnter과 OnCollisionExit를 사용 해서 점프대와 닿을 경우에 점프파워가 증가하고, 점프대와 떨어졌을 경우에 다시 점프파워가 원래대로 돌아가게 했는데(시작 점프파워를 저장 할 변수 1개, 적용할 변수 1개 2개 사용 중이였다) 문제가 발생 했다. 무슨 문제였냐면 나는 점프대에 Exit가 호출이 될 때 애니메이션도 추가를 했었다. (점프대가 올랐다가 내려가는 애니메이션)

     

    그런데 이 애니메이션이 닿자마자 작동이 되는 것이다. 나는 점프대에서 벗어날 때 작동 시키고 싶었다. 

     

    왜 그런가 생각을 해도 떠올리지 않아서 튜터님께 물어봤다. 그 이유는 Rigidbody를 이용한 움직임을 구현 할 때 발생 하는 흔한 문제라고 했는데, 두 물체가 충돌을 할 때, 닿게 될 때 살짝 밀리는 경우가 생긴다. 그로 인해 두 물체가 닿으면 닿았다가 바로 밀리게 되는데 그로 인해서 Exit가 바로 실행이 되는 것이다. 

    그래서 어떻게 하나 생각을 하다가 점프대에 자식 오브젝트를 하나 만들어서 위치를 살짝 밑으로 내리게 하고 부모 오브젝트에는 isTrigger를 적용 시켜서 두 개의 레이어를 다르게 해 기능을 구현 했다. 

     

    이렇게 해서 내 3D 개인과제가 끝이 났는데 정말 기능을 구현 많이 못 했다. 

     

    나 같은 경우 20일 정도 캠프를 빠지게 돼서 하 핑계 대지 말자. 뭐 복사붙여넣기 하면 필수구현 하라고 하는 것을 다 할 순 있었겠지만, 복사붙여넣기 할빠에는 안 한다 라는 마인드로 안 했다. 

     

    ==튜터님의 피드백

    나름 강의 내용대로 구현하실려는 노력이 보였습니다. 움직이지 않을 때 스테미나가 오르게 한다던지 체력 감소를 안하게 하는 기믹이 있다던지 등등 하지만 늦게 제출하신거에 비해 구현되어 있는 부분이 너무 없는게 좀 아쉬웠습니다. 진행하시면서 어려운 부분이 있으면 언제든 튜터님들을 찾아주세요!

    복사붙여넣기 할 걸 그랬나..욕 머겄다 ㅜ ==

     

    하다보니까 그래도 재밌고, 떠오른 게 있어서 만든 거는 나중에 다시 업그레이드 할 예정이다. 맵을 돌아다니면서 몬스터가 계속 나오고 총 쏘면서 몬스터를 잡고 레벨업 하고 등등등?? 아이디어가 샘솟는다. 하지만 지금은 공부 할 시간..,

    결과물.. 초라하당

     

    사용한 스크립트

     

     

    ================

    무료에셋 자주 공유 해주시는 캠프 동기분이 계신다. 마침 터레인 에셋이여서 갖고 와서 적용을 하니 제법 그럴싸한 지형이 됐다!

    ㄷㄷㄷㄷㄷㄷㄷ 남들 눈엔 허접해 보일진 몰라도 내 눈엔 이쁘구먼 허허

Designed by Tistory.