빌드 시 오류 발생

JDK와 Gradle

JDK not Found

안드로이드로 스위칭 후 빌드 시 아래의 오류가 보인다면 JDK문제일 것이다.

다른 버전 설치하면서 헤메기 전에 (나는 헤맸지만) 우선 공식 문서를 살펴보도록 하자.

위 사진의 첫 번째 오류에서 바로 알 수 있게 해놨으면 좋겠지만.. 공식 문서를 봐야지 알 수 있는 상황이다.

3번째 표를 보면 나의 경우 Unity 2022.3.2f1이니 JDK version은 11을 다운받으면 되는 것이다.

https://docs.unity3d.com/2023.3/Documentation/Manual/android-sdksetup.html

 

Unity - Manual: Android environment setup

Getting started with Android Android environment setup To create a Unity application for Android, you first need to set up your Unity project to support Android. To support Android, a Unity project requires the following dependencies: The Android Build Sup

docs.unity3d.com

그렇다면 JDK 11은 어디서 다운 받느냐 오라클에서 다운 받을 수 있다. (회원가입 필수)

회원가입 후 다운받도록 하자.

https://www.oracle.com/kr/java/technologies/javase/jdk11-archive-downloads.html

 

Java Archive Downloads - Java SE 11 | Oracle 대한민국

WARNING: These older versions of the JRE and JDK are provided to help developers debug issues in older systems. They are not updated with the latest security patches and are not recommended for use in production. For production use Oracle recommends downlo

www.oracle.com

 

설치하고 나서 체크 해제 후 'Edit - Preferences - External Tools - JDK - Browse - JDK 폴더'를 적용해주자

 

여차저차 했을 때 Gradle~~ 오류가 난다면?

JAVA의 환경변수 설정이 안 되어 있을 수 있다.

아래에 좋은 글이 있으니 따라서 적용해보자.

https://devparklibrary.tistory.com/28

 

[Unity] Android Resolver 사용 시 JAVA_HOME 설정 오류 해결 방법

Gradle failed to fetch dependencies. ... ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 오류 해결 방법. 유니티를 2019 이상 버전 사용 시 이전 버전의 유니티와는 다르게 JDK를 허브를 통해서

devparklibrary.tistory.com

 

 

SDK와 NDK

SDK not found

해당 폴더에 SDK가 없다고 한다. 바로 설치해주자.

SDK를 설치하기 위해 Android Studio를 사용한다.

https://developer.android.com/studio

 

Download Android Studio & App Tools - Android Developers

Android Studio provides app builders with an integrated development environment (IDE) optimized for Android apps. Download Android Studio today.

developer.android.com

설치가 다 됐으면 ... 버튼을 눌러 SDK Managager를 켜준다.

이제 다시 공식 문서를 볼 때다.

SDK Build tools는 32.0.0이고 SDK Command-line tools version은 6이다. (Unity 2022.3.2f1)

NDK는 r23b(23.1.7779620)을 설치해준다.

 

우측 하단의 Show Package Details를 체크해야 버전을 선택할 수 있다.

이 때 중요한 점은 '컴퓨터를 재시작해야한다'는 점이다. (이것 때문에 고생했음)

 

이러면 잘 될 것이다. (잘 되시길 바랍니다.)

진행한 것들

플레이어 더블 점프

JumpCountHandler에서 JumpCount를 관리하고

public class JumpCountHandler
{
    public JumpCountHandler(int maxJumpCount)
    {
        SetJumpCount(maxJumpCount);
    }

    public int JumpCount { get; private set; }

    public void DecreaseJumpCount()
    {
        JumpCount--;
    }

    public void SetJumpCount(int count)
    {
        JumpCount = count;
    }
}

PlayerJumpState에서 Jump 상태 변경을 관리한다.

using UnityEngine;

public class PlayerJumpState : PlayerAirState
{
    private void Jump()
    {
        if (jumpCountSetter.JumpCount > 0)
        {
            animationController.ReStartIfAnimationIsPlaying(animationsData.JumpParameterHash);

            jumpCountSetter.DecreaseJumpCount();
            Vector3 velocity = rigid.velocity;
            velocity.y = playerController.StatHandler.Data.JumpForce;
            rigid.velocity = velocity;
        }
    }
}

마지막으로 자연스러운 더블점프 동작을 위해 현재 점프 상태이고 또 점프가 들어오면 처음부터 애니메이션을 다시 재생하도록 했다.

using UnityEngine;

public class AnimationController : MonoBehaviour
{
    [field: SerializeField] public PlayerAnimationsData AnimationData { get; private set; }
    private Animator _animator;

    public void ReStartIfAnimationIsPlaying(int animationParameterHash, int layerIndex = 0)
    {
        if (_animator.GetCurrentAnimatorStateInfo(layerIndex).shortNameHash.Equals(animationParameterHash))
            _animator.Play(animationParameterHash);
    }
}

 

플레이어 구르기

구르기에서는 무적, 쿨타임, 구르기 시 움직임 제한 기능이 필요했다.

 

먼저 PlayerRollState에서 구르기 애니메이션과 구르기 끝났는지를 체크하고

public class PlayerRollState : PlayerStateBase
{
    private void CheckRollingEnded()
    {
        if (animationController.CheckAnimationEnded(animationsData.RollParameterHash))
        {
            stateMachine.RollDataHandler.SetIsRolling(false);

            if (stateMachine.IsGrounded)
                stateMachine.ChangeState(stateMachine.MovementState);
            else
                stateMachine.ChangeState(stateMachine.FallState);
        }
    }
}

RollDataHandler에서 구르기 수행 시 무적과 쿨타임을 계산한다.

using UnityEngine;

public class RollDataHandler
{
    public bool CanRoll { get; private set; }
    public bool IsInvincible { get; private set; }
    public bool IsRolling { get; private set; }
    private float _rollingCoolTime;
    private float _currentRollingElapsedTime;
    private float _invincibleTime;

    public RollDataHandler(float rollingCoolTime, float invincibleTime)
    {
        SetRollingCoolTime(rollingCoolTime);
        _currentRollingElapsedTime = rollingCoolTime;
        _invincibleTime = invincibleTime;
        CanRoll = true;
    }

    public void SetRollingCoolTime(float rollingCoolTime)
    {
        _rollingCoolTime = rollingCoolTime;
    }

    public void ResetCurrentRollingElapsedTime()
    {
        CanRoll = false;
        _currentRollingElapsedTime = 0f;
        IsInvincible = true;
    }

    public void CalculateCoolTime()
    {
        if (_currentRollingElapsedTime >= _rollingCoolTime)
        {
            CanRoll = true;
            return;
        }

        _currentRollingElapsedTime += Time.deltaTime;
        _currentRollingElapsedTime = 
            _currentRollingElapsedTime > _rollingCoolTime ? 
            _rollingCoolTime : _currentRollingElapsedTime;

        CalculateInvincible();
    }

    public void SetIsRolling(bool isRolling)
    {
        IsRolling = isRolling;
    }

    private void CalculateInvincible()
    {
        if (_currentRollingElapsedTime < _invincibleTime)
            return;

        IsInvincible = false;
    }
}

 

 

오늘의 이슈 / 내일 할 것

더블 점프 구현을 위한 JumpCount 이슈

문제점 : JumpCount를 IsGronded일 때 JumpCountMax로 초기화를 해줬으나 Debug.Log를 찍어보면 초기화가 안 되는 이슈, PlayerJumpState에서의 문제인 줄 알고 PlayerAirState에 옮겼으나 결과는 같았음
원인 : 호출 스택을 살펴보니 PlayerFallState 부모의 PlayerAirState에서만 초기화되는 경우였음 (PlayerJumpState JumpCount != PlayerFallState JumpCount)
해결 : 공통적으로 참조하는 StateMachine에서 JumpCount를 관리하기로 함
** 또한 IsGrounded도 같은 이슈여서 StateMachine에서 관리하는 것으로 처리

 

플레이어가 날라가는 이슈

문제점 : 플레이어 날아가는 이슈

원인 : 점프 값에도 Speed가 곱해져 날라가던 것이었다.

해결 : 이동에만 Speed를 곱해주니 해결

 

내일 할 것 : 구르기 시 이동 입력 받기, 빌드

 

 

오늘의 회고

 오늘은 캐릭터 더블 점프와 구르기를 구현했다. 더블 점프에 상태머신이 겹쳐서 참조 변수를 각각 따로 참조하게 되는 실수를 저질렀는데 이후에 호출 스택을 보고 처리하길 잘했던 것 같다. 그리고 구르기 시 Input을 받지 않는 작업은 InputSystem의 Interaction Hold 부분을 좀 더 공부해보고 적용해봐야겠다. 내일도 파이팅!

진행한 것들

캐릭터 상태머신

아래 글에서 진행한대로 플레이어 애니메이션과 관련된 부분은 상태머신으로 관리하기로 했다. 상태머신은 내가 의도한대로 플레이어가 동작 하도록 하기 위해 적용했다.

https://jcdevelop98.tistory.com/349

 

내일배움캠프 40일차 TIL - FSM

오늘의 학습 키워드 Finite State Machine 공부한 내용 Finite State Machine 한 번에 한 개의 상태만 가질 수 있고 다른 상태로 전이가 가능한 모델을 FSM(유한 상태 머신)이라고 부른다. 게임에서는 애니메

jcdevelop98.tistory.com

 

모든 State는 IState를 상속받고 

public interface IState
{
    void Enter();
    void Exit();
    void UpdateState();
    void PhysicsUpdateState();
    void OnDead();
}

 

StateMachine에서 현재 IState인  _currentState를 ChangeState(IState newState)로 바꿔준다.

public class StateMachine
{
    private IState _currentState;

    public PlayerController PlayerController { get; private set; }

    public PlayerMoveState MovementState { get; private set; }
    public PlayerJumpState JumpState { get; private set; }
    
    public StateMachine(PlayerController playerController)
    {
        PlayerController = playerController;

        MovementState = new PlayerMoveState(this);
    }

    public void Init()
    {
        ChangeState(MovementState);
    }


    public void ChangeState(IState newState)
    {
        _currentState?.Exit();
        _currentState = newState;
        _currentState?.Enter();
    }

    public void Update()
    {
        _currentState.UpdateState();
    }

    public void PhysicsUpdate()
    {
        _currentState.PhysicsUpdateState();
    }
}

 

각 State는 애니메이션을 동작시키는데 예를 들어 PlayerMoveState가 있으면 Enter에서 플레이어의 애니메이션 bool 파라미터를 true로 만들고 Exit에서 false로 만들게끔 했다.

public class PlayerMoveState : PlayerStateBase
{
    public PlayerMoveState(StateMachine stateMachine) : base(stateMachine)
    {
        
    }

    public override void Enter()
    {
        playerController.Animator.SetBool(animationsData.MoveParameterHash, true);
    }

    public override void UpdateState()
    {
        base.UpdateState();
        playerController.Animator.SetFloat(animationsData.SpeedRatioParameterHash, speedRatio);
    }

    public override void Exit()
    {
        playerController.Animator.SetBool(animationsData.MoveParameterHash, false);
    }

    public override void OnDead()
    {
        base.OnDead();
    }
}

 

애니메이션은 블렌드 트리를 사용하였다.

 

 

오늘의 이슈 / 내일 할 것

이슈 : Mixamo에서 가져온 Animation에서 humanoid로 변경 후 Import Message Warning이 뜸

 

시도한 것 : 'Take001'이라는 애니메이션이 문제여서 Animation 탭의 Clips에서 제거함, 그러나 왜인지 Source Take 부분에는 남아 있고 Import Message Warning도 존재함

 

내일 할 것 : 캐릭터 점프, 슬라이딩

 

 

 

오늘의 회고

 오늘은 캐릭터 점프와 슬라이딩 쪽을 구현할 예정이었으나 캐릭터 상태머신과 애니메이션이 더 필요하다고 하여 상태머신 쪽을 먼저 구현하게 되었다. Input을 받아와 이동에 적용하는데 구조를 변경하는 작업이 동반되어서 시간이 좀 걸렸던 것 같다. 리팩토링은 할 땐 귀찮은데 하고 나면 괜히 뿌듯한 작업인 것 같다. 내일도 파이팅!

진행한 것들

캐릭터 이동

캐릭터 이동은 InputController의 MoveAction의 콜백으로 PlayerMovement의 SetDirection을 호출하고 여기서 _direction을 초기화해준다. 이후에 Update에서 프레임마다 호출되는UpdateSpeed로 스피드를 계산해주고 FixedUpdate에서 Move를 호출하여 Rigidbody의 velocity를 세팅하여 적용된다.

- 중력이 필요하기 때문에 Transform으로의 이동 대신 Rigidbody 이동을 선택했다.

- Time.deltaTime이 필요한 계산은 Update로 rigidbody를 사용하는 Move는 FixedUpdate에서 호출하게 했다.

public class InputController : MonoBehaviour
{
    public event Action<Vector2> MoveAction;

    public void OnMove(InputAction.CallbackContext context)
    {
        if (context.canceled)
        {
            CallMoveAction(Vector2.zero);
            return;
        }

        Vector2 inputVec = context.ReadValue<Vector2>();
        // 전달
        CallMoveAction(inputVec);
    }

    private void CallMoveAction(Vector2 inputVec)
    {
        MoveAction?.Invoke(inputVec);
    }
}
[RequireComponent(typeof(Rigidbody))]
public class PlayerMovement : MonoBehaviour
{
    private void Update()
    {
        UpdateSpeed();
        Look();
    }

    private void FixedUpdate()
    {
        Move();
    }

    public void SetDirection(Vector2 direction)
    {
        _direction = direction;
    }

    private void UpdateSpeed()
    {
        _speed = _speedCalculator.CalculateSpeed(
            _controller.StatHandler.Data.SpeedMin,
            _controller.StatHandler.Data.SpeedMax,
            _direction == Vector2.zero);
    }

    private void Move()
    {
        _rigid.velocity = new Vector3(_direction.x, _rigid.velocity.y, 0f) * _speed;
    }
}

 

 

캐릭터 회전

구현해야할 것 : 플레이어가 회전할 때 정면을 바라보게끔 구현 (왼쪽에서 오른쪽으로 돌 때는 반시계방향으로, 오른쪽에서 왼쪽으로 돌 때는 시계방향으로)

문제점 : QuaternionLookRotation을 이용해 회전을 구현하면 제한을 걸기가 힘듬. 뒤를 바라보는 경우가 생기거나 문워크를 하는 경우가 생김

private void Look()
    {
        if (_direction == Vector2.zero)
        {
            transform.rotation = Quaternion.LookRotation(_preDirection);
            return;
        }

        _preDirection = (Vector3.right * _direction.x).normalized;

        Quaternion rotation = Quaternion.Slerp(
            transform.rotation, 
            Quaternion.LookRotation(_preDirection), 
            turningSpeed * Time.deltaTime);

        _rigid.velocity = new Vector3(_direction.x, _rigid.velocity.y, 0f) * speed;
        transform.rotation = rotation;
    }

 

해결 방안 : 이해하기 쉬운 Euler각을 이용하여 각도에 제한을 둠, 여기서 Vector3.SignedAngle()을 이용하여 좌/우측 둘 다 고려, Quaternion.RotateTowards는 더 작은 각도인 쪽으로 도는데 이를 이용한 트릭으로 Circle_Angle에(-90도, 90도) 방향으로 1을 더해주거나 빼줌으로써 정면만 바라보게 했음

public Quaternion CalculateRotation(Quaternion rotation, Vector3 _preDirection)
{
    float targetAngle = Vector3.SignedAngle(Vector3.forward, _preDirection, Vector3.up);

    float rotationY = rotation.eulerAngles.y;

    rotationY = targetAngle < 0 ? rotationY++ : rotationY--;

    if (targetAngle < 0)
        targetAngle += CIRCLE_ANGLE;

    Quaternion startRotation = Quaternion.Euler(new Vector3(rotation.x, rotationY, rotation.z));
    Quaternion targetRotation = Quaternion.Euler(new Vector3(rotation.x, targetAngle, rotation.z));

    Quaternion newRotation = Quaternion.RotateTowards(startRotation, targetRotation, _rotationSpeed);

    return newRotation;
}

 

 

 

오늘의 이슈 / 내일 할 것

내일 할 것 : 캐릭터 점프, 슬라이딩, UI 조이스틱 이동 연결

 

오늘의 회고

 오늘은 캐릭터 이동과 회전을 구현하였다. 이동은 비교적 쉽게 구현하였는데 회전은 신경써야할 게 더 많아서 좀 오래 걸렸던 것 같다. 구조에 대해서도 고민을 했는데 프로토타입이니 일단 구현부터 한 뒤에 리팩토링을 한다고 생각하고 진행해야겠다. 내일도 파이팅!

 

 

참고 : 

https://docs.unity3d.com/ScriptReference/Vector3.SignedAngle.html

 

Unity - Scripting API: Vector3.SignedAngle

The angle returned is the angle of rotation from the first vector to the second, when treating these first two vector inputs as directions. These two vectors also define the plane of rotation, meaning they are parallel to the plane. This means the axis of

docs.unity3d.com

 

진행한 것들

구조 설계(진행중)

이 프로젝트에서는 캐릭터, 플레이어, 적에 대한 필수적인 데이터를 스크립터블 오브젝트 형식의 클래스로 만들기로 했다.

우선 스크립터블 오브젝트에서 캐릭터 데이터를 EntityData와 HealthData로 나누었는데 이는 IEntity에서 공격자의 입장과 타겟의 입장을 나누기 위해 두가지로 나누었다. (필요한 데이터만 전달하기 위해)

 

 

에셋 찾기(진행 중)

UI를 역동적으로 보여주기 위해 DoTween이라는 에셋을 사용하기로 했다.

https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676

 

DOTween (HOTween v2) | 애니메이션 도구 | Unity Asset Store

Use the DOTween (HOTween v2) tool from Demigiant on your next project. Find this & more animation tools on the Unity Asset Store.

assetstore.unity.com

 

오늘의 이슈

 

 

오늘의 회고

 오늘은 프로토 타입을 만들기 위해 UI 스테이지 컨셉을 기획하고 플레이어 데이터를 구상해보았다. 기획한 것들을 UI에 집어넣다보니 조금 UI가 복잡해지는 감이 있지만 일단은 넣고 싶은 것들을 다 넣어놓고 프로토타입에서 테스트를 한 뒤 추가할 것은 추가하고 뺄 건 빼는 방향으로 해볼 생각이다.

 내일은 플레이어 이동을 구현해서 팀원이 만든 맵에 테스트를 해보고 시간이 남으면 조이스틱에 연동까지 할 수 있도록 해야겠다. 내일도 파이팅!

진행한 것들

제목 : 이그라엘

주제 : 로그라이트류 플랫포머 게임

팀 목표 : Android 기기 타겟으로 하여 Google PlayStore에 출시

유니티 버전 : 2022.3.2f1

레퍼런스 : 던전 슬래셔

간단 스토리 : 핵전쟁 이후 세계는 방사능에 오염되었다. 생명공학 연구원 K(가명)는 방사능을 정화하는 나무의 존재를 발견하게 된다. 연구를 거듭하여 방사능을 정화시키자!

 

구조 설계(진행중)

구조 설계에 대해서도 의견을 나눴다.

먼저 필요한 매니저들에 대해 정리를 해보고

 

 

에셋 찾기(진행 중)

에셋은 이번에 무료로 배포한 에셋이 있어서 아포칼립스 분위기에 맞게 파괴된 오브젝트들 위주로 사용하기로 했다.

https://assetstore.unity.com/packages/3d/environments/urban/polygon-battle-royale-low-poly-3d-art-by-synty-128513

 

POLYGON Battle Royale - Low Poly 3D Art by Synty | 3D 도시 | Unity Asset Store

Elevate your workflow with the POLYGON Battle Royale - Low Poly 3D Art by Synty asset from Synty Studios. Find this & other 도시 options on the Unity Asset Store.

assetstore.unity.com

 

스토리 (진행 중)

게임의 배경을 설명하기 위한 스토리도 만들고 있다.

 

오늘의 이슈

 

오늘의 회고

 오늘은 최종 프로젝트 기획을 본격적으로 시작했다. 우리 조는 기획이 개발 전반적으로 영향을 끼치는 것을 알고 있기 때문에 기획에 시간을 충분히 쏟고 시작하기로 했다. 먼저 우리는 출시가 목표이기 때문에 레퍼런스 게임을 잡고 우리만의 컨셉(시스템)을 넣어서 새로운 로그라이크 게임을 만들기로 했다. 그리고 필수적인 기능들이 뭔지 미리 생각해보고 클래스를 만들어보기도 했다.

 내일은 오늘 한 것에 이어서 기획을 더 해볼건데 에셋과 더불어 스테이지 컨셉을 정할 생각이다. 내일도 파이팅!

공부한 내용

프로젝트 마무리

최종 프로젝트 진행 전 팀 프로젝트를 마무리 했다.

각자의 미니게임을 합치는 부분에서 좀 오래 걸렸고 특히나 합칠 때 버그를 잡는 부분에서 시간이 많이 걸렸던 것 같다.

특히나 마지막에는 프로젝트 기한을 맞추다보니 확장성이 부족한 코드들을 작성해서 불편한 기분을 느꼈다.

 

오늘의 회고

 오늘은 최종 프로젝트 전 팀 프로젝트 발표가 있었다. 오전 중에는 발표 영상 만드느랴 버그 잡느랴 정신없이 지나갔고 오후에는 팀 발표물들을 보면서 다른 팀에게서도 배울 점이 많다고 생각이 들었다. 최종 프로젝트에는 기존에 프로젝트를 하면서 아쉬운 점들을 모두 보완하도록 노력해야겠다. 다음 주 최종 프로젝트 화이팅!

공부한 내용

시간증가에 따른 등급 감소

내 게임의 규칙은 빠른 시간 안에 정상에 오르는 것인데 시간이 증가할 수록 등급이 감소해야하는 로직을 구현해야했다.

스크립터블 오브젝트에서 기준을 정하고

현재 점수(시간) - 기준 >= 0 의 조건으로 결과를 도출해낼 수 있었다.

int integerTime = (int)elapsedTime;
string grade = gradeCalculator.CalculateGrade(integerTime, out int gold, out int reverseScore);
public string CalculateGrade(int score, out int gold, out int reverseScore)
{
    string grade = string.Empty;
    gold = 0;
    reverseScore = 0;

    for (int i = 0; i < grades.Length; i++)
    {
        if (score - data.ScoreCriteria[i] <= 0)
        {
            grade = grades[i];
            gold = golds[i];
            reverseScore = data.ScoreCriteria[grades.Length - 1 - i];
            break;
        }
    }

    return grade;
}

 

 

오늘의 회고

 오늘은 내일 프로젝트 제출을 위해 엔딩 씬이든 결과 연결이든 여러가지 작업을 진행했다. 늦은 시간까지 다들 열심히 하니 나도 더 열심히 하게 되는 것 같다. 내일 최소한 버그가 없이 제출하는 것이 목표인데 다들 열심히 해주시니 가능하다고 생각한다. 내일도 파이팅!

오늘의 학습 키워드

Async와 Coroutine

 

공부한 내용

Async와 Coroutine

프로젝트를 진행하면서

캐릭터가 오브젝트에 부딪혔을 때

1. 캐릭터의 조작을 멈추고

2. 일정 시간이 지나고 난 후 풀어주는 로직을 짜기로 했다.

3. 이 때 캐릭터에 다시 충돌이 들어오면 경과 시간을 초기화해주는 조건이 필요했다.

4. 이를 기다리는데 다른 로직이 방해받지 않고 기다렸으면 좋겠다고 생각하고 정보들을 찾아보기로 했다.

 

찾아보니 Unite Copenhagen에서 진행한 자료가 있어서 참고해봤다.

대충 이런 차이점이 있는데 내 경우에서는 MonoBehaviour를 상속받지 않으므로 Async를 사용하기로 했다.

 

다음은 Async를 적용하여 MonoBehaviour를 상속받는 Obstacle 클래스에서 OnCollisionEnter 이벤트가 호출되면 조건을 체크하여 ObstacleCollision의 ApplyCollision을 호출하고 물리적 힘을 준 뒤 캐릭터가 이미 충돌 상태인지 확인하고 처리해주는 것을 구현한 로직이다.

public class Obstacle : MonoBehaviour, IPoolingObject<Obstacle>
{
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.TryGetComponent(out CharacterController controller))
        {
            _obstacleCollision.ApplyCollision(controller, collision.rigidbody, -collision.GetContact(0).normal, mass, waitMilliseconds);
        }
    }
}
public class ObstacleCollision
{
    public async void ApplyCollision(CharacterController controller, Rigidbody oppositeRigid, Vector3 towardTargetVec, float mass, int waitMilliseconds)
    {
        oppositeRigid.AddForce(towardTargetVec * mass, ForceMode.Impulse);

        controller.SetImmovable();

        await Task.Delay(waitMilliseconds);

        controller.SetMovable();
    }
}
public class CharacterController : MonoBehaviour
{
    public void SetMovable()
    {
        if (_collisionStack > 0)
        {
            _collisionStack--;

            if (_collisionStack == 0)
                _canMove = true;
        }
    }

    public void SetImmovable()
    {
        _collisionStack++;

        if (_collisionStack == 1)
            _canMove = false;
    }
}

 

 

오늘의 회고

 오늘은 코루틴과 비동기의 차이점에 대해서 배웠다. 코루틴은 유니티에서 MonoBehaviour를 상속 받을 때 싱글 쓰레드로 동작하는 것이고 Async는 멀티 쓰레드로 웹에 요청을 보내거나 파일 입출력을 할 때 많이 쓰인다는 것을 배우게 되었다.

 내일은 게임의 결과를 보여주는 창과 SFX 관리를 할 생각이다. 내일도 열심히 하자 파이팅!

 

 

참고 : 

https://www.youtube.com/watch?v=7eKi6NKri6I

 

오늘의 학습 키워드

단일 책임 원칙

 

공부한 내용

단일 책임 원칙

MonoBehviour을 상속 받고 충돌을 체크하며 float의 mass 값을 가진 Obstacle이 있고

충돌체에 물리적인 힘을 가하는 ObstacleCollision이 있다.

ObstacleCollision은 Obstacle 클래스의 OnCollisionEnter로부터 필요한 정보(Rigidbody, normal, mass) 값만 받아와서 충돌을 처리한다. -> 역할 구분이 확실해진다.

public class Obstacle : MonoBehaviour
{
    [Header("Collision")]
    [SerializeField] private float mass;
    private ObstacleCollision _obstacleCollision;
    
    private void Awake()
    {
        _obstacleCollision = new ObstacleCollision();
    }
    
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.rigidbody != null)
        {
            _obstacleCollision.ApplyCollision(collision.rigidbody, -collision.GetContact(0).normal, mass);
        }
    }
}
public class ObstacleCollision
{
    public void ApplyCollision(Rigidbody oppositeRigid, Vector3 towardTargetVec, float mass)
    {
        oppositeRigid.AddForce(towardTargetVec * mass, ForceMode.Impulse);
    }
}

 

 

 

오늘의 회고

 오늘은 Solid 원칙 중 단일 책임 원칙을 보고 클래스가 하는 역할에 따라 구분해보았다. Obstacle의 클래스의 다른 부분이 얼마나 수정되든 ObstacleCollision의 클래스는 수정할 필요가 없고 그 반대도 동일하다. 이래서 단일 책임 원칙을 사용하나 싶다.

 내일은 오브젝트 풀링을 이용해 오브젝트들을 세 곳에서 생성하고 플레이어가 경사진 다리를 올라가게 할 것이다. 내일도 열심히 해보자 파이팅!

 

 

참고 : 

https://www.youtube.com/watch?v=Eyr7_l5NMds&list=PLB5_EOMkLx_WjcjrsGUXq9wpTib3NCuqg

 

+ Recent posts