-
[TIL] 유니티로 개인과제 1TIL 2024. 5. 13. 22:44
개인과제로 zep 같은 게임을 유니티로 만들고 있다.
기능을 구현하면서 사용한 유니티 기능가 겪었던 문제들을 정리해봤다.
InputSystem 을 이용하여 대시 만들기
더보기만든거에 별 이유는 없고
무료로 다운 받은 캐릭터 스프라이트에 걷기와 달리기가 있길래 한번 구현해봤다.
// TopDownController.cs public class TopDownController : MonoBehaviour { public event Action<Vector2> OnMoveEvent; public event Action<Vector2> OnLookEvent; public event Action<bool> OnDashEvent; public void CallMoveEvent(Vector2 direaction) { OnMoveEvent?.Invoke(direaction); } public void CallLookEvent(Vector2 direaction) { OnLookEvent?.Invoke(direaction); } public void CallDashEvent(bool push) { OnDashEvent?.Invoke(push); } }
강의에서 봤던 구조와 유사하게 짰다.
추가된 함수는 CallDashEvent() 눌렀는지 아닌지 확인 하기 위해 bool형을 매개변수로 받는다.
//TopDownMovement.cs private CharacterStatHandler characterStatHandler; private float speed = 3f; private void FixedUpdate() { if(Time.timeScale ==1) rb.velocity = moveDireaction * speed; } private void Start() { controller.OnMoveEvent += Move; controller.OnDashEvent += Dash; } private void Dash(bool push) { if(push)//대시 키를 누르고 있다면 { speed = characterStatHandler.characterInfo.runSpeed; } else { speed = characterStatHandler.characterInfo.moveSpeed; } } private void Move(Vector2 direaction) { moveDireaction=direaction; }
Dash는 대시 키(LeftShift)를 눌렀을 때와 손가락을 뗄 때 한번 씩 호출된다.
따라서 누르고 있을 때 (true)일 때는 속도를 높여주고
뗄 때 (false)일 때는 원래 속도로 돌아간다.
참고로 runSpeed와 moveSpeed는 캐릭터 정보에 미리 정의해 두었다.
ChenamchineCamera를 사용하여 플레이어 따라가기
더보기필수 구현 기능 중 하나로 플레이어 따라가는게 있었다.
보자마자 그냥 바로 시네머신 써야지~ 해서 그냥 썼다...... (코드랑 이것중 뭐가 더 좋은지는 모르겠다)
프로젝트에 ChenamchineCamera 적용법
Window - PackageManager - UnityRegistry - Cinemachine
원래 있던 MainCamera에 AddComponenet로 CinemachineBrain을 달아준다.
그리고 Hierarchy 창에 마우스 우클릭으로 VirtualCamera를 생성한다.
이러면 CinemachineVirtualCamera 라는 컴포넌트를 가진 오브젝트가 생성되고
저기에 Follow에 따라다닐 캐릭터를 끌어서 넣기만하면 잘 따라다닌다.
https://docs.unity3d.com/Packages/com.unity.cinemachine@2.1/api/Cinemachine.html
TextMeshPro 폰트 한글로 바꾸기
더보기평소에 unity를 거의 2018? 2020? 버전을 썼었는데 팀 프로젝트를 위해 버전을 2022로 올리니깐 친애하던 Text가 Legacy로 가버렸다.
원래도 문제가 많은 친구니 그냥 보내주기로 하지만 기본폰트로도 한글이 적히는 기존의 Text와는 다르게 한글이 안된다.
그래서 기존의 폰트를 TMP font로 바꿔줘야 한다.
Window - TextMeshPro - FontAssetCreator
사용할 폰트를 넣고
CharacterSequence에
32-126,44032-55203,12593-12643,8200-9900
를 입력한다.
만약 CharacterSequence가 안뜬다면 CharacterSet이 CustomRange가 아닌지 확인해야 한다.
버튼이 방향키로 입력되는 현상
더보기버튼이 클릭된 채로 방향키를 움직이면 다른버튼이 눌리고 닫히는 이상한 문제가 있었다.
애꿎은 버튼만 계속 봤는데 사실 원인은 EventSystem에 있었다.
EventSystem은 Canvs를 생성하면 자동으로 만들어지고, 반대로 실수로 지워버리면 잘 작동이 안되니 조심해야한다.
체크한 부분에서 Move를 none으로 바꿔주니 현상이 없어졌다.
이게 정확한 해결법인지는 아직 잘 모르겠다.
AnimatorOverrideController
더보기예전에 강의해서 언급만하고 넘어간 기능.
이번에 플레이어의 캐릭터를 바꾸는 기능을 넣어야 했기때문에 그거에 맞게 애니메이션을 또 따로 다 만들기보다는 이 기능을 써보기로 했다.
캐릭터마다 애니메이션은 다르지만 애니메이터의 구조가 똑같을 경우
또 다시 파라미터 만들고 화살표 연결할 필요 없이 기반이 될 애니메이터를 넣고 해당하는 애니메이션을 넣으면 적용할 수 있다.
이렇게 만든 Animator Override는 일반적인 Animator처럼 쓸 수도 있고
public List<AnimatorOverrideController> animators; public void ChangeAnimator(int num) { animator.runtimeAnimatorController = animators[num]; }
나는 이렇게 리스트로 받아서 캐릭터가 바뀔 때 마다 animator를 변경해 주었다.
https://docs.unity3d.com/kr/2019.4/Manual/AnimatorOverrideController.html
중복된 코드 정리
더보기생각의 흐름대로 코드를 짜다보면 변수랑 함수명도 꼬이고 비슷한 코드를 여러번 함수에 적고있는 나를 발견할 수 있다.
몇가지 코드를 정리했다.
public void ClickCharacterSelect() { bool active; if (nameInputPanel.activeSelf) { active = characterSelect.activeSelf; characterSelect.SetActive(!active); } else { active = miniCharacterSelect.activeSelf; miniCharacterSelect.SetActive(!active); } } public void ClickChangeName() { if(Time.timeScale==1) { Time.timeScale = 0; } bool active; active = miniNameChange.activeSelf; miniNameChange.SetActive(!active); }
둘 다 버튼을 누른다고 Click을 붙여서 함수를 만들었다. 그런데 짜면서 생각해보니 둘다 버튼을 클릭해서
하나의 오브젝트를 활성화하고 끄는 함수였다.
using UnityEngine.EventSystems; public void ButtonActive() { Time.timeScale = 0;//버튼 활성화 중에는 캐릭터가 멈춰야함 //클릭한 버튼의 오브젝트 정보를 받아온다. GameObject obj = EventSystem.current.currentSelectedGameObject.transform.GetChild(0).gameObject; bool active = obj.activeSelf; if (lastActiveObj!=null) //버튼이 켜져있는 도중 다른 버튼도 켜저 겹치는 것을 방지 { lastActiveObj.SetActive(false); } obj.SetActive(!active); //현재 상태와 반대로 껐다 키기 Time.timeScale = nameInputPanel.activeSelf ? 1 : 0; if (!active == false) Time.timeScale = 1; lastActiveObj = obj; }
두 함수를 합쳐서 Button Active로 만들었다.
using UnityEngine.EventSystems;
EventSystem.current.currentSelectedGameObject : 클릭한 버튼의 오브젝트 정보를 받아온다.
public void ChangeName() { if(nameInputPanel.activeSelf) { CheckNameCorrect(nameInputPanel.activeSelf? nameText: miniNameText); } if (nameText.text.Length <=2) { if(runningCorutine!=null) //마지막에 입력된 기준으로 1초를 세기위해 기존에 작동하던 코루틴 멈춤 StopCoroutine(runningCorutine); warningText.enabled = true; warningText.text ="이름이 너무 짧습니다."; runningCorutine= StartCoroutine(TextClose(warningText)); //1초 뒤에 꺼짐 } else { if(nameInputPanel.activeSelf) { characterStatHandler.characterInfo.name = nameText.text; nameInputPanel.SetActive(false); Time.timeScale = 1; } else characterStatHandler.characterInfo.name = miniNameText.text; characterStatHandler.UpdateStatus(); } }
얘는 플레이어의 이름을 변경하는 함수였다.
처음에는 문제가 없었지만 인게임안에서도 닉네임을 변경할 수 있게 별도의 ui를 만들어주면서 똑같은 기능을 가진 함수를 2개만들어야 하나 고민하다가 재활용할 수 없을까? 하고 변경해봤다.
void CheckNameCorrect(TMP_Text inputText,GameObject obj) { if (inputText.text.Length <= 2) { if (runningCorutine != null) //마지막에 입력된 기준으로 1초를 세기위해 기존에 작동하던 코루틴 멈춤 StopCoroutine(runningCorutine); warningText.enabled = true; warningText.text = "이름이 너무 짧습니다."; runningCorutine = StartCoroutine(TextClose(warningText)); //1초 뒤에 꺼짐 } else { characterStatHandler.characterInfo.name = inputText.text; obj.SetActive(false); characterStatHandler.UpdateStatus(); Time.timeScale = 1; } } public void ChangeName() { GameObject obj = EventSystem.current.currentSelectedGameObject.transform.parent.gameObject; CheckNameCorrect(nameInputPanel.activeSelf? nameText: miniNameText, obj); }
함수를 두개로 분리하고 위에썼던 EventSystem.current.currentSelectedGameObject을 사용해서 오브젝트 정보를 전달해줘서
앞으로도 같은 기능을 가진 ui가 여러개 생긴다 해도 문제 없게 바꿔주었다.
'TIL' 카테고리의 다른 글
[TIL] 객체지향 코드 설계 1 (0) 2024.05.16 [TIL] 유니티 개인과제 2 (0) 2024.05.14 [TIL] Unity 3 + 알고리즘 문제 (0) 2024.05.10 [TIL] Unity 강의 2 (0) 2024.05.09 [TIL] Unity 강의 1 (0) 2024.05.08