NDC2017 2017. 5. 18. 14:02

라이브 프로세스 분석을 통한 효율적인 로직 개발

<게임 프로그래밍 패턴> DP

라이브 프로세스
- 기획서 이해 -> 기존 코드 분석 -> 구조 설계 -> 코드 작성 -> QA & 버그수정 -> 완성
<게임 프로그래밍 패턴> 책에서 기능추가, 버그수정 그 외 무슨 이유든 코드를 고치려면 먼저 기존 코드를 이해해야한다. 대부분 이 과정을 별것 아닌 것으로 여기지만 사실 프로그래밍에서 가장 오래 걸리는 부분이다.

코드 설계 시간 부족 -> Bad Code -> 분석 시간 증가 ->코드 설계 시간 부족.... 악순환

주제 : 분석에 소요되는 시간을 줄여서 코드 설계 & 작성하는 시간을 늘리자.

라이브에서 좋은 코드 : 새로운 코드를 작성 하기 전, 머리 속에 입력해야 할 정보가 적은 코드 ( 가독성 )

'코드'적인 측면과 '방법론'적인 측면

코드 : 작명 중요(변수, 함수, 클래스의 작명)
 1. 공통적인 내용이 앞에 있어 알아보기 쉽다. ex) GetName,GetNameRes,GetUserID
ex) CheckState() (O) CS() (X)
-> 작업자들간의 공유할 수 있는 네이밍 규칙이 필요합니다.

 2. 사용하지 않게 된"#if~endif"은 빠르게 삭제.
-> 대부분의 서비스중인 온라인 게임에서 #define의 개수는 적게는 몇백개에서 많게는 몇천 몇만개에 달한다.
가독성과 유지보수에 있어 굉장히 중요하고 민감한 부분임을 항상 명시하자.

 3. 미사용 코드는 꼭 제거하자
-> 완전히 같은 기능을 하는 중복 함수들

 4. 적재적소의 주석, 미사용 주석은 빠르게 제거.
-> 직관적으로 이해 가능할때는 주석 (O) 작성자만 알 수있는 코드는 주석 사용.

공통점 . 작은 불씨가 큰 불로.. / 업무 하다가 남은 시간에 정리하자. -> "남는 시간은 없다."
-> 반드시 "업무"로 할당하여 해결하자.
방법론

1. 짧은 개발 기간 동안 무리한 양의 개발은 피해야한다.

2. 개발 완료 이후 출시 전 사이 여러 번의 내용 변경 시도는 피해야한다.
-> 어쩔 수 없이 하게 되면 업데이트 이후 스케줄은 반드시 무리한 개발에 따른 비효율적인 코드(날림코드) or 리소스의 정리(리펙토링)가 되어야 한다.
무리한 개발을 진행하였으면 반드시 그에 따른 결과를 기록해야 하고 이른 향후 비슷한 이슈가 발생했을 때 참고자료로 사용해야 한다.

3. 퇴사 예정자에게는 새로운 업무 부여는 주어서는 안된다.
-> 퇴사 예정자가 진짜 해야 할 업무는 "신규 개발"이 아닌 "인수 인계"다.

4. 직 간접적인 "코드 리뷰"
-> 나는 10줄의 코드로 구현 가능하다고 생각한 기능을 다른 프로그래머는 단 2줄의 코드로 구현 가능한 방법을 알고 있을 수도 있다.
=> 직접적인 코드 리뷰 (결과물에 대해 모두가 토론) 30%
=> 간접적인 코드 리뷰 (리드 프로그래머의 검수) 70%(라이브는 이것이 대부분)
간접적인 코드 리뷰를 하면 팀원들의 리드 프로그래머에 대한 신뢰도 증가.
-> 프로젝트의 코드 퀄리티가 뛰어나다 응답.
작업자와 1:1 대화를 통한 코드 리뷰 or 관련 컨텐츠의 샘플 코드 제시 -> 방향을 제시
=> 리더가 직접 코드를 작성하며 게임 코드의 변화를 자세히 파악하고 있어야 한다.


posted by 천마서생
:
NDC2017 2017. 5. 18. 13:59

현실적인 pvp AI 만들기
누구나 구현 가능한, 쉬운, 바로 써먹을 수 있는,

대전 액션게임의 아케이드 모드 에이아이를 효율적으로 쉽게 만드는 것에 대한 이야기

시즈키 도장 : 결투장 유저처럼 움직이는 AI 구현 사람하고 싸우고 싶은 AI구현 아케이드 모드에 사용가능한 적절한 AI를 배치

던파 결투장 : xy축을 사용한 무빙 , 방대한 컨텐츠, RatingPoint 매칭기반, 공중,스탠딩,바닥,보정시스템
시즈키 도장

1. 모든 유저가 자신과 같은 전직의 AI와 대전 가능해야한다. (51개) - 매우 복잡도가 높은 컨텐츠에 대해 기획자가 바로 로직을 짜도록 설계. - 루아스크립트 사용.
2. 유저의 콤보 학습을 도와야 한다. - 빠르고 쉽게 제작해야함.
3. 유저와 같은 의미 있는 무빙을 해야함. - AI가 유저의 공격 범위를 예측하여 움직여야함.
4. 제공되는 난이도는 3가지( RP 600, 800, 1000이 기준) - 난이도는 데이터로만 결정.(너무 많은 캐릭터를 만들어야해서)

키스트림 기반의 콤보
- 콤보는 상대가 무력화 된 상태에서, 순차적으로 실행되는 흐름일 뿐
- 기획자의 콤보 키입력을 파일로 저장하는 기능 제공 = 콤보 녹화 -> 텍스트 형식 파일로 저장 -> 찍어내기
- AI로직 스크립트에서는 키스트림을 간단히 재생 - 단순하게 저장된거 실행

위험영역 기반의 무빙
- 무빙이란, 나는 맞지 않고, 때리려는 움직임
- 스킬별 적의 공격 데이터 정의.
- 스킬 쿨타임에 따라 위험영역 on/off (스킬 사거리)
- 접근 + 회피 + 위험영역 = 유저와 같은 움직임 재현
- 위험영역은 AI스크립트에 이벤트로 전달, 기획자가 필요에 따라 로직 처리

FSM 상태정의

- checkstate : 견제를 담당하는 상태로써, 공격성공시 콤보로 연계를 할 수 있는 딜레이가 짧은 어퍼류의 스킬을 사용함.
- checkstate를 별도로 분리함으로써, MoveState와 콤보시스템과 번갈아가며 사용된다.

난이도 구현
- 난이도별 AI로직을 분리하는것은 힘듬.
- 난이도란? 숙련도의 차이, 같은 플레이에 대해 점점더 정교해지는 개념
- 난이도별 AI데이터는 정확도 수치만을 다르게 입력.

단점
- 투척류, 설치형 스킬에 취약
- AI별로 퀄리티의 편차가 있는편

 AI 구현 팁.
- 키스트림 기반 콤보
- 위험영역 기반 무빙
- checkState를 사용한 FSM
- 생산성을 높이는 정확도 시스템


posted by 천마서생
:
프로그래밍/Unity 2016. 7. 20. 14:48

필자가 JSON을 알게 된 것은 nodejs+mongodb를 연환한 서버를 구축할 때 였다.

이 당시에는 JSON의 개념조차 잡혀있지 않았고 JSON이 파일까지 만들어주는 줄 알았다.

(JSON은 파싱 즉 값을 string으로 변환만 해준다.)

결국엔 실패했다.


각설하고 이번 게임 제작할때 SAVE / LOAD를 구현하려고 다시 자료를 찾던중 playerprefabs와 json을 활용한 자료 저장 xml이 있었다. 그중 필자는 저번의 실패를 만회하기 위해 json을 다시 도전했고 자료를 찾던중 유니티 5.3이상부터 지원되는 JsonUtility 기능에 대해서 알게되었다.


https://docs.unity3d.com/ScriptReference/JsonUtility.html    <= 유니티 공식홈페이지

   JsonUtility 레퍼런스


영어로 되어있다.


해석하자면


FromJson

Create an object from its JSON representation.
JSON 형식으로부터 오브젝트를 생성한다.

FromJsonOverwrite

Overwrite data in an object by reading from its JSON representation.
JSON 형식의 데이터를 받아와 오브젝트에 오버라이팅을 한다.

ToJson

Generate a JSON representation of the public fields of an object.
public 형식으로 선언된 오브젝트를 JSON형식으로 저장한다.

여기서 오브젝트란 클래스 / 구조체 / 값 전부 된다.


이제 사용 방법을 보겠다. 

우선 필자는 클래스를 오브젝트로 잡았다.


[SerializeField]

    public class Data

    {

        public string charname;

        public string birthday;

        public int stress;

        public int stamina;

        public int year;

        public int month;

        public int money;

        public bool istired;

        public bool isseek;

    }


아 그리고 모든 오브젝트는 public 과 [SerializeField]로 선언되어야 한다. (이유는 잘 모르겠으나 레퍼런스를 읽어보니 JsonUtility에서 읽고 쓰는 오브젝트들은 SerializeField / public으로 선언되어있어야 사용가능하다고 나옴)


아무튼 필자는 세이브 버튼을 누르면 함수가 호출되도록 설계했다.

 public void Button_save()

    {

        var saveData = new Data();

        saveData.charname = m_charactorname;

        saveData.birthday = m_birthday;

        saveData.stress = m_stress;

        saveData.stamina = m_stamina;

        saveData.year = m_year;

        saveData.month = m_month;

        saveData.money = m_money;

        saveData.istired = m_istired;

        saveData.isseek = m_isseek;

        string save = JsonUtility.ToJson(saveData, prettyPrint: true);

  Debug.Log(save);


        pathForDocumentsFile("save.txt");       //파일 입출력 용 함수

        writeStringToFile(save1, "save.txt");      //파일 입출력 용 함수

    }

이런 식으로 만들었다.

우선적으로 클래스를 saveData로 동적생성 해주고 각각의 값을 저장했다.

그 후 string save = JsonUtility.ToJson(saveData, prettyPrint: true); 이렇게 적었다.

JsonUtility 레퍼런스에서 JsonUtility.ToJson의 반환 값이 string이므로 string 변수를 생성 후 그 곳에 저장한다. 그리고 Debug.Log()를 해보면 Json형식으로 바뀐 값을 볼 수있다.

여기서 그만두면 string에만 저장되있고 파일로는 저장이 안된다. 따라서 이제 string을 파일입출력을 통해 txt파일로 저장하면된다!


이제 저장을 했으니 불러오기를 할 차례이다.

이거 또한 Load 버튼을 누르면 함수가 호출되도록 설계했다.

 public void Button_load()

    {

        pathForDocumentsFile("save.txt");                        //파일 입출력 용 함수

        string load = readStringFromFile("save.txt");           //파일 입출력 용 함수

        var loadData = JsonUtility.FromJson<Data>(load);

        m_charactorname = loadData.charname;

        m_birthday = loadData.birthday;

        m_stress = loadData.stress;

        m_stamina = loadData.stamina;

        m_year = loadData.year;

        m_month = loadData.month;

        m_money = loadData.money;

        m_istired = loadData.istired;

        m_isseek = loadData.isseek;

    }


세이브와는 정 반대이다.   var loadData = JsonUtility.FromJson<Data>(load); 

Data클래스의 형식으로 Json으로 되어있는 파일을 바꿔준다.


JsonUtility.FromJson<T>(string );

레퍼런스에서는 이러한 구조로 되어있다. 따라서 T 부분에 자기가 원하는 저장시 데이터 상태를 넣어주고 string 부분에 Json형식이 저장되 있는 것을 넣어주면된다.

'프로그래밍 > Unity' 카테고리의 다른 글

유니티 VideoPlayer.  (0) 2017.08.03
오브젝트 풀  (0) 2016.07.15
LitJSON 파일 있는지 없는지 확인 함수  (0) 2016.07.10
posted by 천마서생
: