728x90

https://github.com/Tencent/puerts

 

GitHub - Tencent/puerts: PUER(普洱) Typescript. Let's write your game in UE or Unity with TypeScript.

PUER(普洱) Typescript. Let's write your game in UE or Unity with TypeScript. - Tencent/puerts

github.com

 

먼저, puerts는 중국 텐센트에서 개발한 라이브러리로 유니티, 언리얼 엔진의 C#, C++을 type script로 변환해서 개발할 수 있게 해주는 라이브러리이다.

PuerTSUnity/Unreal/DotNet용 다국어 스크립팅 솔루션 입니다 .

  • 🌐 다국어 지원 (Unity 3.0 신규 기능!) : JavaScript/TypeScript, Lua , Python — 팀에서 가장 생산적인 언어를 사용하거나, 하나의 프로젝트에서 여러 언어를 혼합하여 사용할 수도 있습니다. (Unreal Engine은 현재 JavaScript/TypeScript만 지원합니다.)
  • 🚀 C#/C++와의 원활한 상호 운용성을 갖춘 고성능 스크립트 런타임을 제공합니다.
  • 📝 호스트 엔진 API에 대한 타입 안전 접근을 위한 TypeScript 선언 생성 기능.

출처 - puerts github

현재 재직중인 회사에서 해당 라이브러리를 사용하여 게임을 개발, 서비스 중이다. 그렇다면 왜 이 라이브러리를 사용하고 있을까?

  • 원하는 언어를 선택하세요(Unity) : PuerTS 3.0은 통합 ScriptEnv아키텍처를 도입하여 TypeScript, Lua 또는 Python으로 게임 로직을 작성하고 일관된 C# 브리징 API를 사용할 수 있습니다. 더 이상 획일적인 방식은 없습니다.
  • 방대한 생태계 접근성 : npm, LuaRocks 또는 PyPI 패키지를 전문 게임 엔진과 함께 활용하여 개발 속도를 높이세요.
  • 필요할 때 타입 안정성을 확보하세요 : TypeScript의 정적 타입 검사는 코드의 견고성을 크게 향상시키며, Lua와 Python은 빠른 프로토타이핑을 위한 유연성을 제공합니다.
  • 높은 효율성 : 완전한 엔진, 크로스 플랫폼 리플렉션 호출 — C++/C# 상호 운용을 위한 상용구 코드가 전혀 필요 없습니다.
  • 고성능 : 지원되는 모든 언어에서 성능에 중요한 경로에 대한 정적 래퍼 생성 기능을 제공합니다.
  • 뛰어난 WebGL 지원 : 성능 및 개발 효율성 측면에서 엄청난 이점을 제공하며, 경우에 따라 순수 C#보다도 빠릅니다.

출처 - puerts github

 

해당 라이브러리 사용 후기

장점

1. 스크립트 개발

본래 상용 게임 엔진(유니티, 언리얼)의 스크립트를 변경하면 빌드 > 스토어에 검수 > 대기 > 배포 이러한 과정을 겪게 되는데 해당 과정을 겪을 필요 없이 빌드 하고 배포중인 게임에 스크립트만 업데이트 하면 된다. (재접속 후 갱신됨)

2. 빠른 개발

상용 게임 엔진에서 스크립트를 변경하고 해당 엔진으로 돌아오면 컴파일이 한 번 돌게 되는데 puerts 에서는 스크립트 백엔드 기능도 제공하여 JS의 V8을 사용해 코드 변경 후 해당 변경 부분이 바로 적용이 되어 엔진에서 확인 가능하다.

 

단점

1. 부족한 자료

해당 라이브러리를 사용하는 국내, 해외 기업이 많지 않아서 자료가 많이 부족하다. 국내 기업은 없는 것 같고 해외 기업들도 중국 기업들이 대부분이고 대표적으로 명조가 해당 라이브러리를 사용하여 개발되었다.

2. type script

사실 C++, C# 만 사용하다가 type script를 사용하면 익숙하지 않다. 대표적으로 C#에서 Linq를 자주 사용했었는데 type script es5기준 비슷한 기능을 하는게 몇 개 있을뿐 내부적으로는 똑같이 작동하지 않는다.

 

실제 사용 자료

UnityEngine의 기능들을 미리 바인딩 시키고 ts로 만든다.

purets 툴을 사용하여 index.d.ts 파일로 생성하면 엔진의 해당 기능을 사용할 수 있게 된다. Vector3를 예시로 들었다.

 

해당 부분을 가져와서 ts에서 사용한다.

 

디버깅도 유니티의 디버깅 기능이 아닌 node.js의 디버깅을 이용했다.

 

728x90
728x90

모바일 던파 TD분이 오셔서 섹션을 진행, 모바일 던파가 어떤 식으로 제작 되었는지 설명

모바일 던파 개발 배경
PC 던파의 기본 클래스
PC 던파의 기본 클래스들을 그대로 이식

PC 던파의 클래스 구조를 그대로 이식했지만 프레임 저하 등 최적화 문제 발생

코드 구조를 연산과 표현 계층으로 나누었다고 한다.
과정에서 유니티의 기술 활용
PC 던파의 네트워크 - 클라이언트 구조

기존 PC 던파는 P2P 연결을 통하여 던전 플레이를 구현

모바일 던파의 네트워크 - 클라이언트 구조

모바일 환경에서는 다양한 문제 때문에 락스탭 서버를 통하여 던전 플레이를 구현

던파 모바일에서 프레임 동기화 방식 사용
프레임 동기화방식에서 문제되는 것을 해결
전투중 반응 속도 문제

모바일 던파에서 전투 플레이 중 반응 속도 문제를 해결하기 위해 미리 연산 처리된 B와 인풋으로 입력된 A를 보간하여 C를 보여줌

락스탭 서버를 통해서 얻는 이점1
락스탭 서버를 통해서 얻는 이점2
락스탭 서버를 통해서 얻는 이점3
락스탭 서버를 통해서 얻는 이점4

락스탭 서버를 사용하면 기록이 쉬워져 해당 이점들을 얻어서 적용하였다 함

핫픽스 솔루션은 텐센트의 injectFix 사용

핫픽스 솔루션인 injectFix의 사용 과정을 보여줌

 

정리하자면

1. PC던파의 리소스, 코드를 모바일 던파로 이식하는 툴을 개발해 이식

2. 과정에서 유니티의 기술도 사용하면서 모바일 환경에서 개선해야할 문제를 개선

3. 네트워크 방식은 다른 방식을 사용함

4. Logic과 View 계층을 분리함

728x90
728x90

25년 4월 15일 유나이트 서울에 방문하였다.

키노트에서 유니티 6에서 추가된 기능들을 소개하고 있다.

 

첫번째 섹션에서 안드로이드 ANR에 대한 이야기를 듣고왔다

ANR이 왜 일어나는지 디버그를 통해 분석하는게 일반적이며 주로 일어나는 경우에 대해서 설명해 주셨다.

이외의 섹션은 따로 게시물을 작성하여 남겨놓으려 한다.

티셔츠와 레고를 받았다. 궁금했던 기술에 대해서 자세하게 알 수 있어서 좋았다.

728x90

'일상' 카테고리의 다른 글

2025.01.15 기술 면접 피드백  (1) 2025.01.15
지난 날의 내 Git 잔디  (1) 2024.01.09
728x90

PlayMaker 패키지를 이용해 구성한 FSM 로직이 실제 빌드 런타임에서 실행되지 않는 문제가 발생했습니다.

원인은 Linker Wizard라는 브릿지와 같은 내용이 빌드 단계에서 포함되지 않아 발생하는 문제였습니다.

 

해결 방법

  1. 우선 PlayMaker Ecosystem 페이지에서 EcosystemBrowser 패키지를 다운받은 뒤, 프로젝트에 추가합니다.
    Ecosystem 패키지 업데이트가 2021년도에 되어서 API 업데이트가 발생할 수 있습니다. 가능하면 변경사항들을 미리 백업 해두세요.
  2. Ecosystem 패키지 추가 후, 프로젝트 툴바의 PlayMaker > Addons > Ecosystem > Ecosystem Browser를 통해 Ecosystem 브라우저를 엽니다. 처음 브라우저를 열었을 때에는 disclaimer 페이지가 표시되니, 브라우저의 우측 상단 disclaimer 버튼 또는, 페이지 내용 중 Back to Browser 버튼을 클릭해 검색 페이지로 이동할 수 있습니다.
  3. 브라우저 검색 창에서 Linker Wizard를 검색하고, 해당 이름의 패키지를 찾아 프로젝트에 추가합니다. 해당 단계에서 Linker Wizard 패키지가 추가되고, API 업데이트가 한번 더 발생할 수 있습니다. 마찬가지로 진행 전, 변경사항들을 백업해두세요.
  4. Linker Wizard 패키지 설치 후, 에셋 폴더 내에 Linker Wizard 에셋이 추가된것을 확인할 수 있습니다.
    해당 에셋 선택하면 다음과 같은 인스펙터를 확인할 수 있습니다.
  5. Install Actions > Include Conditional Expression action > Update Linker content를 차례로 클릭합니다.
    이 과정 이후에는 에셋 폴더 아래에 link.xml이라는 파일이 생성된것을 확인할 수 있습니다.

 

PlayMaker FSM에서 Conditional Express Action을 이용하거나, C# Reflection을 이용하는 것으로 보이는 액션을 사용/수정한다면, 빌드 전에 항상 Linker Wizard를 통해 링크 데이터를 업데이트 해주세요.
릴리즈 런타임에서 PlayMaker FSM이 정상적으로 작동하지 않을 수 있습니다.

728x90
728x90

타워 디펜스 게임은 어떻게 만드는지 알기 위해 제작

어떠한 예제도 없이 구현

구현한 기능들

1. 유닛 등급 일반/희귀/영웅/신화 구분

2. 유닛 소환, 도박, 합성, 신화 유닛 조합, 판매

3. 몬스터는 웨이브, 보스로 나눔

4. 같이 플레이하는 AI 로직 (골드가 충족되면 유닛 소환, 합성 및 조합이 가능하면 수행함)

5. 유닛 배치때 같은 종류의 유닛은 한 칸에 3마리 우선 배치

6. 모든 데이터 정보를 밖으로 노출하여 관리하기 편하게 하려고함

5일 동안 진행하였고 어떤 느낌으로 만드는지 알게 됨

장르 - 타워 디펜스

이름 - LuckyDefense

개발 엔진 및 도구 - Unity

소스 코드 관리 - Git

스케줄 관리 - Todo mate(개인 기록)

제작 기간 - 5일

깃 주소 - https://github.com/Lee-SeungBin/LuckyDefense

 

GitHub - Lee-SeungBin/LuckyDefense: 운빨존많겜 게임 화면 클로닝

운빨존많겜 게임 화면 클로닝. Contribute to Lee-SeungBin/LuckyDefense development by creating an account on GitHub.

github.com

게임 플레이 영상 - https://youtu.be/yAL8FX9E9JA

 

 

728x90
728x90
  • 문제

이중 우선순위 큐는 다음 연산을 할 수 있는 자료구조를 말합니다.

명령어 수신 탑(높이)
I 숫자 큐에 주어진 숫자를 삽입합니다.
D 1 큐에서 최댓값을 삭제합니다.
D -1 큐에서 최솟값을 삭제합니다.

이중 우선순위 큐가 할 연산 operations가 매개변수로 주어질 때, 모든 연산을 처리한 후 큐가 비어있으면 [0,0] 비어있지 않으면 [최댓값, 최솟값]을 return 하도록 solution 함수를 구현해주세요.

  • 제한 사항

operations는 길이가 1 이상 1,000,000 이하인 문자열 배열입니다.
operations의 원소는 큐가 수행할 연산을 나타냅니다.
원소는 “명령어 데이터” 형식으로 주어집니다.- 최댓값/최솟값을 삭제하는 연산에서 최댓값/최솟값이 둘 이상인 경우, 하나만 삭제합니다.
빈 큐에 데이터를 삭제하라는 연산이 주어질 경우, 해당 연산은 무시합니다.

  • 입출력 예시
operations return
["I 16", "I -5643", "D -1", "D 1", "D 1", "I 123", "D -1"] [0,0]
["I -45", "I 653", "D 1", "I -642", "I 45", "I 97", "D 1", "D -1", "I 333"] [333, -45]
  • 접근방식

처음에 우선순위 큐를 두 개 만들어서 최대 최소만 나누자라고 생각했지만 찾아보니 multiset은 자동으로 값을 정렬해주면서 중복 저장이 가능하다는 특성을 가지고 있어서 해당 기능을 사용하기로 했다.

1. 'D'를 가진 문자가 있으면서 해당 multiset이 비어있지 않으면 multiset의 끝이나 처음을 지운다 (-1 또는 1로 판단)

2. 'I'를 가진 문자가 있으면 공백을 제외하고 숫자만 multiset에 집어 넣는다.

3. multiset이 비어 있으면 0,0 출력 아니면 정상 값 출력

  • 코드
#include <string>
#include <vector>
#include <set>
#include <sstream>

using namespace std;

vector<int> solution(vector<string> operations)
{
    vector<int> answer;
    multiset<int> ms;

    for (const string &op : operations)
    {
        if (op[0] == 'D' && !ms.empty())
        {
            if (op[2] == '1')
            {
                ms.erase(prev(ms.end()));
            }
            else
            {
                ms.erase(ms.begin());
            }
        }
        else if (op[0] == 'I')
        {
            istringstream iss(op);
            char cmd;
            int num;
            iss >> cmd >> num;
            ms.insert(num);
        }
    }

    answer = ms.empty() ? vector<int>{0, 0} : vector<int>{*ms.rbegin(), *ms.begin()};
    return answer;
}

문제링크 :https://school.programmers.co.kr/learn/courses/30/lessons/42628

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

728x90
728x90
  • 문제

트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순으로 건너려 합니다. 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다. 다리에는 트럭이 최대 bridge_length대 올라갈 수 있으며, 다리는 weight 이하까지의 무게를 견딜 수 있습니다. 단, 다리에 완전히 오르지 않은 트럭의 무게는 무시합니다.

예를 들어, 트럭 2대가 올라갈 수 있고 무게를 10kg까지 견디는 다리가 있습니다. 무게가 [7, 4, 5, 6]kg인 트럭이 순서대로 최단 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.

경과 시간 다리를 지난 트럭 다리 를 건너는 트럭 대기 트럭
0 [] [] [7,4,5,6]
1~2 [] [7] [4,5,6]
3 [7] [4] [5,6]
4 [7] [4,5] [6]
5 [7,4] [5] [6]
6~7 [7,4,5] [6] []
8 [7,4,5,6] [] []


따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.

solution 함수의 매개변수로 다리에 올라갈 수 있는 트럭 수 bridge_length, 다리가 견딜 수 있는 무게 weight, 트럭 별 무게 truck_weights가 주어집니다. 이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.

 

  • 제한 사항

bridge_length는 1 이상 10,000 이하입니다.
weight는 1 이상 10,000 이하입니다.
truck_weights의 길이는 1 이상 10,000 이하입니다.
모든 트럭의 무게는 1 이상 weight 이하입니다.

  • 입출력 예시
bridge_length weight truck_weights return
2 10 [7,4,5,6] 8
100 100 [10] 101
100 100 [10,10,10,10,10,10,10,10,10,10] 110
  • 접근방식

선입 선출의 큐를 사용해야 하고 truck_weights.size() 가 0이 될 때 까지 반복한다. 단, 벡터의 끝을 사용하려고 (pop_back, back) reverse를 시켜 주었다.

1. 주어진 벡터를 뒤집고 벡터의 크기 만큼 반복하는데

2. 우선 반복을 시작하면 시간초가 증가하고 벡터의 끝 (첫 번째 트럭)을 가져온다. (temp)

3. 만약 큐의 크기가 다리 길이와 같다면 (다리 위에 다리 길이만큼의 트럭만 있을수 있기 때문) 다리 위에 있는 트럭의 전체 무게(currentTotalWeight)에서 큐의 첫번째 값을 빼준다. (다리를 지난 트럭)

4. weight 보다 가 currentTotalWeight 와 벡터의 끝의 트럭의 무게의 합보다 크거나 같다면 (weight >= currentTotalWeight + temp)

5. 다리에 트럭을 올리고(currentTotalWeight += temp) 큐에 넣어준다음 주어진 벡터에 끝자리를 뺀다. (pop_back)

6. 조건이 아니라면 큐에 0을 넣어주어 시간이 흘러가게 한다.

7. 마지막으로 시간에 다리의 길이까지 더해준다.

  • 코드
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

int solution(int bridge_length, int weight, vector<int> truck_weights)
{
    int answer = 0;
    int currentTotalWeight = 0;
    queue<int> q;

    reverse(truck_weights.begin(), truck_weights.end());
    
    while (truck_weights.size())
    {
        answer++;
        int temp = truck_weights.back();
        
        if (q.size() == bridge_length)
        {
            currentTotalWeight -= q.front();
            q.pop();
        }
        
        if (currentTotalWeight + temp <= weight)
        {
            currentTotalWeight += temp;
            q.push(temp);
            truck_weights.pop_back();
        }
        else
        {
            q.push(0);
        }
    }
    
    answer += bridge_length;
    
    return answer;
}

문제링크 :https://school.programmers.co.kr/learn/courses/30/lessons/42583

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

728x90
728x90
  • 문제

문제 설명
0과 1로 이루어진 어떤 문자열 x에 대한 이진 변환을 다음과 같이 정의합니다.

1. x의 모든 0을 제거합니다.
2. x의 길이를 c라고 하면, x를 "c를 2진법으로 표현한 문자열"로 바꿉니다.
예를 들어, x = "0111010"이라면, x에 이진 변환을 가하면 x = "0111010" -> "1111" -> "100" 이 됩니다.

0과 1로 이루어진 문자열 s가 매개변수로 주어집니다. s가 "1"이 될 때까지 계속해서 s에 이진 변환을 가했을 때, 이진 변환의 횟수와 변환 과정에서 제거된 모든 0의 개수를 각각 배열에 담아 return 하도록 solution 함수를 완성해주세요.

  • 제한 사항

s의 길이는 1 이상 150,000 이하입니다.
s에는 '1'이 최소 하나 이상 포함되어 있습니다.

  • 입출력 예시
s result
"110010101001" [3,8]
"01110" [3,3]
"1111111" [4,1]
  • 접근방식

s가 1이 될 때 까지 반복하는데 시도한 횟수 cnt, 0을 몇 번 제거한지 기록한 횟수 zerocnt

1. s의 길이만큼 반복하고 "1"이면 빈 문자열 temp에 1을 붙히고 아니라면(0이라면) zerocnt증가

2. temp 길이를 저장하고 (tempLength) temp와 s를 클리어

3. tempLength가 1미만이 될 때 까지 반복하는데 1이상이면 s에 0을 tempLengh % 2 만큼 넣고 tempLength /= 2를 해줌

4. 반복이 끝나면 나온 cnt와 zerocnt를 answer에 push_back

  • 코드
#include <string>
#include <vector>
#include <iostream>

using namespace std;

vector<int> solution(string s)
{
    vector<int> answer;
    string temp = "";
    int zerocnt = 0;
    int cnt = 0;
    
    while (s != "1")
    {
        cnt++;
        for (int i = 0; i < s.length(); i++)
        {
            if (s[i] == '1')
            {
                temp += s[i];
            }
            else
            {
                zerocnt++;
            }
        }
        
        int tempLength = temp.length();
        temp.clear();
        s.clear();
    
        while (tempLength >= 1)
        {
            s.insert(0, to_string(tempLength % 2));
            tempLength /= 2;
        }
    }
        
    answer.push_back(cnt);
    answer.push_back(zerocnt);
    
    return answer;
}

문제링크 : https://school.programmers.co.kr/learn/courses/30/lessons/70129?language=cpp

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

728x90

+ Recent posts