전체 글 (197)

  • 2024.01.24
  • 2024.01.23
  • 2024.01.22
  • 2024.01.19
  • 2024.01.18
  • 2024.01.17
  • 2024.01.16
  • 2024.01.15
  • 2024.01.13
  • 2024.01.12
  • 2024.01.11
  • 2024.01.10
  • 01
    24

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 23일차

    부분진행도 : Chapter3.2 - 1일차

    작성일자 : 2024.01.24(수)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    팀 과제 선정

    새로운 팀 과제를 시작하였다. 팀원들과 회의를 통해 '탕후루 만들기'라는 게임을 만들기로 정했다.

    주어진 레시피에 맞게 하늘에서 떨어지는 과일들을 받아, 10개의 탕후루를 만들면 게임 종료.

    오늘 작성한 컨셉기획서에서 퍼온 팀원의 그림. 묘사력이 굉장하다.

    매 탕후루마다 레시피와의 일치도에 따라 점수 부여를 하여 집계한다.

    역할분담을 하고, 각자 맡을 파트를 확실히 정해 과제를 시작하였다.

    나는 GameManager의 구현을 맡았다. 컨셉기획서의 작성 도중 GameManager에서 구현할 내용은 다음과 같다.

    마찬가지로 컨셉기획서의 구현 기능 목록 중 일부, 파워포인트를 수상할정도로 잘 활용하는 팀원이 작성했다.

    • 장면전환과 UI 로직 전반, 게임 규칙 로직 전반

    구현히 엄청 재밌을 것 같았고 우선해서 지원하는 팀원이 없는 것을 확인하고 바로 맡았다.

    첫날이지만 하루종일 불태워 GameManager에서 요구하는 기능의 70% 이상은 구현한 듯 하다.

    오늘의 마지막 PR

    팀 노션에도 오늘 먹은 것(TIA), 오늘의 특강(GIT)과 QnA의 정리, 스크럼 내용 정리 등 여러가지를 꾸미고, 버전 관리에 익숙해지기 위해 커밋메시지와 PR 등을 계속 다듬도록 노력했다.

    하루를 알차게 보내면 시간이 빠르게 간다는 생각이 드는데, 오늘은 그런 것 조차 신경 쓸 여유가 없을 정도로 활동한 것 같다. 살면서 가장 빛나고 있을지도.

    2. 오늘 학습에 대해

    구현 중에 어째선지 잘 되지 않던 내용

    버튼UI가 어째선지 눌리지 않았다. 원인부터 적자면 Scene 내에 EventSystem이 없었다.

    같은 이슈를 예전에 한 번 겪은 적이 있었지만, 이 원인을 알아채는 데에 많은 시간이 걸렸다.

    처음에는 메서드 자체가 문제라고 생각하여, 디버그를 수 차례 하였지만, 해당 메서드는 실행조차 되지 않았다.

    다음은 버튼을 클릭했을 때 실행되는 메서드가 잘 연결되지 않았는지 오브젝트 간 관계나 포함되는 컴포넌트들을 조사했지만 원인을 찾을 수 없었다.

    다른 씬과 비교해보는 도중 씬 내에 EventSystem 오브젝트가 없다는 것을 발견하여 원인을 찾을 수 있었다.

    해당 이슈가 발생했을 때의 대표적인 증상은 아래와 같다.

    • 버튼이 눌리는 모션이 발생하지 않는다.

    버튼이 아닌 그냥 이미지를 상대하는 듯하다는 느낌을 다음에 받는다면, EventSystem 오브젝트가 있는지 확인하는 것을 기억해야겠다.

    오늘 구현한 스크립트에 대해

    1. 게임 상태 관리 (GameManager.cs):

    • GameState 열거형을 정의하여 게임의 다양한 상태 (MainMenu, Playing, Paused, GameOver)를 관리한다.
    • GameManager 싱글톤 패턴을 구현하여 게임 전반에 걸쳐 하나의 인스턴스만 유지하도록 한다.
    • ChangeState 메서드를 통해 게임 상태를 전환하고, 각 상태에 따른 로직을 구현하였다. (예: 타임 스케일 조정, 사운드 관리).

    2. 게임 플레이 로직 (GameManager.cs):

    • StartGame, PauseGame, ResumeGame, RestartGame, BackMainMenu, GameOver 메서드를 구현하여 게임의 주요 행동을 제어하였다.

    3. 게임 데이터 초기화 및 로드 (GameManager.cs):

    • ResetData 메서드를 통해 특정 조건에서 게임 데이터를 초기화한다.
    • PlayerPrefs를 사용하여 최고 점수를 로드하고 저장한다.

    4. 게임 씬 관리 (GameManager.cs):

    • LoadMainSceneLoadTitleScene 메서드를 사용하여 게임의 메인 씬과 타이틀 씬을 로드한다.

    5. UI 관리 (UIManager.cs):

    • UIManager 싱글톤 패턴을 구현하였다.
    • SceneManager.sceneLoaded 이벤트를 사용하여 씬 로딩 시 UI 요소를 찾고 할당하였다.
    • 토글이 필요한 모든 UI 패널의 활성화/비활성화를 위한 메서드들을 제공한다.

    6. 버튼 상호작용 (ButtonManager.cs):

    • StartGame, PauseGame, BackMainMenu, ResumeGame, RestartGame 등의 UI 버튼에 응답하는 메서드들을 ButtonManager에 구현하였다.

    7. 목표 탕후루 생성 및 진행 업데이트 (GameManager.cs):

    • GenerateTargetTanghulu 메서드를 통해 랜덤한 목표 탕후루를 생성한다.
    • UpdateTanghuluProgress 메서드를 호출하여 플레이어가 쌓은 과일과 목표 탕후루를 비교하고 점수를 계산하며 종료조건을 얻는다.

    오늘의 작업을 통해 게임의 핵심 메커니즘과 흐름 제어를 위한 기반을 마련하였고, 각 컴포넌트의 기본적인 상호작용을 설정하였다.

    이후, StartDroppingFruits, CalculateAndUpdateScore, ShowTargetTanghulu 등의 메서드에 대한 구체적인 구현을 진행할 필요가 있다.

    대부분을 구현하였지만, Player를 담당하는 다른 팀원이 원활한 개발을 하도록 하기 위해서는 과일을 실제로 생성해주는 메서드의 구현이 가장 필요한 부분이다.

    3. 과제에 대해

    • StartDroppingFruits, CalculateAndUpdateScore, ShowTargetTanghulu 등의 메서드에 대한 구체적인 구현
    • GameManager에서 더 구현할 내용 찾기...당장 ExitGame 기능(게임 종료 버튼)을 구현하지 않았다는 것도 생각났다.

    4. GIT 특강 QnA 정리

    깃 특강 중에 나왔던 질의응답 내용이 무척 도움이 되어 정리 해 보았다. 하이라이트는 나의 질문

    Q&A

    작업 도중에 다른 브렌치나 이전 커밋으로 되돌아가서 확인 해 보고 싶을 때
    현재 작업 내용을 커밋해두고 이동하는 게 정상인가요?

    • Stash 사용(이후 설명)

     

    씬을 나눠서 작업하는경우 나눠서 작업하다가 마지막에 한씬에 합치는 방식인건가요?

    • (예시를 보여줌)
      • 즉, 같은 씬에서 여러 명이 기능구현을 하는 상태라면, 씬을 나눠서 하는 방식 대신 다른 방법으로.

     

    처음 레파지토리 생성할 때 깃 이그노어를 Unity로 설정하면 되나요?

    • Yes

     

    개인 적으로 궁금한건데 한명이 에셋을 받아서 적용한걸 올리면 다른사람이 그걸 받았을 때 적용이 되나요?

    • Yes

     

    메인에 합치는 작업은 팀장이 아니라 작업을 한 본인이 하는 편이 좋을까요?

    • 케바케. 지금 단계에서는 각자 Merge를 하되, 코드리뷰를 서로 잘 하는 것을 추천

     

    나중에 '게임매니저' 에 대해서 수정할 게 생기면 새로 또 브런치를 파서 작업하시는건가요?

    • Yes
    • 과거 이미 메인에 Merge한 브런치를 계속 이용하는 것은 튜터 입장에서 비추. 합친 뒤 하루이틀 뒤에 삭제하는 편.
    • 작업할 게 생길때마다 브런치를 열어서 작업
    • 히스토리에 계속 쌓이면 보기 안좋아서? 관리가 힘듬

    삭제한 브런치를 다시 가져오는 방법도 있나용?

    • No

     

    내용중에 GithubDesktop 및 유니티 인스펙터에서 한글깨짐 현상도 보여서 생각나서 질문드립니다
    /.editorconfig

    [*]
    charset = utf-8-bom

    위와 같이 프로젝트 루트 폴더에 .editorconfig 파일을 만들어 인코딩 문제를 해결하는 방법이 있던데, 현업에서도 이런 밑작업을 하고 시작하는 편인가요?
    몇 주 전에 팀 프로젝트에서 이슈(주석이나, '한글이름.png'를 불러오는 코드 등)가 있었을 때에는 코드 내에 한글 사용을 지양하는 걸로 진행했습니다.

    • 맥을 사용하는 사람이 없다면, 그냥 세팅 없이도 하는 편.
    • 실제로 한글 사용을 지양하는 편이 맞는듯.

     

    (제일 처음 질문에 이어)Stash에 관해

    • Branch - Stash all changes // 임시저장 후 다른 브런치로 이동(체크아웃) 등 할 수 있음
    • Restore을 통해 Stash했던 내용 가져오기 가능

     

    stash 공간은 하나인가요?

    • 확인 필요(확인 안되고 끝난듯)

     

    체리픽에 관해

    • 특정 커밋만 선택해서 가져오는법
    • Github Desktop에서도 가능

     

    혹시 이미 커밋해버린 친구들을 지우는 방법이 있나요?+커밋 이름도 커밋후에 수정이 가능한지 궁금합니다

    • Push가 된 건 못돌림.
    • 아직 커밋만 된 건 취소 가능 : Undo Commit
    • Amend commit(가장 마지막 푸시된 Commit만 가능) + Forced Push Origin : 이미 푸시한 커밋도 '커밋 메시지'만은 수정 가능
    • Revert?

     

    conflict 도중에 a작업물을 선택할거를 잘못해서 b를 선택해서 머지 되었을 경우 다시 conflict 작업으로 돌아가서 b작업물을 선택할 수 있는 방법이 있나요?

    • 미답변
    반응형
    COMMENT
     
    01
    23

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 22일차

    부분진행도 : Chapter3.1 - 4일차

    작성일자 : 2024.01.23(화)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    Unity를 사용하여, 캐릭터 외형과 이름선택을 하여 필드에서 돌아다닐 수 있도록 하는 개인과제 프로젝트를 진행중이다.

    제출기한이 오늘까지인데, 1차제출인 13시까지 밤을 새서 만들어 제출하고, 피곤해서 꾸벅꾸벅 졸면서 오후를 보내고, 추가 보수를 하여 21시에 다시 제출하였다.

    개발 초기에 스크립트 간 설계를 제대로 하지 않아 현재 시점에서는 보수가 크게 필요한 상황이라는 점, 특히 플레이어의 데이터가 여러 곳에 산재해 있어 이를 모아 하나의 클래스 객체화 하는 것이 남은 과제이다. 시간을 들여서 보수를 할 수 있을 것 같은데, 내일부터 할 팀 프로젝트는 아무래도 개인프로젝트에서 이어지지 않는다는 소문이 있어 추가 작업을 할 것 같지는 않다.

    2. 오늘 학습에 대해

    개발 중 이슈에 대해서는 리포지토리의 README.md에 모두 작성하였다. 그 내용은 아래와 같다.

    필수 요구사항

    1. 캐릭터 만들기
      • 입문 강의 중 사용했던 스프라이트 사용
    2. 캐릭터 이동 및 바라보기
      • InputSystem 사용
    3. 스테이지 만들기
      • 타일맵 사용
    4. 카메라가 캐릭터를 따라가기
      • 카메라 오브젝트를 Player의 하위 오브젝트로 넣음.
      • 스무스한 카메라 구현은 현재 방식으로 어려움, 이후 CameraPivot 오브젝트를 Player의 하위 오브젝트로 넣어 MainCamera가 정해진 규칙대로 CameraPivot을 따라가도록 하여 개선 가능
    5. 캐릭터 애니메이션
      • 현재 준비된 두 캐릭터에 대해 각각 idle상태, walk상태에 대한 애니메이션 마련
      • Animator의 파라미터로 int CharacterNum을 주어, 캐릭터의 외형을 선택 시 해당 CharacterNum 를 설정하고 그에 맞는 애니메이션을 Layers에서 선택하여 재생하려고 하였으나, 잘 작동하지 않아 한 개의 레이어에 두 캐릭터 외형에 대한 애니메이션을 모두 넣음. 캐릭터 외형 증가에 따라 애니메이터 동작 업데이트의 확장성 매우 낮음.
    6. 시작 시 이름 입력
      • 2~10자 이내로 이름 입력 가능
      • 캐릭터의 머리 위에 이름 반영
    7. 시작 시 캐릭터 선택
      • 두 종류의 캐릭터 마련, 캐릭터 종류가 늘어날 때마다 애니메이션을 추가해야함. 현재 애니메이터 구조로는 다수의 캐릭터 지원 어려움

    선택 요구사항(달성)

    1. 시간 표시
      • TMP와 LegacyText 어느쪽을 사용하더라도 시간 표시가 반영되도록 스크립팅
    2. 인게임 캐릭터 재선택

    개선 할 점

    • 타일 맵 분리 작업 : 현재 장식과 BackDesign이랑 같이 그려진 상태, 장식 타일만을 배치할 Decorate 타일맵 오브젝트 생성으로 개선 필요
    • 텍스트 폰트 단일화 : TMP에는 나눔글씨체를 사용하지 못하고 있음, Legacy로 바꾸던가 TMP용 폰트파일을 만들던가(시간 오래걸림) 해서 서체 단일화 필요.
    • 현재 산재한 플레이어 정보들을 모아 하나의 클래스 객체로 관리하기
    • 위와 동시에 스크립트도 정리하기
    • TMP와 LegacyText 어느쪽이라도 텍스트가 반영되도록 하는 전용 유틸 메서드 작성
    • Image와 SpriteRenderer 어느쪽이라도 스프라이트가 반영되도록 하는 전용 유틸 메서드 작성

    해야 할 일

    • Player의 클래스화
    • NPC와 Player의 클래스 리스트 관리
    • 선택과제 2번 : 인게임 이름 바꾸기(새로운 캔버스 또는 패널을 만들어야 할 듯)
    • 선택과제 3번 : 참석 인원 UI(NPC/Player의 리스트 관리 마련 후 가능)
    • 선택과제 5번 : NPC 대화(NPC 마련부터 해야함)

    개발이슈

    • 입문 강의를 소화하고 개인과제까지 하는 데에 너무 적은 시간이 부여됨. 강의시청을 도중 중단하고, 1일 이내의 시간을 개인과제에 할애하여 필수 요구사항만을 우선 구현.
      • 개인과제를 급하게 만들었기 때문에 강의에서 배운 내용을 적용하지 못한 부분이나 플레이어 데이터의 관리 등 여러 부분에서 결함이 많음.
    • TextMeshPro에서 새로운 폰트 적용이 번거로움. 한글 폰트를 새로 작성하고 적용하려 했으나 생성에 시간이 너무 오래 걸려 보류.

    3. 과제에 대해

    • 진행중인 과정에 대해 상기한대로, 추가적인 프로젝트 보수는 없을 것 같다. 내일부터 새로 주어지는 팀 과제에 착수.
    • 주어진 유니티 강의를 50%가량 소화하지 못했다. 해당 강의를 다시 보며 공부해야 할 것 같다. 디자인패턴에 대해 신경을 쓴 내용이라 필수적으로 알아야 할 스킬들이다.

    4. 참고자료

    • 없음

    5. GPT4 문답

    • 없음
    반응형
    COMMENT
     
    01
    22

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 21일차

    부분진행도 : Chapter3.1 - 3일차

    작성일자 : 2024.01.22(월)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    강의 난이도가 너무 높아 50% 부근까지만 소화한 후, 개인과제에 착수하였다. 내일 정오까지 제출을 해야하기 때문에 시간 부족으로 어쩔 수 없는 선택.

    개인과제도 커스텀하기는 어려울 것 같고, 필수 구현요소 7개만 일단 제대로 구현하기로 생각했다.

    캐릭터 만들기, 타일맵으로 플레이 공간 만들기, 카메라가 캐릭터를 따라가기, 캐릭터 이름 입력하기, 캐릭터 외형 선택하기의 구현을 마쳤고, 캐릭터이동과 idle 애니메이션을 구현하면 일단 필수요소의 구현은 끝이다. 현재 오후 9시, 남은 요소는 내일 오전까지의 시간을 활용해서 구현해야 할 듯 하다.

    강의에서 배운 내용을 활용하기에는 시간이 촉박하여 스크립트 간 디자인 없이 깡으로 구현하였다.

    2. 오늘 학습에 대해

    유니티 인스펙터에서 한글 깨짐 현상

    유니티 인스펙터에서 한글이 깨져보인다

    위 처럼 유니티에서 깨져보이는 현상 이외에도, 이대로 깃허브에 올리고 팀원에 공유를 하면 거기에서는 편집기에서조차 깨져보이기도 한다.

    해결방법은, 해당 프로젝트의 루트 폴더(.sin 파일이 위치한 곳)에 인코딩을 지정해주는 파일 하나를 생성하면 된다.

    [*]
    charset = utf-8-bom

    메모장을 열어 위와 같이 작성 후, .editorconfig 라는 이름으로 루트 폴더에 저장 해 준다.

    .editorconfig가 저장된 모습

    인코딩 설정을 이렇게 하고, Visual Studio 편집기에서 한 번 더 저장을 해준다.

    파일을 다시 한 번 저장한다
    유니티 인스펙터에서 한글이 제대로 보인다

    설정된 인코딩으로 저장을 완료하면, 유니티 인스펙터에서 한글이 제대로 보인다.

    3. 과제에 대해

    • 개인과제 제출(내일 13:00 까지)
    • 코드 및 구조 정돈하기

    4. 참고자료

    5. GPT4 문답

    • 없음
    반응형
    COMMENT
     
    01
    19

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 20일차

    부분진행도 : Chapter3.1 - 2일차

    작성일자 : 2024.01.19(금)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    C#문법과 콘솔게임 주차에서 Unity로 다시 돌아와 개인과제주차를 진행하고있다. 입문 과정이라고 지급된 유니티 강의 영상이 생각보다 어려운 내용이었다. Docs문서를 확인하면 어제 하루간 이 강의를 완강하고 나머지 3일간 개인과제를 하는 것을 염두에 둔 계획을 적어두었는데, 오늘 늦은 오후에 강의 완료표시만 모두 찍어두고 다시 이어서 소화하자고 생각하여 진행도를 100% 찍었는데 

    어.. 아무도 완강을 못한 상태인가보다. 하루는 커녕 이틀이 끝나가는데 이 상태라면, 운영측의 스케쥴 계획에서 큰 미스가 아닌가 생각했다.

    어쨌든 오늘도 유니티 강의를 들으며 하루를 보냈다. 어렵긴 하지만 게임 개발을 위한 오브젝트와 스크립트 구조에 대해 심도가 무척 깊어 유익한 내용이다.

    그리고 챌린지/노말/이지 였나로 수강생의 역량에 맞춰 따로 세션을 진행한다고 한다. 화요일과 목요일 주 2회 예정인데, 구체적으로 어떤 방식으로 진행하는지는 모르겠지만 최적화와 메모리 관리 등 듣기만해도 무서운 내용이 기다리고 있는 것은 확실한 듯.

    2. 오늘 학습에 대해

    스크립트 관련하여 들은 내용이 거의 새롭게 배운 부분이기 때문에, 주어진 시간이 촉박하여 정리하면서 듣기는 좀 어려웠나 생각한다.

    타일맵

    RPG 메이커 비슷한 느낌으로 유니티에서도 맵을 구성하는 타일과 벽 등을 쉽게 그리는 기능이 있었다.

    위와 같이 생긴 윈도우에서 색깔을 선택하듯이 타일을 선택하고, 하이에라키에 추가했던 오브젝트에 도트 아트를 하듯이 타일을 그려 구성하는 느낌.

    하이에라키에서는 2D Object - Tilemap - Rectangular 등을 통해 타일 오브젝트를 만들고

    상단메뉴의 Window - 2D - Tile Palette 윈도우를 열어, 새로운 팔레트를 생성, 바닥 등의 스프라이트 등을 팔레트에 추가하여 사용한다.

    새로운 팔레트를 위와 같이 만들면, 해당 팔레트를 어디에 저장할지 폴더를 지정하도록 한다. 나는 강의를 따라하며 Assets/Artworks/Level/ 을 지정해주었다.

    Tile Palette에 타일 스프라이트를 드래그하여 추가하였다
    타일을 추가하며 저장된 데이터

    그렇게 만들어진 팔레트에, 앞으로 사용할 바닥이나 벽 길가의 풀숲 등 타일로 사용할 스프라이트들을 드래그하여 추가한다. 여러개 선택해서 드래그하면, 적당히 정사각형에 가까운 예쁜 배치를 해 준다. 스프라이트를 드래그하는 시점에 마찬가지로 저장 위치를 지정하도록 하는데, 역시 강의를 따라하며 Assets/Artworks/Level/Tiles/ 위치에 저장하도록 하였다.

    타일 오브젝트 Floor에 바닥을 를 그리고있다
    BackDesign
    ForeDesign

    하이에라키에서 2D Object - Tilemap - Rectangular 를 통해 타일맵 오브젝트를 만들고, 여러 종류의 타일들을 작성해준다.

    어느 타일 오브젝트가 Player를 가리는지, 타일 오브젝트끼리 서로 가려지는 관계에 따라 Floor, BackDesign, ForeDesign 오브젝트를 작성하였고, 각각 높이(Order in Layer)를 0, 2, 20 으로 설정하였다.

    그리고 플레이어가 지나가지 못하도록 하기 위해 Collision 도 이 Tilemap을 통해 만든다.

    Order in Layer가 0이어서 사진에는 여러가지 타일을 쓴 것 같아 보이지만, 가려서 그렇게 보일 뿐 두세가지 종류의 타일을 사용하여 위와 같은 범위에 Collision 용 타일을 그려주었다. 그리고 Tilemap Collider 2D 컴포넌트를 추가해주고

    색을 투명하게 바꿔주어 충돌체의 역할만 수행하도록 한다. 마찬가지로 Player에게도 Box Collider 2D 컴포넌트를 추가한다.

    위와 같은 결과가 나오게 되었는데, 보니까 Player가 BackDesign에 가려지는 것이 보여, 0으로 설정되어있던 Player의 Order in Layer를 5로 바꿔주었다.

    같은 이름 변수명 이름 한번에 바꾸기

    Visual Studio 에서 위와 같이 같은 이름의 변수명 등을 한번에 바꿔줄 수 있다.

    단축키는 Ctrl R R

    최신 버전의 Visual Studio는 F2 키로 사용할 수 있다고 한다.

    3. 과제에 대해

    • 강의 내용 흡수
    • 개인과제 완수

    4. 참고자료

    • 없음

    5. GPT4 문답

    리스트에서 특정 인덱스 범위 삭제

    [You]

    List<int> stackAll = new List<int>();
    ...
    //현재 List : 1, 2, 3, 4, 5, 6, 7 ,8 ,9

    현재 리스트에서 6에서 9를 날려버리고 1에서 5만 남기도록 하는 법

    [ChatGPT]

    List<T>에서 특정 범위의 요소를 제거하려면 RemoveRange 메서드를 사용할 수 있습니다. 이 메서드는 지정된 인덱스에서 시작하여, 지정된 개수만큼의 요소를 리스트에서 제거합니다.

    예를 들어, 리스트 {1, 2, 3, 4, 5, 6, 7, 8, 9}에서 6부터 9까지의 요소를 제거하려면, 6의 인덱스를 찾고(여기서는 5), 그 인덱스부터 리스트 끝까지의 요소를 제거해야 합니다. List<int>의 인덱스는 0부터 시작하기 때문에, 6의 인덱스는 5가 됩니다.

    따라서, 다음과 같이 RemoveRange 메서드를 사용할 수 있습니다:

    List<int> stackAll = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9};
    stackAll.RemoveRange(5, 4); // 5번 인덱스부터 4개의 요소를 제거합니다.

    여기서 5는 제거를 시작할 인덱스이고, 4는 제거할 요소의 개수입니다. 이렇게 하면 리스트에서 6, 7, 8, 9가 제거되고 1, 2, 3, 4, 5만 남게 됩니다.


    [You]

    stackAll.RemoveRange(5); 와 같이 사용해서 Index 5 이후의 원소는 모두 날려버리던가 하는 방법은 어렵니?

    [ChatGPT]

    List<T>RemoveRange 메서드는 두 개의 인자를 필요로 합니다: 제거를 시작할 인덱스와 제거할 요소의 개수입니다. RemoveRange 메서드는 인자 하나만 사용하는 오버로드가 없기 때문에, 인덱스 5 이후의 모든 원소를 제거하려면 다음과 같이 제거할 요소의 총 수를 계산해야 합니다:

    List<int> stackAll = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int removeCount = stackAll.Count - 5; // 제거할 요소의 수를 계산합니다.
    stackAll.RemoveRange(5, removeCount); // 인덱스 5부터 removeCount만큼의 요소를 제거합니다.

    이 코드에서 stackAll.Count - 5는 리스트의 총 길이에서 5를 뺀 값이며, 이는 인덱스 5 이후의 모든 요소의 수를 의미합니다. 이렇게 계산한 값을 RemoveRange의 두 번째 인자로 사용하면 인덱스 5부터 리스트의 끝까지 모든 요소가 제거됩니다.


    반응형
    COMMENT
     
    01
    18

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 19일차

    부분진행도 : Chapter3 - 1일차

    작성일자 : 2024.01.18(목)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    글자 서식을 정돈하기 위해, 티스토리의 글 작성법을 마크다운 위주로 바꾸었다. 특히 외부에서 마크다운 형식의 컨텐츠를 가져올 때 그대로 가져오기 위해서는 마크다운 모드를 쓰지 않으면 안되기 때문.

    기본모드/마크다운/HTML 모드를 오가는 도중에 손실되는 정보가 상당하기 때문에(특히 마크다운으로 전환 시, 이미지 속성등이 모두 사라지는 등, 마크다운에서 지원하지 않는 작성법은 모두 손실된다) 개발자로서 가장 필요로 하는 마크다운을 메인으로 하고, 필요 시 기본모드로 넘어가 추가적인 편집을 할 생각이다.

    새로운 6시간정도 분량의 새로운 유니티 입문 강의를 지급받아, 4일 간 강의를 보며 공부하고 개인과제를 하는 주차이다. 오늘 셔플한 새로운 조는 이전 조에 비해 많이 조용한듯.

    오후 3시정도까지는 너무 피곤하여 졸다 깨다를 반복하다가 이후에서야 강의를 확인하며 학습했다. 강의 난이도가 생각보다 높은 것을 보고 당황하였다. 저녁을 먹고 와서도 다들 조용히 자기 할 일 하는 중. 일단 강의를 두시간 분량(약 1/3정도?) 듣기는 했는데, 학습과 과제까지 하는 시간이 4일밖에 주어지지 않아 시간이 많이 빡빡한 편이다.

    이제 보니, 오늘은 강의를 수강하고 나머지 시간은 개인과제를 하도록 캠프 Docs에 적혀있다. 오늘 발제 세션이 끝난 뒤의 실 학습 가능한 시간이 식사시간과 일지 작성하는 시간 제외하고 6시간정도 였을텐데, 6시간의 강의를 이 시간에 소화하라는 것은 상당히 무리가 있지 않나 생각했다.

    2. 오늘 학습에 대해

    Input 요소의 설정 변경

    아래와 같은 키입력을 유니티 스크립트에서 사용 할 수 있는데

    float x = Input.GetAxis("Horizontal");

    Edit - Project Settings - Input Manager 에서 Horizontal, MouseX 등의 이름 변경이나 상세설정 등을 할 수 있다.

    GetAxis와 GetAxisRaw

    Input.GetAxis("Horizontal") 와는 달리 Input.GetAxisRaw("Horizontal") 는 스무스한 변화(-1 ~ 0 ~ 1) 없이 입력 순간부터 등속(-1,0,1)으로 움직이게 한다.

    *C# 문법, ?.

    OnMoveEvent?.Invoke(direction); 와 같이 ?. 을 사용하면, OnMoveEventNull이 아닐 경우, Invoke(direction)을 실행한다.

    유니티 라이센스 오류 해결

    수강을 위해 유니티 버전을 2022.3.2f로 낮춘 후, 패키지 관리자를 사용하려고 보니 라이센스 이슈가 있었다.

    라이센스 문제로 보여, 유니티 허브에서 라이센스 관리 메뉴로 이동.

    이처럼 Refresh 버튼을 누르면 라이센스의 갱신을 할 수 없다는 내용이 나온다.

    유니티 라이센스 Data 삭제 : 해당 스레드에서 유니티 데이터폴더를 지운 후 해결되었다는 덧글들이 많아 해보았지만 해결되지 않았다.

    라이센스 정보가 사라진 것은 덤.

    최하단 댓글 중 Unity Hub의 로그인을 다시 해서 해결되어다는 내용을 보고, 재로그인을 해 보았더니 해결되었다.

    라이센스 시작일이 꽤 오래전이라 뭔가 아깝다는 생각이 들어 복원방법을 찾아보다가 포기한 후, 새로 무료 라이센스를 얻기를 하였는데, 다행히 시작일이 예전에 쓰던 라이센스와 동일했다.

    라이센스 문제가 해결되어, 유니티에서의 패키지 관리자도 정상적으로 작동하였다.

    유니티 상태 현황판

    라이센스 문제를 해결하며 얻은 정보. 유니티 운영측의 상태를 표시해주는 서비스이다.

    유니티 상태 현황판

    Input System

    유저 입력에 대해 전체적으로 관리해주는 에셋.

    패키지 매니저에서 Input System을 설치하여 사용한다.

    Project 탭에서 우클릭 - CreateInput Actions를 생성해준 뒤, 더블클릭하여 열어준 후 새로운 스키마를 생성한다.

    생성한 스키마 예)Keyboard&Mouse 가 선택된 것을 확인 후, Action Maps에 새로운 항목을 추가한 후, 여러 입력과 그 입력에 대한 행동을 아래와 같이 작성한다.

    그리고, 이를 사용할 스크립트들도 만들어준다.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.InputSystem;
    
    public class PlayerInputController : TopDownCharacterController
    {
        private Camera _camera;
        private void Awake()
        {
             _camera = Camera.main;
        }
        public void OnMove(InputValue value)
        {
            Debug.Log("OnMove"+value.ToString());
        }
        public void OnLook(InputValue value)
        {
            Debug.Log("OnLook" + value.ToString());
        }
        public void OnFire(InputValue value)
        {
            Debug.Log("OnFire" + value.ToString());
        }
    }

    Player오브젝트에 위 스크립트 컴포넌트를 추가.
    Player Input이라는 컴포넌트도 검색해 추가하며, Player InputActions 속성에 위에서 만들어둔 Input Action 도 추가한다.

    Behavior의 밑 내용을 보면, OnMove, OnLook, OnFire 등의 메서드가 스크립트 내에 있다면, 이벤트에 이 메서드들이 반응하도록 해 준다는 내용이라는 듯.

    해당 내용과 관련하여 너무 이해가 안되어 ChatGPT에게 여러번 질문하여 구조를 이해하였다.

    Player Input은 위에서 미리 매핑해둔 듯이(wasd는 Move), 'w'의 입력을 받으면 Send Messages 동작을 시도하는데, Player 오브젝트 내에 추가된 !!!모든 컴포넌트!!!를 뒤적이며 OnMove 메서드를 찾아 실행시킨다.

    PlayerInputController 내에 존재하는 OnMove 메서드를 도대체 어떻게 실행시키는지 연결점을 도무지 찾지 못했는데, 위와 같은 한 문장을 이해하고 나니 모든 의문점이 해결되었다.

    이어서 OnMove 메서드는 CallMoveEvent를 실행시키고

    CallMoveEvent는 미리 준비된 목록에 존재하는 메서드들을 모두 수행한다.

    이처럼 특정 이벤트가 발생하면 해당 이벤트를 필요로하는 모든 기능에 이벤트가 발생했다는 것을 알려주는 것을 옵저버 또는 구독 시스템 이라고 한다는 듯 하다.

    관련 QA 내용은 하단 GPT 문답에 적어두었다.

    스크립트 생성 시 내용 설정

    스크립트를 생성하면 주석과 함께 Start와 Update메서드가 적혀있는데, 이렇게 기본적으로 보이는 내용을 편집하는 방법이라고 한다.

    유니티 아이콘 우클릭 - 파일 위치 열기 - Data(폴더) - Resources(폴더) - ScriptTemplates(폴더) - 81-C# Script-NewBehaviourScript.cs

    해당 클래스의 내용을 수정한다.

    3. 과제에 대해

    • 강의 나머지 2/3분량 마치기
    • 개인 과제 진행하기

    4. 참고자료

    5. GPT4 문답

    유니티 프로젝트 이름 작명법

    [You]

    유니티 프로젝트 이름을 정하고 있는데, 보통의 경우 여러 단어로 이루어진 이름을 지을 때 대소문자 등 작명 규칙을 어떻게 사용하니?

    [ChatGPT]

    Unity 프로젝트의 이름을 정할 때, 일반적으로 "카멜 케이스(CamelCase)" 또는 "파스칼 케이스(PascalCase)"와 같은 작명 규칙을 사용합니다. 이러한 규칙은 여러 단어를 결합할 때 각 단어의 시작을 대문자로 표시하여 단어 간의 구분을 명확하게 합니다. 다음은 두 가지 주요 작명 스타일에 대한 설명입니다:

    1. 카멜 케이스 (CamelCase): 이 방식에서는 첫 단어를 소문자로 시작하고 이후의 각 단어는 대문자로 시작합니다. 예를 들어, myUnityProject와 같이 사용됩니다. 카멜 케이스는 주로 변수나 함수 이름에 사용됩니다.
    2. 파스칼 케이스 (PascalCase): 이 방식에서는 모든 단어를 대문자로 시작합니다. 예를 들어, MyUnityProject와 같이 사용됩니다. 파스칼 케이스는 클래스 이름, 네임스페이스, 프로젝트 이름 등에 자주 사용됩니다.

    프로젝트 이름을 지을 때는 일반적으로 파스칼 케이스를 사용하는 것이 좋습니다. 이는 프로젝트 이름이 종종 클래스나 네임스페이스와 유사한 형태로 사용되기 때문입니다. 또한, 프로젝트 이름은 의미를 명확하게 전달할 수 있도록 간결하고 기억하기 쉬운 이름을 선택하는 것이 좋습니다.

    예시:

    • SpaceAdventureGame
    • VirtualRealitySimulator
    • MobilePuzzleGame

    이러한 규칙은 프로젝트를 더욱 조직적이고 일관된 방식으로 관리하는 데 도움이 됩니다. 프로젝트 이름을 결정할 때는 프로젝트의 내용과 목적을 잘 나타낼 수 있는 이름을 선택하는 것이 중요합니다.


    Input System 에 대해

    [You]

    현재 Player에 다음 스크립트 컴포넌트가 추가되어 있어.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.InputSystem;
    
    public class PlayerInputController : TopDownCharacterController
    {
        private Camera _camera;
        private void Awake()
        {
             _camera = Camera.main;
        }
        public void OnMove(InputValue value)
        {
            Vector2 moveInput = value.Get<Vector2>().normalized;
            CallMoveEvent(moveInput);
        }
        public void OnLook(InputValue value)
        {
            Vector2 newAim = value.Get<Vector2>();
            Vector2 worldPos = _camera.ScreenToWorldPoint(newAim);
            newAim = (worldPos - (Vector2)transform.position).normalized;
            if (newAim.magnitude >= .9f)
            {
                CallLookEvent(newAim);
            }
    
        }
        public void OnFire(InputValue value)
        {
            Debug.Log("OnFire" + value.ToString());
        }
    }

    그리고 Player에는 Player Input이라는 컴포넌트도 추가되어있는데, Actions 속성에 TopDownController2D 라는 InputAction 을 넣어놓은 상태야.

    Behavior은 Send Messages로 설정되어있고, 아래 적혀있는 설명을 보면
    Will SendMessage() to GameObject: OnDeviceLost, OnDeviceRegained, OnControlsChanged, OnMove, OnLook, OnFire
    라고 적혀있어.

    PlayerInputController라는 스크립트에 존재하는 OnLook, OnMove, OnFire 라는 메서드를 어떤 식으로 실행시키는지 연결고리가 어떻게 되어있는지 도무지 이해가 되지 않아.

    다른 스크립트도 참고삼아 적어둘게.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class TopDownCharacterController : MonoBehaviour
    {
        public event Action<Vector2> OnMoveEvent;
        public event Action<Vector2> OnLookEvent;
    
        public void CallMoveEvent(Vector2 direction)
        {
            OnMoveEvent?.Invoke(direction);
        }
        public void CallLookEvent(Vector2 direction)
        {
            OnLookEvent?.Invoke(direction);
        }
    }
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class TopDownMovement : MonoBehaviour
    {
        private TopDownCharacterController _controller;
        private Rigidbody2D _rigidbody;
        private Vector2 _movementDirection = Vector2.zero;
    
        private void Awake()
        {
            _controller = GetComponent<TopDownCharacterController>();
            _rigidbody = GetComponent<Rigidbody2D>();
        }
        private void Start()
        {
            _controller.OnMoveEvent += Move; // 메서드를... OnMoveEvent에 추가하네
        }
        private void Move(Vector2 direction)
        {
            _movementDirection = direction;
        }
    }

    [ChatGPT]

    Unity의 PlayerInput 컴포넌트와 관련된 스크립트들이 어떻게 연결되어 있는지 궁금해하시는군요. Unity의 입력 시스템, 특히 PlayerInput 컴포넌트는 약간 복잡할 수 있지만, 기본적으로 이해하면 간단합니다. 각 부분을 단계별로 살펴보겠습니다.

    PlayerInput 컴포넌트

    PlayerInput 컴포넌트는 Unity의 새로운 입력 시스템의 핵심입니다. 이 컴포넌트는 입력을 처리하고, 입력에 대응하는 이벤트를 발생시킵니다. 여기서 중요한 것은 Behavior 설정입니다. "Send Messages" 옵션은 PlayerInput 컴포넌트가 입력 이벤트를 감지할 때, 이벤트에 해당하는 이름의 메서드를 해당 게임 오브젝트의 스크립트에서 호출하도록 합니다.

    PlayerInputController 스크립트

    이 스크립트에는 OnMove, OnLook, OnFire라는 메서드들이 정의되어 있습니다. 이 메서드들은 PlayerInput 컴포넌트에 의해 호출됩니다. 예를 들어, 사용자가 이동 키를 누르면 PlayerInput 컴포넌트는 OnMove 메서드를 호출합니다.

    OnMove 메서드는 입력 값을 받아서 이를 CallMoveEvent 메서드에 전달합니다. 이렇게 하면 TopDownCharacterController 클래스에 정의된 OnMoveEvent 이벤트가 발생합니다.

    TopDownCharacterController 스크립트

    이 스크립트는 OnMoveEventOnLookEvent라는 이벤트를 정의합니다. 다른 스크립트는 이 이벤트에 메서드를 등록할 수 있고, 이벤트가 발생하면 등록된 메서드가 호출됩니다.

    TopDownMovement 스크립트

    이 스크립트는 TopDownCharacterControllerOnMoveEventMove 메서드를 등록합니다. 그래서 PlayerInputController에서 OnMove 메서드를 호출하여 OnMoveEvent 이벤트를 발생시킬 때, TopDownMovementMove 메서드가 호출됩니다.

    연결 고리

    요약하면, 사용자의 입력은 PlayerInput 컴포넌트에 의해 감지되고, PlayerInputController 스크립트의 메서드를 호출합니다. 이 메서드들은 TopDownCharacterController의 이벤트를 발생시키고, 다른 스크립트에서 이 이벤트에 등록된 메서드들이 호출됩니다. 이 과정을 통해 입력이 실제 게임 내 행동으로 변환됩니다.

    [You]

    사용자의 입력은 PlayerInput 컴포넌트에 의해 감지되고, PlayerInputController 스크립트의 메서드를 호출합니다.
    라고 적혀있는데, PlayerInputController 가 해당 오브젝트의 컴포넌트로 추가되어있다는것 만으로, PlayerInputPlayerInputController의 안에있는 OnMove 등의 메서드에 바로 접근하는거야?

    [ChatGPT]

    네, 맞습니다. Unity의 새로운 입력 시스템에서 PlayerInput 컴포넌트는 입력과 관련된 이벤트를 감지하고, 이를 스크립트에 연결된 메서드로 전달합니다. 이 연결은 PlayerInput 컴포넌트의 설정과 스크립트에 정의된 메서드 이름에 의해 이루어집니다.

    PlayerInput 컴포넌트는 "Behavior" 설정을 "Send Messages"로 설정했을 때, 다음과 같이 작동합니다:

    1. 감지된 입력에 대응하는 메서드 이름 확인: 예를 들어, PlayerInput 컴포넌트의 "Actions" 설정에 "Move"라는 액션이 정의되어 있고, 사용자가 이동 입력을 하면, PlayerInput 컴포넌트는 "OnMove"라는 이름의 메서드를 찾습니다.
    2. 메서드 호출: 만약 PlayerInput 컴포넌트가 추가된 게임 오브젝트에 PlayerInputController 스크립트가 있고, 그 안에 "OnMove"라는 메서드가 정의되어 있다면, PlayerInput 컴포넌트는 이 메서드를 자동으로 호출합니다.

    이 과정은 PlayerInput 컴포넌트가 스크립트의 메서드 이름을 기반으로 자동으로 연결을 수행한다는 점에서 중요합니다. 따라서, PlayerInput 컴포넌트의 액션 이름과 스크립트의 메서드 이름이 일치해야 올바른 연결이 이루어집니다. 예를 들어, "Move" 액션이 있으면, 스크립트 내에 "OnMove"라는 메서드가 정의되어 있어야 합니다.

    [You]

    즉, PlayerInput은 게임 오브젝트 내의 모든 컴포넌트를 뒤적여서 OnMove 메서드를 찾는다는거지? 아니면 PlayerInputController라는 이름을 가진 컴포넌트 내만 탐색한다던가?

    [ChatGPT]

    Unity의 PlayerInput 컴포넌트는 "Send Messages" 동작 모드를 사용할 때, 해당 게임 오브젝트에 부착된 모든 컴포넌트를 대상으로 메서드를 탐색합니다. 즉, PlayerInput 컴포넌트는 특정한 스크립트 이름(예: PlayerInputController)을 찾는 것이 아니라, 게임 오브젝트에 부착된 모든 컴포넌트 안에서 해당 이벤트와 일치하는 메서드 이름(예: OnMove)을 찾습니다.

    이 과정은 다음과 같습니다:

    1. 입력 이벤트 감지: 사용자의 입력이 PlayerInput에 의해 감지됩니다.
    2. 메서드 탐색: PlayerInput 컴포넌트는 해당 게임 오브젝트에 부착된 모든 컴포넌트를 검사하여, 입력 이벤트와 일치하는 메서드 이름을 찾습니다. 예를 들어, 이동 입력에 대해서는 OnMove라는 메서드를 찾습니다.
    3. 메서드 실행: 일치하는 메서드가 발견되면, PlayerInput 컴포넌트는 그 메서드를 호출합니다.

    따라서, PlayerInputController라는 특정한 이름의 스크립트를 찾는 것이 아니라, 입력 이벤트에 대응하는 메서드를 게임 오브젝트에 부착된 모든 컴포넌트에서 찾아 호출합니다. 이렇게 하면, 여러 스크립트가 같은 게임 오브젝트에 존재하더라도 각각의 스크립트에서 필요한 입력 처리를 할 수 있습니다.


    반응형
    COMMENT
     
    01
    17

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 18일차

    부분진행도 : Chapter2.2 - 7일차

    작성일자 : 2024.01.17(수)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    어제자 일지에, Velog로 환승한다는 내용을 적어놓았는데, 이제까지 티스토리에 적어놓은 것도 있고, 중간에 잘라서 Velog에도 도중부터 적혀있으면 모양새가 좀 그렇기 때문에 일단 티스토리를 계속 이용하기로 생각했다. 코드블럭 스타일이나 작성 중의 불편함은 이제까지도 어떻게든 잘 해왔기 때문에 조금 불편할 뿐이지 큰 문제는 아니다.

    오늘은 과제 발표날이다. 오전은 평소처럼 알고리즘 문제를 풀고, 오후 2시부터 발표를 시작하였다. 우리 팀의 발표는 다른 팀원분이 준비 및 발표를 하셨는데, 연습을 많이 하셨는지 리허설때보다 더 좋은 스피드와 딕션으로 프로젝트 소개를 잘 해주셨다. 팀 당 발표시간 7분정도를 준수하라고 공지가 되었었는데, 프로젝트 분량이 워낙 방대해서 10분, 15분을 넘기는 조가 대부분이었다. 개성적인 기능 구현 부분 등을 잘라내며 시간을 줄이고 소감 등도 다 쳐냈기 때문에 발표 내용이 부실해졌다는 느낌이 강했는데, 아쉽지만 발표시간을 준수했다는 사실에 대해 만족해야 할 듯.

    오후에는 치킨이랑 커피가 걸린 미니게임 이벤트와 '좋은 개발자란'을 주제로 강의 세션이 열렸다. 발표를 마치고 잠시 쉬어가며 보내는 시간이었다.

    팀이 바뀌기 전 마지막 밤, 팀원들과 진로 계획과 방향성, Unity나 프로젝트 관련하여 정보 공유 등 이런저런 얘기를 하며 하루를 마무리했다.

     

    2. 오늘 학습에 대해

    아래는 다른 조들의 발표를 보며 아이디어가 좋았거나 배울 점 등 인상적인 부분을 위주로 메모된 내용이다.

    <10조 독점 메모>
    리포지토리의 Wiki 탭 활용하여 작성 및 설명
    뭐야? 다이어그램 뭐쓴거임? 나중에 다시 돌려보자 > DB스키마?
    스토리 스크립트 재생 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 와......
    퀘스트 디테일 뭔데...? 이걸 구현했다고?
    전직 뭐임.....? 아니 진짜뭐임? 어케함?
    낚시 미니게임 뭔데...
    물고기 팔기는 또 뭔데....... 뭐임
    아이템 강화는 또 뭔데...
    똑같은 7일짜리 프로젝트가 맞는지 의심 될 정도의 아이디어와 퀄리티

    <13조 독점 메모>
    피피티에 기능별로 설명해놓는 게 무난한듯
    공방 외에 다양한 스탯 : Key Value 형태로 저장?
    가능한 글자색을 밝게 해야 발표에서는 보기 좋은 듯.
    장비에 따라 마이너스 스탯도 있음 ㅋㅋㅋ
    던전 내 같은 종류의 몬스터에 A,B...등을 이름 뒤에 붙여 구별
    속도 스탯도 있어, 플레이어보다 빠를 시 몬스터가 먼저 공격하는 등 행동
    몬스터도 스킬? 찢었다...
    기본적으로 폰트를 ConsoleColor.White로 한듯. 밝아서 보기 좋은듯? 구현 상으로 어려울 수 있음.
    바이너리 저장 -> 클래스 자체를 직렬화 할 수 있어 구현이 편함, 보안성 강화
    PPT 마지막화면 센스(코딩해요 콘)
    기능구현에 있어 모티브가 된 게임에 대해 소개

    <미스>
    인벤토리에 '회복약' 넣는 거 깜빡함

    <발표>
    PPT 예쁜 템플릿과 깔끔한 정리
    다른 수강생들에게 도움이 될만한 내용을 끼워넣으면 좋을듯
    회고, 어떤 시도를 했는지 등. 기술적 회고가 있으면 더 좋음.
    현장 시연을 위한 치트키
    깃로그 시각화

    <기술과 디자인>
    콘솔 내에 이모지 사용 가능한듯
    스킬명과 수치에 모두 색깔 넣어주기
    레벨업 시 스탯포인트 아이디어
    직업별 다른 상점물품 장비
    MP포션
    저장 슬롯 여러개

    <고급 용어 사용>
    예)던전 스케일링

    <이외 피드백>
    어택 등 플레이어가 사용하는 기능들은 플레이어 클래스에 모아두는 등 하는 게 좋음
    코드컨벤션 준수, 커밋 메시지 등도 신경쓰기
    메인브렌치에서 여러 브렌치로 나누어 사용하는 방법 좋음

    <???>
    30개 이상의 cs파일(17조 이미지)
    제비뽑기로 발표자를 정함
    진행을 맡은 *** 매니저님은 회고 파트를 좋아하시는듯

    <우리팀 피드백>
    화면공유를 해도 작아서 잘 보이지 않는 부분이 곳곳에 존재. 음량 세팅과 함께 체크하면 좋을 듯.

     

    3. 과제에 대해

    오는 주차는 다시 Unity로 복귀하여 개인과제를 진행한다. 앞으로도 대략 한 주 단위로 프로그램이 바뀌는 듯 하다.

    당장 마주하는 프로젝트도 잘 참여하고, 최대한 알찬 결과물을 뽑아가고싶다.

     

    반응형
    COMMENT
     
    01
    16

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 17일차

    부분진행도 : Chapter2.2 - 6일차

    작성일자 : 2024.01.16(화)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    과제 제출과 발표에 대해 회의, 게임 내 장면의 사이클 위주로 발표를 진행하고, 시연에서 혹여나 빠진 내용은 슬라이드에 별첨하여 설명을 할 예정. 팀원 각자의 소감을 발표 마지막에 배치할 예정이다.

    티스토리 글작성이나 테마 그리고 코드블럭 등의부분에서 불편하다고 느껴져서 내일 글부터는 Velog를 사용 해 볼 생각이다.

     

    2. 오늘 학습에 대해

     

    (1) 알고리즘 풀이 : 풀이 중 검색을 했던 내용을 위주로  작성

     

    프로그래머스 - 두 개 뽑아서 더하기

    • 전체 코드
    using System;
    using System.Collections.Generic;
    
    public class Solution {
        public int[] solution(int[] numbers) {
            int[] answer = new int[] {};
            // 동적관리를 위한 List<int> 사용
            List<int> answerList = new List<int>();
            
            for(int i=0; i<numbers.Length-1; i++){
                for(int j=i+1; j<numbers.Length; j++){
                    int sum = numbers[i]+numbers[j];
                    if (!answerList.Contains(sum)) {
                        answerList.Add(sum);
                    }
                }
            }
            answerList.Sort();
            answer = answerList.ToArray();
            return answer;
        }
    }
    • 코드 특징
      • 좋은 로직이 떠오르지 않아 정공법 작성
    • 매번 나오는 값을 array에 추가하야 하는 경우 동적 관리를 위해 List로 바꾸어 사용하는 것이 좋다.
      • List와 그 메서드는 아래와 같이 사용 가능
    // 리스트를 사용하기 위해 using
    using System.Collections.Generic;
    
    // 리스트에 요소를 추가
    answerList.Add(value);
    
    // 리스트 내에 요소가 들어있는지 확인
    if (!answerList.Contains(value)) {}
    
    // 리스트 정렬
    answerList.Sort(); // 리스트 정렬
    
    // answerList라는 List<T> 객체의 모든 요소를 포함하는 새로운 배열을 생성 후, answer라는 배열 변수에 할당
    answer = answerList.ToArray();

     

    프로그래머스 - 가장 가까운 같은 글자

    • 전체 코드
    using System;
    using System.Collections.Generic;
    
    public class Solution {
        public int[] solution(string s) {
            int[] answer = new int[s.Length];
            
            // O(N^2)도 되겠지만, 더 효율적인 알고리즘으로...
            // s가 영어 소문자로만 이루어져 있다고 하니, 26개 소문자의 index 리스트를 작성하자
            Dictionary<char, int> alphaIndex = new Dictionary<char, int>();
            
            // a부터 z까지 -1 설정
            for (char c = 'a'; c <= 'z'; c++) {
                alphaIndex.Add(c, -1);
            }
            
            // s를 처음부터 순회하며 answer와 alphaIndex 갱신
            for (int i = 0; i<s.Length; i++){
                if(alphaIndex[s[i]]==-1) answer[i] = -1;
                else answer[i] = i-alphaIndex[s[i]];
                
                alphaIndex[s[i]] = i;
            }
            // 시간복잡도 O(N)
            return answer;
        }
    }
    • 코드 특징
      • 시간복잡도 O(N)으로 해결
      • 사전형에 26개의 알파벳을 키로 갖는 index를 마련하여, s를 순회하며 매 문자마다 즉각 갱신
    • C#에서 영문 소문자 26개를 key로, int형을 value로 쓰는 사전형을 사용하는 법
      • Dictionary<char, int> 타입을 사용하여 수행. 아래와 같이 사용 가능
    // 사전형을 사용하기 위해 using
    using System.Collections.Generic;
    
    // 선언과 초기화
    Dictionary<char, int> dict = new Dictionary<char, int>();
    
    // 키값 'a'부터 'z'까지, -1 값으로 로 초기화
    for (char c = 'a'; c <= 'z'; c++) {dict.Add(c, -1);}
    
    // 사전형 값 설정
    dict['a'] = 1; // 'a'의 값을 1로 설정
    
    // 미리 설정해주지 않은 키 값에 위 구문처럼 값을 대입하려고 하면, KeyNotFoundException 발생
    // TryGetValue, ContainsKey 메서드를 사용하여 키가 존재하는지 확인하는 조건문을 두면 좋음
    if (dict.TryGetValue('a', out value)) {}
    if (dict.ContainsKey(key)) {}
    
    // 사전 내용 출력
    foreach (KeyValuePair<char, int> entry in dict) {
        Console.WriteLine($"Key: {entry.Key}, Value: {entry.Value}");
    }

     

    3. 과제에 대해

    • 발표 돕기
    • Velog 환승작업

     

    4. 참고자료

    • 없음
    반응형
    COMMENT
     
    01
    15

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 16일차

    부분진행도 : Chapter2.2 - 5일차

    작성일자 : 2024.01.15(월)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    콘솔 던전 RPG 게임 팀 과제의 개발부분은 오늘 마무리되었다. 큰 문제가 나오지 않는다면, 내일 발표에 관해서 회의를 진행하고 발표 자료와 준비를 할 예정으로 보인다.

    아침에 1시간씩 진행하는 CS는 Level1(캠프에서 문제 잔뜩 모아놓고 레벨 매겨줌)부터 시작해서 현재 Level3 문제들을 지나고 있는데, 슬슬 한 문제당 푸는 시간이 늘어나는 게 느껴진다. 아직 간단한 문제지만 문제당 이제 평균 10분을 넘어가는 듯 한 기분. 문제를 풀기보다 매번 내가 찾아보는 게 대체 무엇인지 메모해두는 게 좋을 것 같다. 오답노트 공부하듯이 나중에 CS부분만 몰아보면 좋을 듯. 유감이지만 오늘은 메모한 것이 없다.

     

    2. 오늘 학습에 대해

    콘솔 UI에 파티클 로직을 구현하였다. 모든 파티클이 랜덤으로 깜빡인다거나 하는 건 아니고, 주기적으로 파티클 문자 n개를 화면에 띄우고 지우고를 반복한다.

    콘솔 화면에 파티클 이펙트를 보여주는 코드의 진행

    string titleArt = "{아\n스\n키\n 아\n트}" // 콘솔에 출력할 내용
    InitializeScreenBuffer(titleArt); // 콘솔에 출력하기 전, 내용을 저장
    DrawAsciiArt(titleArt); // 콘솔에 WriteLine() 할 뿐인 메서드
    
    // '+' 문자를 화면에 {num}개 만큼 생겼다 없어지는 파티클 이펙트.
    // 너비 95, 높이 41의 범위에 800ms마다 갱신되도록 했다.
    int width = 95; int height = 41; int num = 15; int msDelay = 800;
    effectThread = new Thread(() => UpdateEffect(width, height, num, msDelay)); effectThread.Start();
    
    // 키 입력을 받으면 스레드를 종료하여 다음 장면으로 넘어갈 준비를 한다.
    Console.ReadKey();
    keepRunning = false; // 스레드에 종료 신호를 보냄
    effectThread.Join(); // 스레드가 종료될 때까지 대기
    
    // 다음 장면으로 넘어감


    (1) InitializeScreenBuffer
    해당 메서드의 목적은 콘솔 화면에 표시할 내용을 '버퍼(buffer)'라는 메모리 구조에 저장하는 것

    버퍼 : 데이터를 임시로 저장하는 메모리 공간

    static void InitializeScreenBuffer(string s) // 내용을 버퍼에 저장하기
    {
        int width = Console.WindowWidth;
        int height = Console.WindowHeight;
        screenBuffer = new char[height, width]; // screenBuffer는 함수 밖에 전역변수로 선언을 해두었다
        // 아스키 아트를 버퍼에 저장
        using (var reader = new StringReader(s))
        {
            string line;
            int y = 0;
            while ((line = reader.ReadLine()) != null)
            {
                for (int x = 0; x < line.Length; x++)
                    screenBuffer[y, x] = line[x];
                y++;
            }
        }
    }

    Console.WindowWidth 와 Console.WindowHeight 를 사용하여 현재 콘솔 창의 너비와 높이를 불러온다.
    콘솔 창의 너비와 높이에 해당하는 배열의 크기를 갖는 2차원 배열 screenBuffer 를 생성.
    screenBuffer 는 버퍼의 역할을 하며, 콘솔 화면에 표시될 각 문자의 위치를 저장.
    + Height를 콘솔의 크기보다 높게 설정해야 하는 경우도 생길 수 있지만, 일단은 콘솔 높이를 사용.

    StringReader를 사용하여 주어진 문자열 s 를 한 줄씩 읽는다.
    각 줄을 순회하며 각 문자를 screenBuffer 배열에 저장.
    y 변수는 현재 처리 중인 줄(행)의 번호. 
    x 변수는 줄 내의 문자(열) 위치.

    screenBuffer에는 asciiArt의 각 문자가 콘솔 화면상의 해당 위치에 매핑된다.
    이후에 콘솔 화면에 어떤 변화가 필요할 때, 이 버퍼를 참조하여 어떤 문자가 원래 어느 위치에 있었는지 알 수 있다.

    예시) "AB\nCD" 를 버퍼에 저장
    screenBuffer[0, 0] = 'A'
    screenBuffer[0, 1] = 'B'
    screenBuffer[1, 0] = 'C'
    screenBuffer[1, 1] = 'D'

    (2) 이후 콘솔에 내용을 출력하고( DrawAsciiArt(titleArt) )

     

    (3) 매개변수로 (1) 파티클이 나올 직사각형 범위, (2) 파티클 갯수, (3) 깜빡이는 주기 를 넘겨 일정 시간마다 랜덤한 위치에 파티클 효과가 보이도록 한다.

    + 지금 더 갱신된 코드는 파티클로 쓸 문자 char, 버퍼를 사용하지 않아도 작동하도록 하는 bool isBuffer 등을 추가하여 확장성을 높였다.

    파티클이 지워지는 타이밍에, 버퍼에 저장되어 있던 내용을 기반으로 원래 문자를 복원한다.

     

    (4) 마지막으로 키 입력을 받으면 스레드를 종료하도록 조건문을 넣어두었다.

     

    콘솔 내 전각문자의 처리

    위 내용의 구현 중 가장 큰 문제는 전각기호의 처리였는데, 반각문자인 파티클 '+'가 전각기호인 한글 문자 자리 등에 나타난다면, 한글문자가 이리밀리고 저리밀리고 해서 난장판이 되어버린다. 그래서 해당 위치가 원래 전각기호가 위치했는지 판별하는 동시에 전각기호의 왼쪽 혹은 오른쪽 중 어느 쪽에 '+'가 들어갔는지 판별하여 " +" 또는 "+ "와 같이 공백문자를 포함하여 해당 전각문자를 덮도록 설계하였다.

    또한 전각기호를 복원할 때에도, 한칸 밀린 방향에 복원되지 않도록 조건 분기를 잘 나누어 제대로 된 위치에 다시 복원되도록 신경썼다.

    위의 두 요소를 신경쓰니 전각문자가 이리저리 치이는 문제는 사라졌다.

    아래는 문자가 전각문자인지 판별하는 코드이다

    아마 모든 전각문자를 포함하고 있진 않을 것. 대표적인 범위만 설정.

    static bool IsFullWidth(char c) // 전각문자인지 판별
    {
        int[] ranges = { 
            0x1100, 0x115F, // 한글 자음과 모음
            0x2E80, 0x2EFF, // CJK(중국, 일본, 한국) 급진 부호
            0x3000, 0x303F, // CJK 심볼 및 구두점
            0x3200, 0x32FF, // CJK 호환성 음절
            0x3400, 0x4DBF, // CJK 통합 한자 확장
            0x4E00, 0x9FFF, // CJK 통합 한자
            0xAC00, 0xD7AF, // 한글 음절
            0xF900, 0xFAFF, // CJK 호환성 한자
            0xFE30, 0xFE4F, // CJK 호환성 형태
            0xFF01, 0xFFEF, // 하프와이드 및 풀와이드 형태
        };
        int code = (int)c;
    
        for (int i = 0; i < ranges.Length; i += 2)
        {
            if (code >= ranges[i] && code <= ranges[i + 1])
            {
                return true; // 전각
            }
        }
        return false; // 반각
    }

    전각문자 판별 메서드는 콘솔 한정 앞으로도 유용하게 써먹을 수 있을 것으로 보인다. 예를 들어 영어와 한글이 섞인 문자열끼리 폭을 같게 맞추도록 공백문자를 채워넣는 등 당장 생각나는 것도 몇 개 있다.

     

    실행파일 생성

    마지막으로 실행파일로 만들어서 다른 경로에서 직접 실행 해 보자고 갑자기 생각나서 해 본 내용.

    크게 과정이 복잡하진 않았고, 

    1. 빌드 세팅(1) - 프로젝트 속성

    2. 빌드 세팅(2) - 대상 OS 버전 대충 win7 등 고름

    3. 빌드 - Debug에서 Release로 바꿔준 후, 빌드

    4. exe 파일 기본 생성 위치, 다른 곳으로 가져갈 때 파일 세개만 챙기면 잘 실행되는 것으로 보임

    우리 조 슬랙에 설명용 쓰려고 대충 찍은 스크린샷이라 크기가 들쭉날쭉하다.

    저렇게 생성된 파일 중, 체크표시한 유형 세가지만 챙겨가면, 다른 환경에서도 잘 실행 될 것으로 예상된다.

     

    3. 과제에 대해

    • 내일부터 CS 중 검색하는 내용 생기면 무조건 적어두기
    • 발표 준비 돕기(본인 발표자가 아님)

     

    4. 참고자료

    반응형
    COMMENT
     
    01
    13

    C# 공부를 하며 계속 긴가민가 헷갈렸던 내용이 있어 정리.

    2차원 이상의 배열을 사용하려고 할 때, 두 가지 방식으로 배열을 사용 할 수 있다.

    int[,] array = new int[3, 2];
    
    int[][] jaggedArray = new int[3][];

    위의 방식처럼 [ , ] 한개의 대괄호 안에 쉼표가 들어가있는 모습과, 아래의 방식처럼 [ ][ ] 두 쌍의 대괄호를 사용하는 방식이다.

    (어느쪽이 맞는지 매번 헷갈리다가, 둘 다 사용한다는 걸 이제 알았음)

     

    1. 다차원 배열(Rectangular Arrays)

    int[,] array = new int[3, 2];

    괄호 내 쉼표를 사용하여 다차원 배열을 사용할 수 있다.

    특징으로는 모든 행이 동일한 수의 열을 갖는다는 것.

     

    2. 가변 배열(Jagged Arrays)

    int[][] jaggedArray = new int[3][];
    jaggedArray[0] = new int[4];
    jaggedArray[1] = new int[5];
    jaggedArray[2] = new int[3];

    가변 배열(Jagged Arrays) 또는 배열의 배열(Array of Arrays) 로 불리는 방식.

    위의 예시에서는 첫 번째 배열(jaggedArray[0])은 4개의 요소를 갖고, 두 번째 배열(jaggedArray[1])은 5개의 요소를 갖는 등 각 행마다 다른 수의 요소를 가질 수 있다.

     

    3. 두 배열의 차이점

    구조: 다차원 배열은 모든 행과 열의 크기가 같은 반면, 가변 배열은 각 행이 서로 다른 크기를 가질 수 있다.

    메모리 할당: 다차원 배열은 단일 연속된 메모리 블록에 할당되는 반면, 가변 배열은 각 행마다 별도의 메모리 블록에 할당된다.

    성능: 일반적으로 가변 배열은 다차원 배열보다 접근 속도가 빠르다. 이는 다차원 배열이 메모리에서 더 복잡하게 처리되기 때문.

    사용 용도: 다차원 배열은 데이터가 균일한 그리드 형태일 때 유용하고, 가변 배열은 각 행의 길이가 다를 수 있는 더 복잡한 데이터 구조를 다룰 때 유용하다.

    반응형
    COMMENT
     
    01
    12

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 15일차

    부분진행도 : Chapter2.2 - 4일차

    작성일자 : 2024.01.12(금)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    팀 과제(콘솔 텍스트 던전 RPG) 진행률이 거의 막바지이다. 오는 월요일에 던전 내 전투 중 장면 구성을 손질하면 게임 내적인 부분은 완료가 되어있을 것 같다. 

    UI.cs 클래스를 새로 마련하여 플레이어의 선택지 패널, 아스키아트 프리셋, 텍스트와 콘솔에 관련된 편의기능을 압축한 메서드 등 여러가지를 구현하고, 디자인 개선을 마쳤다. 전후 이미지를 같이 보여주면 좋을 것 같은데 그렇게까지 하기에는 에너지가 모자라다. 기록으로 남기는게 무조건 좋을텐데 라고 생각 중.

    매일 그렇지만 요즘 다른 하는 일이 없어서 그런지 팀 과제랑 알고리즘 풀기에 모든 에너지를 쏟고 있다. 수면 시간도 너무 적어져서 그런지 두통이 심해졌다.

     

    2. 오늘 학습에 대해

    팀 과제

    Github Desktop으로 하루 종일 팀 과제를 같이하다보니 깃은 이제 수월하게 다루고 있는 것 같다. 특히 팀원들이 Pull Request를 수행하기 전 Main함수로부터 업데이트를 잘 한 뒤에 PR을 진행했기 때문에 충돌이 거의 없었던 편.

    오늘은 UI의 끝을 보자고 생각하여(갑자기 그런 기분이 들어) 구현을 많이 하였는데, 그 내용은 아래와 같다.

    1. 타이틀 구현과 전반적인 UI 스타일 구현

    타이틀이 필요하다고 개인적으로 종종 생각이 들었었기에, 오늘 UI 구현을 하며 타이틀 장면도 마련 해 두었다.

    아스키아트가 화면을 꽉 채우도록 하고, 특정 좌표로 커서를 옮겨 텍스트를 구현하였다. 이 상태에서 아무 키나 누르면

    데이터를 불러온다는 안내 메시지를 잠시 보여준 후, 다음 장면으로 넘어간다. 가운데 정렬이 말끔해보여서 좋았다.

    캐릭터 생성 장면은 더 화려하게 꾸밀 수 있었지만, 생성 단계는 처음이라는 느낌답게 조촐하게 보여주는 것도 좋지 않을까 생각하게 되어, 필요로 하는 간단한 텍스트만 표시하도록 하였다.

    그래도 왼쪽에 여백을 두거나 줄바꿈을 두고, '>>>' 문자를 두는 등 가독성에 신경을 썼다. 뒤따라 나오는 직업 선택이나 확인 장면도 거의 동일

    직업까지 선택을 하면 아래와 같은 메인 메뉴를 볼 수 있다.

    메인 메뉴이지만 현재 아이디어 고갈로 검소한 디자인을 하고있다.

    우측 빈 부분에 아트를 넣거나 하면 좋을듯.

    신경쓰이는 점은 상단 아스키아트가 너무 긴데, 내가 작업한 부분이 아니라 건드리기 조심스러운 부분도 있고 마땅한 대체재를 생각해 두지 않았기 때문에 일단은 현상유지이다.

    메인메뉴를 제외하면 모두 하단의 유저 입력 전용 패널과 동일한 폭으로 맞춰두었다. 예를 들어 회복아이템 메뉴는 아래와 같이 균형잡힌 배치를 가지고 있다.

    유저에게 보여지는 장면의 크기에 맞추어 콘솔창의 크기도 줄여보는 시도를 했었지만, 어째서인지 콘솔 폭을 120자 미만으로 줄이게 되면 콘솔창 하단에 좌우 스크롤바가 생겨버리기 때문에 일단 콘솔창은 넓게 쓰고 있다.

    메인 컨텐츠인 던전에 들어가는 입구 장면이다. 간단한 아스키아트를 넣어두었다.

    E 키를 통해 내 정보를 열어볼 수 있는데(정보열기는 다른 팀원이 구현)

    스테이터스는 밝은 노란색으로 표시되게 하여 가독성을 높였고, 길어진 높이만큼 빈 공간에 아트도 더 넣어두었다.

     

    2. UI.cs

    오늘 UI.cs 파일을 새로 작성하고, 구현한 메서드가 여럿 있다.

     

    (a) 유저 입력 패널

    public static string UserInput(string alert="", bool positive=false, string reqMsg= "다음 행동을 입력하세요.")
    {
        Console.WriteLine("");
        Console.WriteLine(".──────────────────────────────────────────────────────────────────── .");
        Console.WriteLine($"  {reqMsg}");
        Console.WriteLine("");
        Console.WriteLine(""); Console.ForegroundColor = (positive)?ConsoleColor.Green:ConsoleColor.Red;
        Console.WriteLine($"  {alert}"); Console.ResetColor();
        Console.WriteLine("  >>>"); 
        Console.WriteLine("'──────────────────────────────────────────────────────────────────── '");
        Console.SetCursorPosition(6, Console.CursorTop-2);
        return Console.ReadLine();
    }

    UserInput()을 사용하여 위와 같은 패널을 그린다.

    경고 메시지와, 경고메시지의 성격(true:녹색 / false:빨간색), 그리고 기본 메시지인 "다음 행동을 입력하세요." 도 바꾸어 매개변수로 전달할 수 있다.

     

    (b) 아스키아트

    게임 내 모든 아스키아트를 모아두었다. 열거형인 AsciiPreset에 각자 정해둔 이름을 사용하여 AsciiArt 메서드를 호출한다.

    // 열거형
    public enum AsciiPreset
    {
        TitleArt,
        CreateCharacter,
        SelectClass,
        MainMenu,
        Battle,
        Status,
    	...
    }
    
    // 아스키아트 호출
    public static void AsciiArt(AsciiPreset preset)
    {
        ConsoleColor statusColor = ConsoleColor.Gray;
        int x, y;
        switch (preset)
        {
            ...
            case AsciiPreset.PotionInventory:
                Console.WriteLine("                                                                     ");
                Console.WriteLine("    .-.   p--- .'~`. .-=~=-.   :~:      |~|   .-~~8~~-.  |~|  .-.    ");
                Console.WriteLine("  .'__( .'~`.  `. .'  )___(  .'   `.    | |   |~~---~~|  | |  )__`.  ");
                Console.WriteLine("  | l | | m |  .'n`. (  o  ) |  p  |] .' q `. |   r   | .'s`. | t |  ");
                Console.WriteLine("  |___| |___|  `._.'  `._.'  |_____|  `.___.' `._____.' `._.' |___|  ");
                Console.WriteLine("                                                                     ");
                Console.ForegroundColor = statusColor;
                Console.WriteLine("----------------------------[회복 아이템]----------------------------");
                Console.ResetColor();
                Console.WriteLine("");
                break;
            ...
            case AsciiPreset.DungeonEntrance3:
                x = 41; y = 25;
                DrawOnSpecificPos("" +
                    "      |\\      _,,,---,,_\n" +
                    "ZZZzz /,`.-'`'    -.  ;-;;,_\n" +
                    "     |,4-  ) )-,_. ,\\ (  `'-'\n" +
                    "    '---''(_/--'  `-'\\_)\n",
                    x, y);
                break;
            ...
        }
    }

    간단하게 줄여본 코드는 위와 같다. 그냥 적어둔 내용대로 Write를 하고 있기 때문에 복잡한 내용은 없다.

    고양이 아트를 예로 든 DrawOnSpecificPos(string, int x, int y) 메서드는 특정 좌표를 지정하여 그릴 수 있도록 마련해둔 메서드이다. 그 내용은 아래와 같다.

     

    (c) 특정 좌표에 그림을 그리는 DrawOnSpecificPos 메서드

    public static void DrawOnSpecificPos(string s, int xInput, int yInput)
    {
        // 커서 위치를 저장해두어, Draw가 끝나면 커서 위치를 원상복귀
        int ySave = Console.CursorTop;
        int xSave = Console.CursorLeft;
        int x = xInput;
        int y = yInput;
        string[] lines = s.Split('\n');
        foreach (string line in lines)
        {
            Console.SetCursorPosition(x, y);
            Console.Write(line);
            y++;
        }
        Console.SetCursorPosition(xSave, ySave);
    }

    진행중이던 커서 위치는 저장해두고, 특정 위치를 기점으로 아트를 그린 후, 원래의 커서 위치로 되돌아온다. 이렇게 만들어진 것이 아래의 고양이와 캠프장.

     

    (d) 텍스트에 색을 입히는 메서드들

    public static void ColoredWriteLine(string s, ConsoleColor color)
    {
        Console.ForegroundColor = color;
        Console.WriteLine(s);
        Console.ResetColor();
    }
    public static void ColoredWrite(string s, ConsoleColor color)
    {
        Console.ForegroundColor = color;
        Console.Write(s);
        Console.ResetColor();
    }
    public static void RandomColoredWrite(string s)
    {
        Random random = new Random();
        foreach (char c in s)
        {
            Console.ForegroundColor = (ConsoleColor)random.Next(9, 16);
            Console.Write(c);
        }
        Console.ResetColor();
    }

    메서드 이름만큼 직관적으로, 그리고 한 줄로 사용할 수 있어 나름 편리할 메서드이다.

    Console.Write 대신 사용할 수 있고, ConsoleColor.Red 와 같은 매개변수를 함께 넣어 색을 지정해준다.

    // 단일 사용
    UI.ColoredWriteLine("골드", ConsoleColor.Yellow);
    
    // 연계 사용
    Console.WriteLine($"골드를 {UI.ColoredWriteLine("500", ConsoleColor.Yellow);} 만큼 획득!");

    그냥 사용해도 편하고, 더 좋은 점은 문자열 도중에 특정 단어만 색을 입히는 것이 편하다. 위 내용을 메서드 없이 깡으로 구현한다면 아래와 같이 매우 길어지게 된다.

    // 예시1
    Console.ForegroundColor = color;
    Console.WriteLine("골드", ConsoleColor.Yellow);
    Console.ResetColor();
    
    // 예시2
    Console.Write($"골드를 ");
    Console.WriteLine("골드", ConsoleColor.Yellow);
    Console.Write($"{"500"}");
    Console.ResetColor();
    Console.WriteLine($" 만큼 획득!");

    Write와 WriteLine을 섞어 쓸 수 밖에 없게 되버리는 점도 문제점.

    RandomColoredWrite(string s) 메서드는 받은 문자열을 문자 단위로 랜덤한 색을 입히게 하는 신나는 메서드이다.

     

    알고리즘 풀이 중 자주 잊어버릴 만한 내용에 대해

    캠프에서 소개하는 알고리즘 문제 중 40문제 이상을 풀었지만, 자주 잊어버려 찾아보고 코드 작성을 했던 내용이다.

    복습하는 기분으로 문제들을 다시 열어보며 작성하였다.

     

    No.3[120805 몫 구하기]

        public int solution(int num1, int num2) {
            int answer = num1 / num2;
            return answer;
        }

     

    • int 형끼리의 나눗셈 계산은 int 형을 반환한다.

     

    No.7[120806 두 수의 나눗셈]

        public int solution(int num1, int num2) {
            int answer = 0;
            answer = (int)((float)num1/(float)num2*1000);
            return answer;
        }
    • float로 캐스트 된 수 끼리 나눗셈을 해야 제대로 된 결과가 나온다.
    • 현재 문제에서는 결과값의 소수 부분을 버리고 정수값만 출력.

     

    No.10[120817 배열의 평균값]

        public double solution(int[] numbers) {
            double answer = 0;
            for(int i=0; i<numbers.Length; i++){
                answer += numbers[i];
            }
            answer /= numbers.Length;
            return answer;
        }
    • 배열을 전달받을 때에는 int[] numbers 의 형식을 사용.
    • 배열은 .Length 를 사용하여 길이를 반환한다. 리스트의 경우는 .Count 가 길이를 반환한다. 둘 다 뒤에 ()가 없음에 주의.

     

    No.11[12937 짝수와 홀수]

    • (영단어)짝수는 'Even', 홀수는 'Odd' 

     

    No.12[12944 평균 구하기]

        public double solution(int[] arr) {
            double answer = 0;
            answer /= arr.Length;
            ...
        }
    • 위와 같이 double 형을 int 형으로 나눌 경우에는 오류가 발생하지 않음. 변수 간 포함관계에 따라서 허용되는 것으로 추정.

     

    No.13[12931 자릿수 더하기]

        public int solution(int n) {
            int answer = 0;
            string nStr = n.ToString();
            foreach(char c in nStr){
                answer += int.Parse(c.ToString());
            }
            return answer;
        }
    • '문자열' 을 int형으로 바꿀 경우에는 int.Parse() 사용. 문자열이 아닌 문자 는 사용할 수 없기 때문에 .ToString() 메서드를 통해 문자열로 변환 해 주어야 한다.
    • foreach문은 foreach(자료형 이름 in nStr){ 순회 내용 } 과 같이 작성. in 키워드 말고도 다른 방식도 여럿 있을 것으로 생각되어짐.

     

    No.16[12954 x만큼 간격이 있는 n개의 숫자]

        public long[] solution(int x, int n) {
            long[] answer = new long[n];
            for(int i=1;i<=n;i++){
                answer[i-1] = (long)i*(long)x;
            }
            return answer;
        }
    • 일부 테스트케이스에서 실패하는 경우, 오버플로가 일어나는지 확인하자.
    • 해당 문제는 int의 범위를 벗어나는 값을 다루기 때문에 long으로 캐스팅하여 해결.

     

    No.17[12932 자연수 뒤집어 배열로 만들기]

    int[] answer = new int[numStr.Length];
    • 새로운 배열의 선언을 해 줄 때의 형식
    answer[index++] = (int)(num%10);
    • 전치 및 후치 연산자를 활용하여 코드 길이 단축

     

    3. 과제에 대해

    • 전투 중 UI 디자인 수정
    • README.md 작성하기

     

    4. 참고자료

    없음

    반응형
    COMMENT
     
    01
    11

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 14일차

    부분진행도 : Chapter2.2 - 3일차

    작성일자 : 2024.01.11(목) 

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    캠프에서 그제와 어제 알고리즘 특강을 진행하고, 오늘부터 하루 한개 이상 알고리즘 문제 풀기를 아침 09시부터 10시까지 자율적으로 진행한다. 새벽에 잠이 안와서 먼저 시작했었는데, 계속 풀다보니 40문항정도 제출 완료. 한 두 줄로 해결 할 수 있는 기초 알고리즘 문제부터 시작하기 때문에, 사실 지금 시점에 제출한 문항 수는 크게 의미는 없어 보인다.

    팀 과제는 3일차인데 진행이 무척 빠른 것 같다. 하루 10시간씩 잡고있으니 당연하다면 당연한가 싶기도 하다. 스킬과 마나 시스템을 더 손보고, 나머지는 기존 기능에 대한 개선을 진행할 것으로 보인다.

     

    2. 오늘 학습에 대해

    오늘은 특별히 새로운 것을 배우거나 한 것은 없다. 개발파트가 순조로워 오늘 진행한 내용이 무척 많다. 오후 팀 스크럼에서는 내가 오늘 개발했던 내용도 많이 잊어버려 Github Desktop에 적혀있는 커밋 로그를 보며 프레젠테이션을 진행했다.

    오늘 내가 진행한 커밋 내용은 아래와 같다.

    Feat: Potion클래스 및 '회복 아이템' 장면 구현
    - Item 을 상속받는 Potion 클래스 구현
    - new Potion 객체로 [물] 추가(일단은 포션 역할로 사용, 포션 종류가 확장될 가능성이 있기 때문에 이름을 포션으로 두진 않음)
    - 메인메뉴 - 회복아이템 장면 구현

    Feat: 던전 승리 시 포션 및 골드를 획득

    Refactor: Potion 클래스 내 메서드 개편 및 해당 메서드를 사용했던 장면에서 코드 단축

    Design: 회복아이템 아트 수정

    Refactor: 경고문 시스템 도입

    Feat: 던전 전투 중 회복약 사용 기능 구현
    - 던전 전투 중 회복약 사용 기능 구현, isUseItem를 true상태로 주어 활성화.
    - 아이템 이름 [물]을 [회복약]으로 수정

    Feat: 전투 중 치명타, 몬스터회피 실적용

     

    그리고 오늘부터 알고리즘 문제를 풀어 하루 하나 이상씩 제출을 하는 시간을 갖게 되었는데, C#문법에서 헷갈리는 게 많아 많이 찾아보았는데, 이에 관해서도 이후에 문제를 다시 훑어보며 헷갈리는 부분을 정리 해 두면 좋을 것 같다.

     

    3. 과제에 대해

    - 디자인에 신경쓰며 팀 과제 개선해나가기

     

    4. 참고자료

    - 없음

     

    반응형
    COMMENT
     
    01
    10

    과정명 : 내일배움캠프 Unity 게임개발 3기

    전체진행도 : 13일차

    부분진행도 : Chapter2.2 - 2일차

    작성일자 : 2024.01.10(수)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    콘솔 텍스트 던전 RPG 게임의 팀 과제 진행중.

    구현할 기능별로 역할을 분담하여 진행하는 방식을 택하였다. 수정할 파일이 서로 겹치는 경우가 빈번할 것 같아 Merge도중 충돌이 많이 일어날 것 같았는데, 걱정과는 달리 엄청 순조로운 진행을 보였다.

    나는 던전 전투 중 데미지 계산(일정 확률의 치명타, 일정 확률의 적 회피) 메서드의 작성을 먼저 맡아 완료한 후, Potion 클래스에 관해서도 새로 작성 한 후 포션과 관련된 게임 내 기능들을 작성중에 있다.

    필수적인 요소는 모두 마무리가 되어 각자 선택요소 중 원하는 기능들을 구현하고 있다.

    본인은 포션 관련한 기능을 모두 작성하면, 게임을 계속 돌려보며 디자인적으로 계속 개선해보는 역할도 맡았다.

     

    2. 오늘 학습에 대해

    오전에는 Stack, Queue, 정렬알고리즘(Quick 등)에 대한 내용의 특강이 있었다. 해당 요소들을 코드적으로 어떻게 구현하는지가 주된 내용이었는데, --index 처럼 전위연산을 수행한다던가 하는 자잘한 스킬로 구현을 더 쉽게 하는 부분이 인상적이었다. 함께 정리를 하고싶지만, 밤이 늦어 일단 팀 과제에 대한 내용을 먼저 주로 작성. 특강에 관해서는 복습한다던가 하면 이 포스트에 추가 작성을 할 것 같다.

    데미지 계산(일정 확률의 치명타, 일정 확률의 적 회피) 메서드 구현

    데미지 계산 메서드를 어떻게 구현할지 고민을 많이 하였고, 계속 정제를 한 끝에 편의성 측면에서 나름 정답을 찾은 것 같아 구현을 깔끔하게 할 수 있었다.

    public (bool, bool, int) CalculateExDamage(int originDamage, bool isSkill)
    {
        // 입력: 원래의 데미지, 스킬사용여부
        // 반환: 치명타 성공 여부, 회피 여부, 실 데미지
        
        // 반환값 목록 선언 및 초기화
        bool isCritical = false;
        bool isDodged = false;
        int calculatedDamage = originDamage;
    
        // 치명타 계산
        Random random = new Random();
        double chance = random.NextDouble();
        if (chance <= 0.15) // 15% 의 확률로 치명타 발생
        {
            isCritical = true;
            calculatedDamage = (int)(originDamage * 1.6f); // 160% 데미지
        }
        // 회피 계산
        chance = random.NextDouble();
        if (chance <= 0.1 && !isSkill) // 스킬공격이 아닐 시, 10% 의 확률로 회피
        {
            isDodged = true;
            calculatedDamage = 0; // 0의 데미지
        }
        
        return (isCritical, isDodged, calculatedDamage);
        // (bool val1, bool val2, int val3) = player.CalculateExDamage(originDamage, isSkill); 와 같이 사용
    }

    계산된 데미지 수치 이외에도, 치명타가 터지거나 적 몬스터가 회피할 경우 전투 장면 내에 이와 관련한 텍스트를 보여주어야 했기 때문에, isCritical 과 isDodged 의 반환도 필요했다. 즉 여러 개의 변수를 한번에 리턴하고 싶은상황.

    이러한 경우, 소괄호를 사용하여 return (값1, 값2, 값3); 과 같이 튜플값의 반환을 해 주는 걸로 해결을 할 수 있었다.

    매개변수로는 int의 기본공격력, bool의 스킬사용여부를 받아와, 두 변수로부터 치명타와 회피를 계산하도록 하였다.

    전투 장면에서는 아래 코드처럼 메서드를 호출, 세 개의 변수에 대입하여 사용 할 수 있다.

    (bool isCrit, bool isDodge, int calculatedDamage) = player.CalculateExDamage(originDamage, isSkill);

     

    포션 클래스 및 관련 기능 작성

    Item을 상속받는 Potion 클래스를 아래와 같이 작성했다.

        class Potion : Item
        {
            public int heal { get; private set; }
            public int count { get; private set; }
            public Potion(int id, string name, string desc, int price, int heal) : base(id, name, "체력회복", desc, price)
            {
                this.heal = heal;
                this.count = 3;
            }
            public void UsePotionOnDungeon()
            {
                // 포션 사용 구현.
                // 선택1. 플레이어 객체를 함께 받아, player.Hp += heal;
                // 선택2. heal값을 반환하여 장면 내에서 구현하기
    
                // 2번 선택. 이유가 있었는데, 밥먹다가 망각함... 곧 작성.
            }
            public void UsePotionOnInventory() => count--;
            public void GetPotion(int n) => count += n;
        }

    메인 메뉴에서 포션을 사용할 시에는 UsePotionOnInventory(), 던전 내에서 포션을 사용할 시에는 UsePotionOnDungeon() 의 메서드를 사용하도록 설계하였다. 현재 계속 구현 중인 부분이라 미완성이다.

    메인메뉴의 '회복 아이템' 메뉴로 진입하면 아래와 같은 사양의 장면을 구성한다.

    즉 당장 요구되는 사양으로는 한 종류의 포션만 구현하는 것.

    그렇기 때문에, items 배열에는 Potion클래스를 갖는 객체는 현재로써는 유일하기 때문에, 아래와 같이 FirstOrDefault() 메서드를 활용하여 포션 객체참조를 하였다.

    // 정말 만약에 Potion 객체가 shop.items에 없을 경우를 위해 대비한 로직
    // 참조 타입 변수에 null이 할당될 가능성이 있을 때 나오는 경고문 때문에 아래와 같이 라인 수 많아짐.
    Potion? potion = shop.items.OfType<Potion>().FirstOrDefault();
    if (potion != null)
    {
        Console.WriteLine($"포션을 사용하면 체력을 30 회복 할 수 있습니다. (남은 포션 : {potion.count}개)");
    }
    else
    {
        Console.WriteLine("게임에 포션이 구현되지 않아 갯수를 표시 할 수 없습니다.");
    }

    또한 아래와 같이 두줄 작성도 가능하긴 하였지만, 위 코드의 주석에도 적혀있듯 참조 타입 변수에 null이 할당 될 가능성이 있으면 보기 좋지 않은 경고문이 나오기 때문에 코드가 길어지더라도 위와 같이 작성하였다.

    또한 아래처럼 작성하더라도 items에 Potion객체가 하나도 없다면 "0"을 출력할 것이기 떄문에 큰 문제는 없을 것으로 보인다.

    Potion potion = items.OfType<Potion>().FirstOrDefault();
    Console.WriteLine($"{(potion != null ? potion.count.ToString() : "0")}")

    이외로는 사양에 맞추어 여러 조건식에 따라 기능을 구현한 내용이 대부분이기 때문에 이 정도로 마무리.

     

    3. 과제에 대해

    필수 구현 사양은 모두 만족한 것으로 보이고, 선택 구현사항을 각자 또 정하여 구현중에 있다. 큰 문제는 없을것으로 보여 계속 기능을 넣고 점검을 하며 완성도를 높이는 것이 좋겠다.

     

    4. 참고자료

    없음

    반응형
    COMMENT