전체 글 (201)

  • 2023.12.30
  • 2023.12.29
  • 2023.12.28
  • 2023.12.27
  • 2023.12.26
  • 2023.12.22
  • 2023.12.21
  • 2023.12.09
  • 2023.12.08
  • 2023.12.06
  • 2023.12.06
  • 2023.12.05
  • 12
    30

    Pyinstaller 을 사용하여 실행파일을 만들 경우 아래와 같은 OSError: [WinError 225] 에러가 발생하였을 경우, 

    - OSError: [WinError 225] 파일에 바이러스 또는 기타 사용자 동의 없이 설치된 소프트웨어가 있기 때문에 작업이 완료되지 않았습니다
    
    - win32ctypes.pywin32.pywintypes.error: (225, '', '파일에 바이러스 또는 기타 사용자 동의 없이 설치된 소프트웨어가 있기 때문에 작업이 완료되지 않았습니다')

     

    Windows Defender에서 해당 프로젝트 폴더를 검사 제외 목록에 추가하여 해결한다.

    설정 > 업데이트 및 보안 > Windows 보안 > 바이러스 및 위협 방지 > 바이러스 및 위협 방지 설정 > 제외

     

     

     

    반응형
    COMMENT
     
    12
    29

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

    전체진행도 : 6일차

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

    작성일자 : 2023.12.29(금)

    개발일지 목록 : 클릭


    1. 진행중인 과정에 대해

    캠프에서 새로운 팀 편성을 하였다. 1인 개발자, 회사생활 등 경험이 많은 팀원분들이 많으셨다. 약간 쭈글이 모드.

    이번 팀은 2주간 유지된다. 첫 주는 C# 강의와 함께 개인 과제를 위주로 학습하고, 후반 주차는 첫 주에 한 내용을 바탕으로 팀 프로젝트를 진행하여 더 심화된 결과물을 만든다. 이번 과정에서는 Unity는 사용하지 않고 C#만을 사용하여 텍스트로 진행하는 RPG게임이다.

     

    2. 오늘 학습에 대해

    오늘은 학습 시간을 활용하여 C# 강의를 들었다. Unity에서 사용하던 메서드와도 미묘하게 다르고, 다른 언어와도 혼동되는 코드들이 많기 때문에 참고가 될 만한 내용을 정리한다.

    개발 IDE 환경에 대해

    - Visual Studio Installer에서 설치 시에, C#과 동시에 .NET 프레임워크도 설치한다.

    - 솔루션에서 프로젝트 생성 시 [최상위 문 사용 안함]에 체크하여도 무방하다.

    C# 코딩에 대해

    - 나중에 기억하기 힘들 것 같은 literal의 예시 몇 가지

    - 정수형 리터럴
        - 0x10 (16진수 int)
        - 0b10 (2진수 int)
        - 10L (long)
        - 10UL (unsigned long)
    - 부동소수점형 리터럴
        - 3.14 (double)
        - 3.14f (float)
        - 3.14m (decimal)
    - 문자형 리터럴
        - '\u0022' (유니코드 문자)
    - 문자열 리터럴
        - @"문자열 내 개행 문자
        사용하기"

    - 의외로 되는 변수 관련 코드

    int num1, num2, num3 = 10; // num1과 num2는 선언만 된 상태, num3에는 10을 저장
    
    num1 = num2 = num3 = 30; // num3에 30, num2에 30, num1에 30을 저장

    - 코드 컨벤션 몇 가지

    식별자(Identifiers) : 변수, 메서드, 클래스, 인터페이스 등에 사용되는 이름
    식별자 표기법
    - PascalCase: 클래스, 메서드, 프로퍼티 등에 사용
    - camelCase: 변수, 매개변수, 로컬변수 등에 사용
    - 대문자 약어: ID, HTTP, FTP 등 특수한 경우에 사용
    - snake_case : Python에서는 변수나 함수명으로 사용했으나 C#에서는 사용하지 않는 것으로 보임

    - 문자열 관련 메서드 몇 가지

    // 구분자를 통해 문자열 나누기
    string input = Console.ReadLine();
    string[] strs = input.Split(' ');
    
    // 문자 'H'를 5개로 구성된 문자열 생성
    string str1 = new string('H', 5);
    
    // 문자열에서 검색하여 인덱스 반환
    string str2 = "Hello, World!";
    int index = str2.IndexOf("World"); // 7
    
    // 문자열 치환
    string str3 = "Hello, World!";
    string newStr3 = str3.Replace("World", "Universe");
    
    // 문자열을 숫자로 변환 시에는 Parse() 사용
    string str4 = "123";
    int num1 = int.Parse(str4);
    
    // 숫자를 문자열로 변환 시에는 ToString() 사용
    int num2 = 123;
    string str5 = num2.ToString();
    
    // 문자열 대소 비교
    // ASCII 비교가 되며, -1/0/1 중 하나를 반환.
    // 첫 매개변수에서 둘째 매개변수를 뺀 값이라고 기억하면 좋음
    string str6 = "Apple";
    string str7 = "Banana";
    int compare = string.Compare(str6, str7); // -1
    
    // 문자열 포맷팅 : 문자열 형식화
    string name = "John";
    int age = 30;
    string message1 = string.Format("My name is {0} and I'm {1} years old.", name, age);
    
    // 문자열 포맷팅 : 문자열 보간
    string message2 = $"My name is {name} and I'm {age} years old.";

    이상 기억하면 좋을만한 내용 정리.

     

    3. 과제에 대해

    주어진 C# 문법 강의의 1/3정도를 완료하였다. 강의 수강을 하루이틀 정도에 마친 후, 이번주차에 주어진 개인과제를 확인할 예정이다. 개인과제 제출의 기한은 7일 뒤인 23/1/5(금) 19:00까지. RPG게임 하나를 만드는 과제이기 때문에 꽤 시간이 걸릴지도 모르겠다.

    반응형
    COMMENT
     
    12
    28

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

    전체진행도 : 5일차

    부분진행도 : Chapter1 - 5일차

    작성일자 : 2023.12.28(목)

    개발일지 목록 : 클릭


    0. 글 작성에 앞서

    카드 뒤집어 매칭하는 게임에 대해 5인으로 구성된 팀 활동으로 4일간 여러가지 기능 구현을 마친 후 오늘 프로젝트 발표회를 하였다. 팀 내에 불화는 없었고 모두 열심히 참여하여 나름 순조로운 엔딩이 되었다.

     

    1. 진행중인 프로젝트에 대해

    어제 발표시연 녹화영상과 레파지토리 주소를 제출한 후, 어제 남겨졌던 한개의 버그를 오후 2시의 발표 전까지 고치는 작업을 하였다. 대부분의 시간을 소비하여 버그는 고쳐졌고, 그 외 난이도별로 주어지는 시간 설정을 다르게 하거나, 결과로 얻어지는 점수의 스펙트럼을 계산하는 등 발표자에게 참고가 되면 좋을 내용들에 대해 작업하였다.

    발표회에서는 총 11개 팀이 발표를 하였는데, 게임에 구현된 참신한 기능부터 임팩트 있는 발표자료까지 배울 점이 많았다.

     

    2. 오늘 학습에 대해

    발표를 보며 추가했으면 좋았다고 생각한 기능들

    • 저장된 점수 초기화 버튼
    • 사운드바로 음량 조절(데이터 저장하여 게임 재시작 시에도 사용)
    • 시연 발표 시에도 안 그래도 너무 큰 사운드 작게 조절 할 수 있어서 좋은듯
    • 잠긴 스테이지는 자물쇠 아이콘, 다음 난이도 해금 조건은 이전난이도의 ‘클리어’로 하는 게 좋았을 듯
    • 엔딩 크레딧
    • 게임을 진행하여 모으는 재화 시스템
    • (튜터 코멘트) : 남은 시간 표시는 자릿수를 맞추면 좋겠다고 하는데, 남은 시간이 008.97 이렇게 뜨면 보기 좀 별로일 것 같아서 동의는 못하지만 다른 항목의 디자인적 부분으로는 참고 OK.

    발표준비에 도움이 될 내용들

    • 본인이 발표 담당이 아니더라도 따로 녹화 해 보기
    • 발표 연습도 되고, 본인 채널에 따로 업로드하여 포폴로 쓰기 좋을 듯
    • 좋은 느낌의 임팩트 있는 PPT
    • 피드백을 즉각 메모하는 습관
    • 시연을 할 때 보이스 채우기
    • (튜터 코멘트) : 겪은 문제와 그에 대한 해결에 무게를 두어 발표하는 것을 추천. 면접관들 입장에서의 면접자들의 결과물이 그게 그거임. 물음표를 던질 수 있고 성장할 수 있는 개발자를 선호.

     

    3. 과제에 대해

    내일 새로운 팀을 구성하고, 앞으로 2주 간 심화 강의를 들으며 학습을 한다고 들었는데 팀 프로젝트도 병행하는 듯 하다. 첫 주차의 프로젝트를 잘 정리 해 두고 남은 학습 기간 중에도 많이 배워가는 것이 과제.

     

    4. 참고자료

    - 어제 팀원이 녹화한 시연 영상 : https://www.youtube.com/watch?v=HXZUXY8e5dA

    반응형
    COMMENT
     
    12
    27

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

    전체진행도 : 4일차

    부분진행도 : Chapter1 - 4일차

    작성일자 : 2023.12.27(수)

    개발일지 목록 : 클릭


    0. 글 작성에 앞서

    아침에 일어났다가 다시 잠들어 20분 지각하였다. 하루종일 피곤해서 머리가 잘 안돌아갔기 때문에 팀 소통에 영향을 끼쳤을지 모르겠다. 어제까지는 그래도 순조로웠는데 오늘은 버그 픽스 하나에 여러명이 몰려 좀 미묘한 상황이 되어버려 에너지를 많이 써버렸다. 캠프 시작 후 작은 첫 내적 위기.

     

    1. 진행중인 프로젝트에 대해

    디자인적인 개선은 전혀 기대하지 않았었는데, 팀에 그림 능력자가 두 명이나 있어 배경과 카드 이미지 등을 새로운 리소스로 교체하였다. 발표 담당의 팀원도 혼자 척척 준비하시는 듯. 나는 코딩 열심히 해야겠다.

    기능 구현 중 카드를 뒤집는 상황에서, 생각할 수 있는 다양하고 참신한 버그가 많이 터져 두 세명이 달라붙어 버그수정을 하였는데, 같은 코드파일을 만지고 있어서 그런건지 뭔가 심리적 거부감이 심했다. 내가 괜한 오지랖을 부리는건가 싶은 느낌도 자주 들고 그랬기 때문에 결과에 크게 영향을 끼치는 사안이 아니면 그냥 조용히 두고 보는 게 낫다고 생각했다. 그리고 분명 여러 테스트케이스로 테스트를 해보는데도 main에 병합하면 왜인지 모르겠는데 의문의 또 다른 버그가 생기고 그랬던 것도 피로도 상승에 한몫 했다.

    개인 프로젝트라면 사소한 버그도 불을 켜고 잡아낼텐데, 소통이라는 행위 자체에 너무 기가 빨리는 내 모습을 보면 역시 1인개발자가 맞지 않나 싶은 생각이 또 들었다. 물론 회사에 입사하고나면 잘 마련된 체계가 있을 것이기 때문에 이렇게까지 에너지를 쓸 것 같지는 않다.

    이번 주차의 프로젝트는 사실상 3~4일짜리였고 완벽한 게임을 요구하지는 않을 것이기 때문에 결과물 제출은 크게 문제가 없다. 발표 시연 영상의 준비는 한 명이 자진해 맡아주셔 잘 제작해주고 있는 것 같아 나머지 인원은 현재 숨을 돌리는 중.

     

    2. 오늘 학습에 대해

    코딩 부분은 오늘도 새로운 것을 배우진 않았다. 팀 활동과 Git 관련해서 경험치를 쌓은 편.

    팀 프로젝트의 역할 분담

    파트(분야)를 확실하게 분리한 곳에서는 트러블이 일어날 일이 매우 적다는 것을 다시 느꼈다. 그림이나 BGM, 그리고 발표준비는 인원배치가 확실히 되어 문제가 생겨도 독립적인 공간에서 해결을 하면 되는데, 코딩과 씬 관리는 전체가 관리하고 기능구현을 적당적당하게 분배해서 작성했기 때문에 이런 점에서 어려움이 컸다. 조금 더 구체적으로 역할분배를 하면 결과물이 좋을 것 같다고는 생각이 들지만, 코딩교육이기 때문에 어쩔 수 없는 부분이긴 하다.

     

    3. 과제에 대해

    - 내일 시연발표까지 남은 시간동안 가능한 버그 고치기

     

    4. 참고자료

    - 없음

    반응형
    COMMENT
     
    12
    26

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

    전체진행도 : 3일차

    부분진행도 : Chapter1 - 3일차

    작성일자 : 2023.12.26(화)

    개발일지 목록 : 클릭


    글 작성에 앞서

    팀 프로젝트를 하며 깃 사용법과 병렬 개발을 하며 생기는 트러블에 대한 경험치를 열심히 쌓고있다. 특이사항은 없음.

     

    1. 진행중인 프로젝트에 대해

    카드를 뒤집어 같은 카드를 맞추는 게임을 개발 중, 느긋하지만 순조로운 분위기로 5인 팀 프로젝트중이다.

    이미지 리소스를 한번 갈고, 카드 애니메이션에 관한 기능구현을 마친 후, 마지막으로 시연 녹화를 한다면 일단 최종제출의 요구사항은 종료이다.

     

    2. 오늘 배운 내용에 대해

    게임 내적 코딩에 대해 새로운 내용은 없었고, 자잘한 버그픽스를 많이 했다. 모두 코드 내적으로 새로운 변수나 조건문을 쓰거나 라인 순서를 바꾸거나 등으로 해결 가능했다.

    Github와 Github Desktop 사용이 아직 미숙하다. main 브런치에 merge를 끝낸 팀원이 작업한 내용을 내 브런치로 가져오는 기능을 오늘에서야 발견하였다. 그리고 Conflict가 난 부분을 어제는 제대로 해결하지 못하고 결국 스크립트파일을 새로 작성하기도 했었는데, 오늘은 제대로 Atom Browser를(왜인지는 모르겠지만 기본 브라우저로 Atom이 설정되어 있었다) 열어 필요한 코드만을 남기고 저장 및 종료하여 Conflict를 해결하였다.

    깃허브에서는 Pull Request 만 계속 요청하고 기다렸는데, Conflict 안내가 따로 없다면 merge까지 한 후에 팀원들한테 알리면 된다고 하여 밀렸던 commit들을 모두 merge하였다. 레파지토리에 문제가 생길까봐 조심조심 하는 중.

    일단 발견한 버그들은 모두 fix하였고 내일 마무리 작업을 하게 될 것 같다.

     

    3. 과제에 대해

    - 카드 뒤집기 게임 최종확인

    - 시연 발표에 대한 회의와 준비

     

    4. 참고자료

    - 없음

    반응형
    COMMENT
     
    12
    22

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

    전체진행도 : 2일차

    부분진행도 : Chapter1 - 2일차

    작성일자 : 2023.12.22(금)

    개발일지 목록 : 클릭


    글 작성에 앞서

    1주간의 팀 프로젝트인데 다시 보니 시간이 넉넉치 않았다. 월요일은 성탄절이라 쉬는날이어서, 오늘, 화요일, 수요일 중에 기능개발을 완료하고 수요일 21시까지 시연 녹화본을 포함하여 최종 제출을 해야한다.

    생각보다 오늘 진척이 잘 되었다. 오전은 다들 비몽사몽인 것 같긴 했는데, 11시에 있었던 git 실시간 강의를 듣고, 모여서 바로 github 레파지토리를 만들고 각자 기능개발에 착수했다. 팀장 맡으신 분이 경험이 있으신지 가이드를 잘 해주신다.

    노션 팀 스페이스도 열심히 갱신중

     

    1. 진행중인 프로젝트에 대해

    기본적인 카드 뒤집기 게임에 14가지 개선사항을 적용하는 것이 우선 목표이고, 5명이 약 3개정도씩의 기능구현을 맡았다.

    - 난이도별 최고점수를 보여주는 스테이지 선택 씬 구현, 순차적인 난이도 해금 시스템 구현

    - 난이도가 높아질수록 많은 카드가 나오게 하기

    - 카드 섞는 알고리즘 새로 짜기

    새로운 씬 구성은 예상은 했지만 생각했던 것보다 훨씬 많은 시간을 소모했다. 그 외의 알고리즘 관련된 내용은 열배는 더 빠르게 끝낸 듯.

    새롭게 사용한 유형의 코드는 아래와 같다.

    씬이 전환되어도 오브젝트를 유지

    DontDestroyOnLoad(gameObject);

    난이도 선택 씬에서 선택한 난이도를 오브젝트에 저장하고, 해당 오브젝트는 다른 씬으로 이동해도 파괴되지 않는다.

    데이터 불러오기와 저장

    easyScore = PlayerPrefs.GetFloat("EasyScore", 0f); // 로드
    PlayerPrefs.SetFloat("EasyScore", 100f); // 저장

    EasyScore라는 데이터가 저장되어있지 않다면 0f를 사용한다. 해당 데이터는 게임을 종료해도 보존된다.

    카드의 선정과 배치는 난이도 조건에 따라 반복문 등을 다르게 구사하여 구현한다.

    맡은 기능 개발은 모두 구현하고 Pull Request를 하였다. 팀으로 Github를 사용하는 것은 처음이었기 때문에 계속 헤맸다. 다른 팀원의 코드를 Pull 한 뒤에 Conflict 난 부분에서 뭔가 잘 안되어 저장이 이상하게 되어버려 그냥 충돌 난 그 파일을 새로 작성했다. 아까 보았던 Git 강의 다시 한 번 확인하고 익혀야 할 듯.

    아래는 오늘 작성한 난이도 선택 씬이다.

     

    2. 과제에 대해

    - 팀원들이 남은 기능구현을 마치고 모두 Merge 끝내기

    - 세세한 코드 수정과 디자인적 요소 개선

    - 시연 준비(시연할 팀원 정하기, 녹화와 발표)

     

    3. 참고자료

    - 오늘 특별히 찾아본 중요한 자료는 없는 듯

    반응형
    COMMENT
     
    12
    21

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

    전체진행도 : 1일차

    부분진행도 : Chapter1 - 1일차

    작성일자 : 2023.12.21(목)

    개발일지 목록 : 클릭


    글 작성에 앞서

    본 캠프 첫째 날, 아침 9시에 OT를 진행하고, 점심시간 전에 팀 배정이 확정되어 활동을 시작했다.

     

    OT 내용 정리 : 커리큘럼에 대해

    2023.12.21 ~ 2024.05.02 약 5개월간의 훈련 일정. 훈련 2개월째에 접어들면 알고리즘 학습도 병행한다.

    매일 팀 개발을 하며 배운 내용을 정리하는 TIL(Today I Learned)과, 매주 WIL(Week I Learned)을 기록한다.

    하루일정은 오전 9시 ~ 오후 9시이며, 진행 중 두 시간은 식사시간.

    출결 기준은 ~5:59 결석, ~11:59 조퇴, 12:00~ 출석이며 3회의 외출/조퇴/지각을 할 경우 1회 결석이 된다.

    부정출결 또는, 총 결석일수가 과정의 20%를 초과 할 경우 제적이 된다. 

    커리큘럼 중의 중도하차 1회는 20만원 차감, 2회는 50만원 차감, 3회 이상은 100만원 차감. 향후 5년 간 K-Digital Training 과정 수강 불가라고 한다. 또한 한 달 마다 훈련 장려금 신청하기(31만원가량 지급)도 잊지 않도록 하자.

    안내의 자세한 내용은 캠프의 Docs에서 자세히 확인 가능. 

     

    OT 내용정리 : 첫 주차 팀 프로젝트에 대해

    사전캠프 4주차 과정에서 만들었던, 늘어놓은 카드를 순차적으로 뒤집어 같은 카드 두개를 뒤집으면 삭제하는 카드게임의 연장선이다. 새로운 이미지 리소스와 개선 기능을 15개정도 더 구현한다.

    가이드라인에 맞춰 노션 팀 스페이스를 열심히 가꾸었다. 최대한 필요한것만 간략하게 남기도록 노력했다.

    가장 걱정되는 것은, 오는 주 수요일까지 시연 발표를 녹화하는 것과 목요일에 있을 진짜 발표이다.

     

    1. 진행중인 프로젝트에 대해

    사전캠프 4주차에 진행했던 '카드 뒤집기 게임'의 결과는 위와 같다.(테스트를 위해 15초 내에 성공 못할 시 종료 판정)

    5주차에 게임 시작 씬도 넣고, 효과음과 배경음도 넣고, 광고도 넣어 복잡해졌다.

    오늘은 팀 스페이스를 되도록 자세하게 작성하는 것으로 거의 하루를 보냈다. 조원간 분업이 정말 구체적으로 되어있던 다른 팀도 보였는데, 그렇게까지 전문적으로 나누기에는 우리 팀원의 스타일이 모두 비슷비슷했다.

    협업을 위해 팀원이 모두 같은 버전을 맞추고, 한 주간 진행해야 할 흐름을 작성했다. 앞으로 구현할 개선 기능들의 난이도는 크게 어렵지 않아, 대부분의 시간을 협업이라는 것에 소모하게 될 것 같다. 처음에는 머리가 새하얘져서 아무말도 못했는데, 점점 익숙해지는중.

    프로젝트의 진척에 대해서는, 리소스로 사용할 이미지를 팀원 전원이 3장씩 제출하여 모아두었고, 내일부터 코딩을 본격적으로 할 것 같다.

     

    2. 과제에 대해

    - 굳이 적을만한 구체적인 프로젝트 관련 과제는 없는데, 웹버전 노션에서, 첨부한 이미지를 삭제할 수 있는 방법을 못찾겠다. 팀 전원 헤메는 중.

     

    3. 참고자료

    - 없음

    반응형
    COMMENT
     
    12
    09

    https://www.youtube.com/watch?v=XPXXpIx0LCE

    본 프로젝트는 정말 감사하게 위 영상에서 제시해준 로드맵을 기반으로 진행되었다. 상시숭배 할 수 밖에 없어

    전체적인 흐름

    01:32 ▶ 나무위키를 pdf로 저장, GPTs에 첨부하여 참고 지식으로 사용
    01:57 ▶ 게임에서 뜯어온 마키세 음성파일에 대해, OpenAI의 whisper을 사용하여 대본 작성
    02:04 ▶ GPT store에서 검색한 prompty(GPT 세팅방법을 알려주는 GPT)에게 도움! 요청
    02:23 ▶ prompty에게 받은 내용을 번역 후 그대로 마키세 GPTs Instructions에 투입. 추후 음성 지원도 위한 일본어 대답 옵션도 추가.
    02:40 ▶ GPTs는 현재 api 지원을 하지 않기 때문에, Selenium(Chrome비슷한거)으로 직접 웹페이지에 접속해 채팅을 이어가는 설계.
    02:45 ▶ 웹앱 환경에서, 크리스의 대답중엔 '보내기' 버튼이 비활성화 되는 것을 감지하는 로직 활용, GPT에게 물어보아 셀레니움 환경 완성.
    02:55 ▶ 프로그램 UI 작성 시작. 초안을 GPT에게 던져 Python으로 UI 작성.
    03:11 ▶ 상기 작성한 일본어 대본을 사용하여 VITS(TTS AI)학습
    03:17 ▶ 셀레니움 환경에서 얻어낸 GPTs의 답변을 TTS와 결합

    보면 생략된 내용도 있어보이는데, 셀레니움에 대한 내용이 많이 나오지 않았고, 일본어 대본이 아닌 한국어 대본을 어떻게 준비하였는지도 알 수 없으며, 실시간으로 UI에 텍스트가 자연스럽게 나오는 방법도 알 수 없다. 텍스트 갱신과 관련해서는 OpenAI API 다룰 때 보였던 설정과 비슷한건가 싶긴 한데 나중에 찾아봐야겠다.

    초기 준비물 확인

    나무위키 PDF / 크리스 음성파일 → 대본 파일

    게임은 이미 구매했었고, ChatGPT도 지금 가입이 막혔다고 하는데 이미 유료 구독중이라 문제 없다.

    슈타인즈 게이트 보이스 파일 준비

    슈타인즈 게이트 언팩에 관해서는 https://github.com/rdavisau/sg-unpack 의 힘을 빌렸다. 스팀판 이전의 슈타인즈 게이트 정보와 스팀판의 슈타인즈 게이트 정보가 인터넷에 뒤섞여있는데, 예전의 Voice 리소스파일은 NPA 확장자를, 현재는 MPK 확장자를 사용하고 있다. 듣기로는 크게 다를건 없긴 하다는데 Unpack 같은 키워드의 부재로 깃허브 페이지를 찾지 못하면 인터넷에서 한참을 헤멘다.

    스팀 라이브러리 우클릭해서 로컬 폴더를 찾아들어가 경로를 확인한 후, 깃허브 페이지에 친절하게 나와있듯이 명령어 한번으로 쉽게 보이스 파일을 얻을 수 있다. 아래는 cmd에서 입력 예시.

    sg-unpack.exe -i F:\SteamLibrary\steamapps\common\STEINS;GATE\USRDIR\voice.mpk -o C:\Users\happy\Desktop\codes\Amadeus

    sg-unpack.exe -i "F:\SteamLibrary\steamapps\common\STEINS;GATE 0\USRDIR\voice.mpk" -o C:\Users\happy\Desktop\codes\Amadeus\zero

    친절하게도 파일 이름이 이름_번호 로 되어있어 원하는 사람만 빼오기 좋다.

    슈타인즈 게이트 대본 준비

    문제는 이제 Whisper를 사용하여 음성을 대본으로 바꾸어줘야 한다는 것인데, 좋은 모델을 쓰려면 컴퓨터 사양이 말도 안되게 높아야 한다.

    그래서 구글 코랩의 힘을 빌리기로 했다. 이것도 유료 이용중이라 제한 걸리는 등의 문제는 없을 것.

    여러 자료를 찾아보는데, 지금도 잘 작동하고 있는 https://maily.so/dailyprompt/posts/86dd50cc 이 가이드를 따라갔다.

    일단 제대로 대본이 나온다는 것은 확인되었고, 야수의 심장으로 WebUI에 3천개 가량의 파일을 한번에 드래그 해 놓았다. 업로드를 기다리는 중이다. 업로드가 끝나면 Generate 버튼을 눌러 대본을 생성하는데, 코랩 노트북 페이지의 파일시스템 중 outputs 폴더에 대본이 생성된다. 왠지 전체선택 다운로드라는 선택지는 없어보였기 때문에 3천개의 대본을 압축 후, 다운로드 받을것이다.

    WebUI에 너무 많은 파일을 업로드하면 잘 작동하지 않아, 파일을 600개씩 업로드하는 걸로 타협하였다. WebUI의 설정에서 Japanese 와 txt 출력을 제대로 선택하여, 약 3800개 정도의 대본을 생성했다. 2900개의 origin 대본을 생성한 후, Colab 에서의 코딩을 통해 압축을 하여 다운받아주고, 이어서 900개정도 되는 zero의 대본도 작성후 압축 및 다운로드 하였다.

    또한 바로 다음과정인 Prompty에 첨부하기 위해, 파이썬 프로그램을 작성하여 모든 텍스트 파일을 한 개의 텍스트파일 '대본.txt'로 병합하였다.

     Prompty를 통한 GPT봇(마키세 크리스) 세팅 

    Prompty는 GPT를 세팅하거나 질문하는 법에 대해 알려주는 GPT이다.

    GPT Store 에서 prompty를 검색하고, Try Prompty를 눌러 사용을 시작한다. 영상과 같이 두 개의 파일을 첨부하여 질문하였다.

    GPT의 답변은 복사하는 버튼이 있어 그 버튼을 통해 내용을 복사해도 되지만, 영상에서는, Prompty의 답변을 직접 드래그로 긁어 DeepL 번역기로 한글 번역을 하여 크리스 봇에 세팅하였다.

    두 복붙 방법의 장단점이 있는데 아래와 같다.

    위 내용은 복사버튼을 통해 내용을 가져온 경우이다. 빨간색 테두리를 친 부분은 답변 내용에 보이지 않았던 필요없는 부분인데, 같이 복사가 된다.

    반면에 답변을 전체 드래그해서 복사를 하게 되면 빨간색 테두리를 친 부분은 보이지 않지만, 파란색 테두리로 표시한 제목을 의미하는 ### 나 OL과 UL을 나타내는 숫자나 기호도 모두 누락이 되기 때문에 문제가 되었다.

    내 경우에는 복사버튼을 통해 내용을 가져와 필요없는 부분을 모두 지워주는 방향을 택했다. 사실 이렇게 세세하게 하지 않아도 잘 작동할 것 같긴 하다. 그리고 '쿠리수'는 '크리스'로, '스타인즈' 는 '슈타인즈' 로 바꿔주던가 하는 세세한 작업도 하였다.

    영상에서 언급한, 일본어와 한국어 양쪽으로 답할 수 있도록 재현해 보았다. 사실 Prompty의 답변이 갈린 시점부터 영상과 유사하게 진행하는것은 어려워졌는데, 어설프게 따라했더니 챗봇에게 아래와 같은 답변을 받았다.

    첫 답변만 제외하고는 나름 괜찮게 되었다.

    참고로 영상에서의 챗봇은 아래와 같았다.

    추후에 대화창 UI에 띄우는 내용은 아마 한글 번역쪽이 되는 듯 하다.

    Selenium(셀레니움)을 통한 연결

    영상에 언급되기를

    'GPTs는 api가 따로 없기 때문에(assistance : 기존 GPT 커스텀 기능 - 어려움, 유료) Selenium으로 api(물리)를 구현 할 예정' 

    라는 내용이 있어, Selenium을 사용한다고 한다.

    지금까지 사용 해 온 GPT의 API는 이전 대화를 기억하지 못하는 일회성 API였기 때문에 매번 호출을 할 때마다 챗봇의 세팅과 과거 로그를 모두 추합하여 요청을 보내야하는 문제점이 있고 비용문제도 확실히 커지게 된다.

    과거 Selenium을 사용하여 ChatGPT 페이지를 사용하기 위해 긴 시간을 들여 구글로 로그인하는 문제를 어느정도 완화는 했었다. 기본적으로 봇이 가동중인 웹브라우저는 구글로그인에서 막히기 때문에 외부라이브러리를 사용하여 셀레니움에 약간의 조작을 할 필요가 있었다. 그리고 아이디/패스워드만으로는 구글로그인을 시켜주지 않기 때문에 직접 휴대폰에서 확인을 한번 해주어야 로그인이 되는 것이 그 때의 최종 문제였다.

    현재 커스텀 GPTs를 공개 공유링크로 접속해보면, ChatGPT Plus 구독이 필요하며 로그인 버튼이 뜨기 때문에, 위의 로그인 과정은 필요한 것으로 보인다. 아마 영상에서의 셀레니움은 Visual Novel UI 구동과 함께 셀레니움이 동시에 실행되며 그 시점에 최초로 로그인을 한번만 하면 이후 계속 켜져있는 상태로 보인다. 일단 영상에 보이는 상태로는 그렇게 예상되는데, 내 경험에는 셀레니움과 Visual Novel UI(QT인가 싶었는데 코드를 보면 아닌가 싶기도)에서 스레드 점유 문제가 있지 않나 생각되어서 지금 시점에서는 어떻게 될지 모르겠다. 지금껏 그래왔던 것처럼 시간을 갈아넣으면 어떻게든 되지 않을까.

    영상을 살펴보는데 파일구조는 아래와 같다.

    ?????NT.py
    ChatWaifu.py
    ChatWaifu_Modified.py // 위 파일을 개선한듯
    chromedriver.exe
    CombinedChatGPTScript.py
    CombinedChatGPTScript_Full.py // Full과 아닌 코드의 차이점은 모르겠다. 230라인으로 이루어짐. GPT의 대답을 가져옴.

    ChatWaifu_WithInputHandling.py // 가장 마지막 단계에 커스텀UI와 셀레니움을 결합하는데에 사용

    (단계 완료 후 이어서 작성)

    남은과제 : 셀레니움 환경 갖추기 / TTS 변환 모델 작성하기 / UI구성(간단하게는 만들었지만 위 영상처럼은 어떻게 만들었는지 신기함 텍스트 표시 방식 등)

    반응형
    COMMENT
     
    12
    08

    클라우드 타입 구독 시스템(유료화) 도입

     그렇게 긴 기간은 아니었지만 디스코드 봇 배포에 특히 도움을 받은 클라우드타입이, 계속된 업데이트를 거쳐 구독기능이 생기게 되었다. 예정된 날짜는 2023년 12월 7일(목)이고, 지금까지 무료로 사용 가능했던 기능이 일부 제한을 당한다.

     어떤 기능들이 있었는지는 대부분 신경쓰지 않았지만, 앞으로 무료 버전 이용자는 매일 실행되고 있는 서비스가 오전 3시 ~ 9시 사이에 중지상태로 만드는 변경점은 상시로 디스코드 봇을 운영하고 있는 입장에서 서비스 종료를 할 수밖에 없다.

     클라우드타입의 최소 구독 요금은 월 9,900원으로 적지도 많지도 않은 금액이라고 개인적으로는 생각하는데 다른 플랫폼을 사용한 경험이 없어서 비교는 어렵다. 다만 디스코드봇을 운영함으로써 상시로 서버에서 작동가능한 봇이 매우 활용도가 높다는 점, 플랫폼이 굉장히 깔끔하게 만들어졌다는 점, 기능적인 부분에서 필요하다고 느낀 대부분을 지원한다는 점 등으로 일단은 계속 정착하기로 결정했다.

    동료 디스코드 봇 기능 흡수

    같은 디스코드 서버에서 함께 클라우드 타입을 사용해 봇을 운영하던 동료분은 봇 운영을 중단한다고 하셔 양해를 구하고 갖고 있던 봇 기능을 이쪽에 도입하기로 했다. 

    - !듀얼 : '하이', '미드', '로우', '역미드' 네가지 규칙 중 하나를 선정해준다.

    - !주사위 : 0~100 사이로 주사위 굴려줌

    - !환율(미세개량) : 엔화 및 달러 환율을 알려준다. 숫자나 단위 함께 쓰면 계산도 해줌. 가독성 측면에 신경써서 개량했다.

    - !날씨(개량) : 오늘부터 5일 뒤까지의 날씨를 예보해준다. 대충 찍는 건 아니고 tomorrow.io 의 API를 사용했다. 나름 응답받은 자료로 여러가지 정보를 도출해내어 사용자에게 알려준다. 랜덤 이모지 함수도 만들어 환율 명령에도 여기에도 소소하게 사용 해 보았다.

    tomorrow.io 날씨 API에 요청을 할 때, 좌표가 아닌 지역이름으로 요청을 할 수 있다는 것을 오늘 처음 알았는데, 이게 심상치가 않다.

    오타만 아니라면 왠만한 입력은 다 통과했다. 엄청 시골의 면 단위까지도 지역 입력으로 가능했다. 처음에 예시로써 'seoul'을 사용하는 것을 보고, '아아, 영어로 대도시단위로 틀리지 않고 똑바로 써야 응답해주겠구나' 싶어서 들어오는 입력에 lowcase() 함수도 붙여가며 소문자로 만들어주고 했었는데 헛짓이었다. 아무튼 신기했다. 일단 특수문자랑 공백문자는 모두 제거하고 판단하나보다.

    새로 다루는 API이고 기능적으로도 준비하고 싶은 게 많아 하루 내내 여기에 시간을 썼다.

    동료 봇 은퇴식

    실시간으로 채널에 있었던 네명정도 머리에 나사 반정도 풀고 헛소리했다.

     

     

    반응형
    COMMENT
     
    12
    06

    개발일지 목록 : 클릭

     

    학습 내용에 대해

    3주차는 리소스 스프라이트가 주어지고, 별도의 Start Scene을 구성하기 등을 배웠다. 4주차는 gameManager 스크립트가 게임의 대부분을 구성하는 같은 그림 찾기 보드게임을 만들었다. 게임 로직에 특히 신경 쓸 부분이 많았다. 5주차는 4주차에 만들었던 보드게임에 효과음과 배경음 넣기, 빌드세팅, '게임 재시작' 단계에 광고 넣기 등 까다로운 부분을 다뤘다.

    전체적으로 익숙해지는 느낌이라 학습 정리는 크게 하지 않았고, 5주차에 실습한 내용들이 유니티의 매 프로젝트마다 까다롭다고 생각되는 부분이다. 강의자료의 '광고 넣기' 파트는 예전의 자료였기 때문에 많이 달라져 작동하지 않아 최신 문서를 찾아가며 적용하였다. 현재 Unity Ads를 넣는 방법과 예제 코드는 아래 노션 페이지에 정리 해 두었다. 또한 빌드 시 해상도가 맞지 않을 시 화면을 빠져나가는 자잘한 버그도 스크립트 수정을 통해 해결하였다.

    Unity Ads 사용 가이드(2023.12.05)

    유니티 화면 밖으로 내용이 삐져나가는 경우를 방지한 해상도 비율 고정 스크립트 작성

     

    사전캠프 과정을 미리 마치며

    유니티를 처음 시작하는 사람도 많이 참여하는 캠프이기 때문에, 전체적으로 분량과 난이도가 크게 어렵지 않았고 복습 및 익숙해진다는 느낌으로 빠르게 종료하였다.

    남은 사전캠프 기간은 지금까지 모아둔 레퍼런스를 구현하며 공부 해 나가려고 한다.

     

    이하 현재 메모한 레퍼런스들

    1. (단기, 약 24시간~30시간 정도 예상) 아마데우스 프로젝트

    https://www.youtube.com/watch?v=XPXXpIx0LCE

    짧은 영상 안에 요즘 트렌드들을 신랄하게 압축 해 놓은 프로젝트이다. 매우 유익한 로드맵을 작성해 준 영상 제작자에게 감사하며, 이 과정을 그대로 진행 해 보기로 생각했다. 슈타인즈 게이트 전 시나리오를 아마 다섯 번 이상 정주행했고(생각나면 찾아봄) 특히 아마데우스 파트는 다른 에피소드와 비교해 윤리 문제를 비롯한 수많은 감정선이 얽혀 있어 미묘한 기분을 느낄 수 있었기 때문에 이 프로젝트에 더욱 관심이 갔다. 해당 영상의 댓글란에 타임스탬프와 함께 기술적인 요소를 함께 적어놓았기 때문에 매번 참고할 수 있다.

    시작하기 전에, 기술적인 부분은 2분정도로 짧게 다루어지지만, 이 중 한개의 스킬에서 이미 큰 시행착오를 겪은 경험이 있기 때문에 모든 과정을 구현하는 데에는 아마 시간이 오래 걸릴 것으로 생각된다. 

    영상 작성자가 보여준 완성작은 소설 내 아마데우스와 본질적으로 크게 다르지 않을까 생각된다. 소설의 아마데우스는 인간의 기억으로부터 학습된 언어모델이고, 영상 제작자의 아마데우스는 게임 등장인물의 모든 음성파일 대본 즉 일부 생활패턴을 학습시킨 언어모델이다. 음성인식 기능 그리고 현재 OpenAI에서는 지원하지 않는 GPT로부터의 대화 시작 등 몇 가지 요소가 더 마련되면 더 소설 속의 아마데우스와 가까워질 것이다.

    2. (중장기 프로젝트)Unity를 사용한, 미디 파일로부터 바운스 볼 자동 생성 시뮬레이터

    https://www.youtube.com/watch?v=fagldH23oj0

    미디파일만으로 위와 같은 영상의 벽돌을 직접 배치해주는 시뮬레이터를 구상중이다.

    현재까지의 진척

    • 매번 실행을 할 때마다 유니티 물리엔진이 큰 오차를 내지 않는다는 것을 확인했다. 그렇기 때문에 한번 배치가 완료된다면 미디 파일이나 타임스케일, 공의 시작지점 등을 바꾸지 않는 이상 계속 활용이 가능하다.
    • 개발 환경의 플레이 도중 상태에서 생성된 오브젝트는, 프리펩으로 저장하면 게임을 정지해도 남겨둘 수 있다는 것을 알았다. 알고리즘을 통해 배치한 벽돌은 프리펩으로 저장하여 남길 것이다.
    • 미디파일을 필요한대로 다루는 방법을 아직 찾지 못했다. 앞으로의 진척 과제이다.
    • 기본적인 틀이 잡히면, 디자인적 요소를 더 신경쓰며 보완 해 나가야 할 것이다.
    • 이상의 내용은 하나의 탬플릿으로 사용하여, 다양한 미디와 그에 맞는 스타일링을 거친 후 각각 영상 미디어로 가공 할 예정이다. 완료한다면 유튜브에 업로드 하지 않을까

    3. GPT 둘의 상호 대화 구현

    지금 환경에서도 사람이 직접 GPT 모델 두개를 놓고 수동으로 입력을 시켜주어 양방향 대화를 이어줄 수 있기는 하다.

    셀레니움을 활용하여 이를 자동화 시켜줄 수 있을지, 프로젝트의 진척을 서로 보완해가며 사람의 도움 없이 괜찮은 결과물을 만들 수 있을지 궁금하다. OpenAI ChatGPT에는 입력해줄 수 있는 내용의 종류가 한정적이기 때문에, 처음에 어떤 프로젝트를 쥐여줄지도 고민해 봐야겠다.

    4. NovelAI 자동생성 및 업로드

    노벨AI를 매달 25달러를 주고 구독하고 있는데, 그럴싸한 아웃풋이 없어 아쉽기때문에, 셀레니움을 이용한 자동생성과 어딘가의 플랫폼에 업로드 하는 것을 자동화하는 프로그램을 짜 보고 싶다고 생각했다.

    개발자도구의 콘솔창에서 쉽게 일러스트의 자동생성은 할 수 있었기 때문에, 셀레니움에서 콘솔창 제어를 활용 할 수 있을지 확인해 보고 싶다. AI그림을 대량으로 업로드할 플랫폼이 있을지도 찾아봐야겠다.

    월 구독액만큼 뽕을 뽑을 수 있는 방법이 어디 없을까.

     

    반응형
    COMMENT
     
    12
    06

    글 작성에 앞서

    한국어 검색으로는 자료가 너무 없었기 때문에 계속 탐색중. 현재진행형이다.

    DryWetMIDI

    검색했을 때 가장 눈에 띄었던 건 무료 에셋인 DryWetMIDI 에 대한 내용이다.

    에셋을 다운로드 받아보면 몇개의 파일과 DEMO씬으로 이루어져 있다.

    DryWetMIDI의 구성

    DemoScript를 통해 대략 어떤 느낌으로 사용하면 될지 알 수 있고, [깃허브 README.md]나 [Documentation]에서 자세한 내용을 확인 할 수 있다.

    당장 확인한 내용은, DemoScene에서 제공하는 DemoScript를 그대로 사용하면 미디파일을 재생하며 콘솔에 음계를 로그로 보여주는데, 음계 로그와 동시에 오브젝트를 생성하려고 시도하면 오브젝트 생성은 메인 스레드에서만 가능하다는 에러를 보여주는걸로 보아 제대로 활용하기 위해선 다른 접근 방법을 생각해야 할 것 같다.

    또한 자세히는 모르겠지만, 미디재생을 위해 할당받은 오디오 출력 채널을 도중 에러로 인해 Release 작업 없이 종료되면 오디오 채널이 계속 점유중인 채로 남게 되어 프로그램을 껐다 켜야하는 수고가 필요했다. 다른 방법이 있을 것 같긴 한데 초심자라 잘 모르겠다. 그리고 그 외 여러가지 테스트를 해 보며 충돌이 나 유니티가 종료되는 일이 굉장히 빈번했다.

    공식문서를 자세히 보면서 익혀나가면 좋을 것 같다.

    Unity Midi Visualizer Tutorial (유튜브)

    https://www.youtube.com/watch?v=3PRifmlwi0I

    Midi 인풋을 받아오는 MidiJack 이라는 라이브러리가 있다는 것은 들었지만, 내가 본 이 영상에서는 아무래도 라이브러리를 사용하지 않는 것 같아 참고가 될까 하여 가져왔다.

    영상 제작자는 미디 키보드를 연결하여, 계이름에 맞는 오브젝트를 생성하는 스크립트를 작성한 것처럼 보인다.

    일단 메모만 해 두고 시간이되면 본 후 이 글에 정리 해 볼것.

    How to make a Rhythm Game In Unity (using MIDI) 

    https://www.youtube.com/watch?v=ev0HsmgLScg

    2023.12.07

    괜찮은 영상을 찾은 것 같다. 바로 따라 해 봐야겠다. DryWetMIDI를 이용하여 리듬게임을 만드는 방법을 설명한다.

     

    반응형
    COMMENT
     
    12
    05

    글 확인 전 참고사항

    - Unity Ads 패키지의 이름이 Unity Advertising으로 변경되었습니다. 버전 4.4.1부터는 이 패키지를 Unity 광고 레거시라고 합니다.

    - 아래의 내용은 2023년 12월 5일에 공식문서를 참고하여 유니티 2022.3.8.f1(LTS) 버전에서 정상적인 작동을 확인하였습니다.

    - [노션페이지]에서 더 나은 스타일로 글을 확인할 수 있습니다.

    Unity Ads / Unity Advertising 사용 가이드

    1. https://cloud.unity.com/ 로 접속하여 대시보드 진입
    2. 광고를 넣고자 하는 프로젝트 진입
    3. 서비스 목록 중 Unity Ads Monetization 선택하여, 광고 활성화
      1. I only plans to use Unity Ads(Unity Ads만 사용할 계획입니다) 선택 후 다음
      2. My app is not live in an app store yet(내 앱이 아직 앱 스토어에 게시되지 않았습니다) 선택 후 프로젝트 추가
      3. 본인의 경우 에러 발생 창 나왔지만, Retry 버튼 클릭하면 바로 해결.
      4. 아까 보였던 광고 활성화 버튼이 사라져있으면 OK
    4. Unity Ads Monetization 페이지에서 계속 진행. 설정 가이드 진입.
    5. 가이드에 따라 3개 스텝을 진행.
      1. Install Unity Ads SDK(Unity 광고 SDK 설치)
        1. 개발환경의 Unity로 이동
        2. Window > General > Services 진입하여, Advertisement Legacy 설치
        3. 또한 별개로 Setup Guide 페이지에서 Read integration guide 를 클릭하면 전체 가이드 공식문서가 열리며, 추후 사용할 예시 스크립트도 모두 여기에 적혀있다.
      2. Testing(테스트)
        1. 실제 광고가 아닌 테스트 광고를 사용하기 위해 필요한 절차
        2. Go to Testing 클릭하여 설정 페이지로 이동
        3. Apple App Store 와 Google Play Store 의 편집 버튼을 눌러 Override client test mode 에 체크 한 후, Force test mode ON (i.e. use test ads) for all devices 을 선택하여 모든 장치에서 테스트용 광고를 사용하도록 설정한다.
        4. 추후 실제 광고를 사용하게 된다면 여기서 다시 설정을 바꿔준다.
      3. Configure Ad Units(광고 단위 구성)
        1. 어떤 탬플릿의 광고를 사용할지 확인하기 위한 목적.
        2. Go to Ad Units 버튼 또는 왼쪽의 광고 단위 탭에 접근한다.
        3. 여기서 확인해야 할 것은 상단에 표시된 iOS 게임 ID, 안드로이드 게임 ID 그리고 하단에 나온 광고 단위 ID 이다. 필요에 따라 다른 모양의 광고를 사용하면 되며, 예시로 전면 광고 ID인 Interstitial_Android와 Interstitial_iOS를 사용 해 보겠다.
    6. 광고 적용
      1. 앱 시작 시 ‘SDK 초기화’를 필수적으로 해야하며, 이후 필요한만큼 ‘광고 유닛 표시’ 를 한다.
      2. SDK 초기화를 위해 씬에 빈 오브젝트를 하나 생성하여 아래 스크립트를 적용한다. 게임 시작 시 함께 실행된다. _androidGameId 변수와 _iOSGameId 는 5-c-iii에서 확인한 것을 기재한다.
        • AdsInitializer.cs(포스트 하단)
      3. 전면, 보상형, 배너 타입의 광고 중에 전면 광고를 넣어보자. 각 타입의 구현은 [공식문서]에서 확인할 수 있다. 아래와 같은 스크립트를 방금 생성한 오브젝트에 함께 적용한다. 게임이 시작되고 약 2초 후에 광고의 로드와 표시를 한다. _androidAdUnitId 와 _iOsAdUnitId 에는 각각 안드로이드와 iOS에서 표시될 광고의 타입(유닛)을 넣어주면 되는데, 전면광고를 예로 들면 각각 "Interstitial_Android” 와 “Interstitial_iOS”를 입력 해 주어야 한다. 광고 단위의 ID는 5-c-iii 과정에서 확인한 광고 단위 탭에서 확인 가능하다.
        • InterstitialAdExample.cs(포스트 하단)
      4. 적용하여 실행한 후 2초 뒤 모습은 아래와 같다.
        • 결과 확인

     

    7. 보상형 광고 등 이외 내용은 [공식문서]를 참고

     

    티스토리 이미지 위치 조정도 안되고, 오더리스트 타입도 설정 안 되고, 들여쓰기 내어쓰기도 안보이고, 코드블럭도 배치 안되고, 글씨 size 설정도 안보이고, 마크다운모드 다녀오면 글 전체 문단 배치가 박살나있고 왜 이러는지 모르겠다. 플랫폼 바꿔야할까 생각중

    (소스코드)

    // AdsInitializer.cs
    
    using UnityEngine;
    using UnityEngine.Advertisements;
    
    public class AdsInitializer : MonoBehaviour, IUnityAdsInitializationListener
    {
        [SerializeField] string _androidGameId;
        [SerializeField] string _iOSGameId;
        [SerializeField] bool _testMode = true;
        private string _gameId;
    
        void Awake()
        {
            InitializeAds();
        }
    
        public void InitializeAds()
        {
    #if UNITY_IOS
                _gameId = _iOSGameId;
    #elif UNITY_ANDROID
            _gameId = _androidGameId;
    #elif UNITY_EDITOR
                _gameId = _androidGameId; //Only for testing the functionality in the Editor
    #endif
            if (!Advertisement.isInitialized && Advertisement.isSupported)
            {
                Advertisement.Initialize(_gameId, _testMode, this);
            }
        }
    
    
        public void OnInitializationComplete()
        {
            Debug.Log("Unity Ads initialization complete.");
        }
    
        public void OnInitializationFailed(UnityAdsInitializationError error, string message)
        {
            Debug.Log($"Unity Ads Initialization Failed: {error.ToString()} - {message}");
        }
    }
    // InterstitialAdExample
    
    using UnityEngine;
    using UnityEngine.Advertisements;
    
    public class InterstitialAdExample : MonoBehaviour, IUnityAdsLoadListener, IUnityAdsShowListener
    {
        [SerializeField] string _androidAdUnitId = "Interstitial_Android";
        [SerializeField] string _iOsAdUnitId = "Interstitial_iOS";
        string _adUnitId;
    
        void Awake()
        {
            // Get the Ad Unit ID for the current platform:
            _adUnitId = (Application.platform == RuntimePlatform.IPhonePlayer)
                ? _iOsAdUnitId
                : _androidAdUnitId;
        }
           
        void Start()
        {
            // 2초 후에 광고를 표시합니다
            Invoke("InvokeAd", 2.0f);
        }
    
        void InvokeAd()
        {
            LoadAd();
            ShowAd();
        }
        // Load content to the Ad Unit:
        public void LoadAd()
        {
            // IMPORTANT! Only load content AFTER initialization (in this example, initialization is handled in a different script).
            Debug.Log("Loading Ad: " + _adUnitId);
            Advertisement.Load(_adUnitId, this);
        }
    
        // Show the loaded content in the Ad Unit:
        public void ShowAd()
        {
            // Note that if the ad content wasn't previously loaded, this method will fail
            Debug.Log("Showing Ad: " + _adUnitId);
            Advertisement.Show(_adUnitId, this);
        }
    
        // Implement Load Listener and Show Listener interface methods: 
        public void OnUnityAdsAdLoaded(string adUnitId)
        {
            // Optionally execute code if the Ad Unit successfully loads content.
        }
    
        public void OnUnityAdsFailedToLoad(string _adUnitId, UnityAdsLoadError error, string message)
        {
            Debug.Log($"Error loading Ad Unit: {_adUnitId} - {error.ToString()} - {message}");
            // Optionally execute code if the Ad Unit fails to load, such as attempting to try again.
        }
    
        public void OnUnityAdsShowFailure(string _adUnitId, UnityAdsShowError error, string message)
        {
            Debug.Log($"Error showing Ad Unit {_adUnitId}: {error.ToString()} - {message}");
            // Optionally execute code if the Ad Unit fails to show, such as loading another ad.
        }
    
        public void OnUnityAdsShowStart(string _adUnitId) { }
        public void OnUnityAdsShowClick(string _adUnitId) { }
        public void OnUnityAdsShowComplete(string _adUnitId, UnityAdsShowCompletionState showCompletionState) { }
    }
    반응형
    COMMENT