매주 랭킹을 초기화 해야한다.
좋은 방법이 없을까

- 일단 페이스북에서 제공하는 API가 있다.

앱의 모든 점수 삭제

해당 앱의 앱 access_token으로 /APP_ID/scores에 대한 HTTP DELETE 요청을 실행하여 앱의 모든 점수를 삭제할 수 있습니다.
그러면 앱의 점수를 재설정합니다. 게임 점수 및 리더보드를 주기적으로 재설정하려 할 때 사용하세요.

응답은 다음과 같습니다.

설명
유형

삭제 성공 여부에 따라 true 또는 error

boolean


이 API를 이용하면 될 것 같은데 일주일에 한 번 서버자체로 해당 코드를 실행 시키도록 해야할 것 같다. 
해당 기능은 스케줄러를 이용해서 구현할 수 있다고 하여 관련 포스트를 찾아 보았다. 출처: http://webinformation.tistory.com/6 [끄적끄적]

Crontab

[분] [시] [일] [월] [요일] [실행하고자 하는 명령어]

분(0~59), 시(0~23), 일(1~31), 요일 (1~7{월~일})

위와 같은 구조로 실행하고자 하는 명령어를 예약할 수 가 있으며, crontab 을 사용하는 방법에는 두가지가 있습니다.

vim /etc/crontab 을 이용해서 예약하기

[root@localhost ~]# vim /etc/crontab


* 01 */1 * * /usr/local/bin/php -f /home/user/sync.php


위 명령어는 매일 새벽 1시에 sync.php 파일이 실행되도록 한 것입니다.

:wq 명령어를 이용해서 저장하고 나오시면 끝!

해당 방법은 별도의 추가 작업이 필요없으며 그냥 저장하고 나오시면 자동으로 적용이 됩니다.

crontab -e 를 이용해서 예약하기

[root@localhost ~]# crontab -e


* 01 * * 1 /usr/local/bin/php -f /home/user/sync.php


위 명령어는 월요일 새벽 1시에 sync.php 파일이 실행되도록 한 것입니다.

:wq 명령어를 이용해서 저장하고 나오시면 끝!

해당 방법은 아래와 같은 실행 및 재 시작의 명령어를 추가로 수행해야 합니다.

실행, 종료, 재 시작 명령어

[root@localhost ~]# /etc/rc.d/init.d/crond start
[root@localhost ~]# /etc/rc.d/init.d/crond stop
[root@localhost ~]# /etc/rc.d/init.d/crond restart

위의 내용을 참고하여 일단 테스트로 * * * * * sh /game/project/test.sh  라고 
저장하였다. test.sh엔 
echo "Hello World" > hello.txt
가 저장되어있다.

예상대로라면 1분마다 Hello World라고 hello.txt 에 저장해야하는데 아무런 변화가 없다.
crontab -l 을 실행해보니 “no crontab for root” 라고 나온다. 

서치결과 "crontab -u root -e” 명령어로 새로운 크론탭을 적용했다.
다시 crontab -l 을 실행하니 제대로 * * * * * sh /game/project/test.sh 가 나왔다. 

cat /var/log/cron을 실행해보니 뭔가 1분마다 동작하고 있었지만 
여전히 hello.txt파일은 존재하지 않았다. 경로가 잘못된 듯하여 home을 기준으로 절대 경로를 삽입하였다.

* * * * * sh home/user/game/project/test.sh  잘된다.

이어서 일요일에 1번 실행시키기 위해 59 23 * * * php /home/user/game/project/resetRanking.php 를 설정했다.
이제 페이스북 랭킹을 초기화하는 로직만 작성하면된다.


랭킹 초기화하는 페이스북 API 호출하기

먼저 페이스북 PHP SDK를 깔아야한다. 안에 있는 src폴더를 서버에 복사한다.
그리고 mbstring 이라는 php모듈? 을 설치한다. (sudo yum install php56-mbstring) php 버전에 따라 다르게 설치한다. 이것때문에 한참을 해맸다.

이후에 유저 전체의 스코어를 모두 초기화 하는 스크립트를 구현하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
    error_reporting(E_ALL);
 
    ini_set("display_errors"1);
 
    require_once __DIR__ . '/php-graph-sdk-5.0.0/src/Facebook/autoload.php';
 
    $fb = new Facebook\Facebook(['app_id' => ‘xxx',
                                'app_secret' => ‘xxx',
                                'default_graph_version' => ‘xxx']);
    $fbApp = $fb->getApp();
    $fb->delete('/app/scores/', [], $fbApp->getAccessToken());
cs
 

사실 위의 app accesstoken을 어디서 어떻게 가져와야 할지 몰라 한참을 해맸다.
결국 잘되는 것을 확인했다.

이제 웹에서  경로를 통해 php를 실행하는 것을 막아야한다. ( 웹에서 누구나 접근하여 게임의 스코어를 날릴수 있다면 큰일이다. )
여러 방법이 있겠지만  
웹에서 접근하지 못하는 경로에 추가하였다.


'All > Project' 카테고리의 다른 글

지금까지 개발된 내용  (0) 2017.04.08
Laviah  (0) 2017.04.08
UI_ HealthBarUI  (0) 2016.04.12
UI_ MyButton  (0) 2016.04.12
별게임의 상태트리  (0) 2016.04.12

Json syntax check

http://jsonlint.com/


Shell script syntax check

https://www.shellcheck.net/


online photoshop

https://pixlr.com/editor/


gradation list

http://uigradients.com/#WhatliesBeyond


Web scripter

http://colorscripter.com/


Algorithm Visualizer

http://algo-visualizer.jasonpark.me/#path=backtracking/knight's_tour/basic

'All > ETC' 카테고리의 다른 글

국토종주  (0) 2017.05.10
훈련소 (2016. 01. 21 ~ 2016. 2. 18)  (2) 2016.01.19
Tistory Start  (0) 2015.12.28

1. memset( array, 0, sizeof array );

전달된 배열을 0으로 초기화 한다.

ex)

1
2
3
4
char outputArray[30];
 
//array init by 0
memset( outputArray, 0sizeof(outputArray) );
cs

2. std::copy( input_begin, input_end, output_begin );
어떠한 컨테이너도 복사한다. 
output에 해당하는 컨테이너의 크기가 input의 컨테이너보다 크거나 같아야 한다.
ex)
1
2
3
4
5
6
7
8
9
10
11
12
char outputArray[30];
std::string inputArray = "A B C D E F G H I J K L"  //size = 23
 
//array init by 0
memset( outputArray, 0sizeof(outputArray) );
 
std::copy(std::begin(inputArray), std::end(inputArray), std::begin(outputArray));
 
//show
/** 
 * outputArray = "A B C D E F G H I J K L\0\0\0\0\0\0\0"
 **/
cs



3. std::advance( iterator, index );
어떠한 컨테이너도 배열처럼 접근한다.
iterator를 index만큼 증가시킨다. 
index는 0보다 크거나 같고 컨테이너의 사이즈보다 작아야 한다.
ex)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::map<std::stringstd::string> nameMap;
// init map 
nameMap.emplace(std::pair<std::stringstd::string>("Hong" , "Hello Hong" ));
nameMap.emplace(std::pair<std::stringstd::string>("Seong""Hello Seong"));
nameMap.emplace(std::pair<std::stringstd::string>("Hee"  , "Hello Hee"  ));
 
auto item = nameMap.begin();
std::advance( item, random<int>(0, nameMap.size()-1) );
 
//show
/** 
 * randomIndex = 0, data = "Hello Hong"
 * randomIndex = 1, data = "Hello Seong"
 * randomIndex = 2, data = "Hello Hee"
 **/
cs


4. std::find( array_begin, array_end, item );
컨테이너 중 item의 iterator를 반환한다.
5. std::distance( array_begin, iterator );
컨테이너에서 iterator에 해당하는 index를 반환한다.
ex)
1
2
3
4
5
6
7
auto iter = std::find(list.begin(), list.end(), item);
int index = std::distance(list.begin(), iter);
 
//show
/**
 * list[index] 
 **/
cs


6. std::fill( array_begin, array_end, value );
컨테이너를 value로 채운다. (초기화 한다.)

ex)

1
2
3
4
5
6
7
8
9
10
std::vector<int> array;    
array.resize(3);
std::fill(array.begin(), array.end(), 10);
 
//show
/**
 * array[0] = 10
 * array[1] = 10
 * array[2] = 10  
 */
cs


'All > C++' 카테고리의 다른 글

operator new / operator delete  (0) 2016.03.14
메모리 누수 검사  (0) 2015.12.29
가변인자 로그 출력함수  (0) 2015.12.29
RValue와 LValue  (2) 2015.12.28
문장줄이기  (0) 2015.12.28

개요

체력 계산 함수를 외부에 구현하고 CHealthBarUI에서는 함수포인터만 전달하여 호출하는 식으로 구현했습니다. 

처음엔 체력계산 함수를 Player의 virtual function으로 구현 하였습니다.

하지만 이후 캐릭터마다 체력계산 함수의 종류나 계산 방식 등이 다를 수 있을 것이라 생각하였고 

Strategy Pattern을 적용하게 되었습니다.

또 계산식에서 필요한 private변수들이 많아질 것으로 예상하였습니다. 

때문에 클래스나 구조체로 구현하여 Player의 인스턴스를 전달하는 Strategy Pattern의 전형적인 방식을 사용하기보다는 

Player의 함수 포인터를 사용하는 식으로 변형하였습니다.

추상클래스로 인터페이스를 제공하는 장점을 버리게 되었지만 private변수 참조 용이, 은닉화의 장점을 취할 수 있었습니다.


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*-----------------------CHealthBarUI--------------------------
 * strategy pattern
 * 같은 캐릭터라도 다른 체력계산함수를 사용할 수 있도록 구현
 * 때문에 캐릭터에서 virtual 함수로 구현하지 않고 strategy pattern을 이용
 * 차후에 다른캐릭터로 이어달리기 등의 기능을 구현할때 용이함
 * (자세한 것은 player클래스 참조)
 * Lambda혹은 함수포인터, 함수객체를 인자로 받는다.
 * CHealthBarUI는 철저히 UI만 표현한다.
 * ------------------------------------------------------------*/
 
 
 
 
/* 캐릭터마다의 체력계산함수 포인터 전달 */
static CHealthBarUI* create(HealthCalculatorFunc healthCalFunc);
 
 
/* 플레이중 버프나 보너스 타임때 계산 함수 변경가능위해 */
void ChangeHealthCalFunc(HealthCalculatorFunc healthCalFunc);    
 
 
/* ProgressBar Update 
 * m_HealthCalculatorFunction에 들어있는 함수 호출 */
void UpdateHealthUI(float delta);
{
    float percent = m_HealthCalculatorFunction(delta);
    m_HealthBar->setPercentage(percent);
}
 
/* HealthFunc 타입 정의 */
typedef std::function<float(float delta)> HealthCalculatorFunc;
 
 
/* HealthBarUI 생성 시 캐릭터의 원하는 체력계산함수 호출을 위해 
 * 체력계산함수 포인터 전달  */
HealthCalculatorFunc m_HealthCalculatorFunction;
cs

CHealthBarUI 클래스의 주요 함수 및 동작원리 설명

1. UI생성 시 캐릭터의 체력계산 함수포인터를 전달합니다.

2. 때문에 사용자는 캐릭터의 종류에 따라 원하는 체력계산 함수를 모두 정의 할 수 있습니다.

3. ChangeHealthCalFunc함수를 통해 호출되는 함수를 변경할 수 있습니다.


사용 예

1
2
3
4
auto healthBar = CHealthBarUI::create(
        std::bind(&CPlayer::HealthCalculatorInNormal, 
        CObjectManager::Instance()->getPlayer(), 
        std::placeholders::_1));
cs

1. 체력 계산 함수로써 Player의 HealthCalculatorInNormal()함수를 호출하는 HealthBarUI를 생성

2. std::placeholders::_1 : 함수 호출 시 전달하는 매개변수는 함수를 호출하는 장소에서 전달하는 값으로 사용한다는 의미입니다.

3. 여기서는 deltaTime을 전달합니다.



귀차니즘을 위한 2줄 요약

1. HealthBarUI는 UI만 표현하고 계산 함수는 캐릭터가 가지고 있다.

2. HealthBarUI를 생성할 때 캐릭터의 함수를 인자로 전달하면된다.

3. ChangeHealthCarFunc()로 계산 함수를 변경할 수 있습니다.

'All > Project' 카테고리의 다른 글

Laviah  (0) 2017.04.08
매주 일요일 랭킹 초기화  (0) 2017.04.05
UI_ MyButton  (0) 2016.04.12
별게임의 상태트리  (0) 2016.04.12
AI_ FSM / State  (0) 2016.04.12

개요

cocos2dx 자체의 버튼 클래스가 존재하는 것으로 알지만,

원하는 기능인 버튼이 눌린 상태를 체크할 방법과 여러 콜백함수 등록기능을 사용하기 위해 자체 클래스를 만들었습니다.

최대한 사용자가 버튼을 만들어 사용할 때 편리할 수 있도록 구현하였습니다.


코드 및 설명은 아래와 같습니다. 

(가독성을 위해 적당히 편집하였습니다.)


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*--------------------------CMyButton--------------------------
 * strategy pattern
 * texture 혹은 label로 초기화하여 사용하는 Button
 * Lambda혹은 함수포인터, 함수객체를 인자로 받는다.
 * 눌렀을때 체크
 * 누르고 있을 때 체크
 * 끝났을 때 체크 
 * ------------------------------------------------------------*/
 
 
 
 
/* 버튼의 상태 */
enum eMYBUTTON_STATE{
    BEGIN = 0,
    EXECUTE = 1,
    END = 2,
}
 
 
/* 텍스쳐와 함께 버튼 생성 
 * normalImg와 selectedImg를 인자로 전달*/
CMyButton* CMyButton::createWithTexture(
    std::string normalTextureName,                // 선택 전 버튼의 텍스쳐 이름
    std::string selectedTextureName,              // 선택 중 버튼의 텍스쳐 이름
    eMYBUTTON_STATE state,                        // 버튼 상태 (해당 상태일 때 함수 호출됨)
    const std::function<void(void)> &func)        // 람다 혹은 함수포인터 혹은 함수객체 전달(매개 변수는 void)
 
 
/* 문자열과 함께 버튼 생성 */
CMyButton* CMyButton::createWithString(
    std::string normalTextureName,                // 버튼의 텍스쳐 이름
    std::string labelString,                      // 버튼의 label 내용
    int fontSize,                                 // 폰트 사이즈
    eMYBUTTON_STATE state,                        // 버튼 상태 (해당 상태일 때 함수 호출됨)
    const std::function<void(void)> &func)        // 람다 혹은 함수포인터 혹은 함수객체 전달(매개 변수는 void)
 
 
/* 버튼의 함수 포인터 리스트에 함수 포인터 추가 */
void AddState(eMYBUTTON_STATE state,             // 상태 (해당 상태일 때 함수 호출됨)
    const std::function<void(void)> &func)        // 람다 혹은 함수포인터 혹은 함수객체 전달(매개 변수는 void)
 
 
/* 터치된 좌표를 버튼의 좌표로 변환 한 후에 버튼이 터치되었는지 검사 */
bool touchHits(Touch  *touch)
{
    const Rect area(00, m_pNormalTexture->getContentSize().width, 
        m_pNormalTexture->getContentSize().height);
 
    // world to nodespace 좌표 변환
    return area.containsPoint(m_pNormalTexture->convertToNodeSpace(touch->getLocation()));
}
 
 
/* 버튼이 눌렸을 때 BEGIN */
bool onTouchBegan(Touch  *touch, Event  *event)
{
    CC_UNUSED_PARAM(event);
    if (m_pNormalTexture){
 
        // 좌표 변환 후 터치 체크
        m_IsSelect = touchHits(touch);
 
        // 버튼의 좌표에서 진짜로 터치되었을 경우
        if (m_IsSelect){
 
            // BEGIN 상태일때 호출해야할 함수가 있다면 호출
            std::for_each(m_BeginFuncList.begin(), m_BeginFuncList.end(), 
                [](const std::function<void(void)> &func){
                func();
            });
            
            // 선택 시 이미지가 있다면 이미지 교체
            if (m_SelectedTextureName != ""){                    
                m_pNormalTexture->setTexture(m_SelectedTextureName);
            }
            else { // 교체될 이미지가 없다면 크기를 키움                                                
                m_pNormalTexture->setScale(1.1f);
            }
        }
    }
    return m_IsSelect;
}
 
 
/* 버튼에서 떨어졌을 때 END */
void CMyButton::onTouchEnded(Touch  *touch, Event  *event)
{
    CC_UNUSED_PARAM(event);
    if (m_pNormalTexture){
 
        // END 상태일때 호출해야할 함수가 있다면 호출
        std::for_each(m_EndFuncList.begin(), m_EndFuncList.end(), 
            [](const std::function<void(void)> &func){
            func();
        });
 
        // 이미지가 바뀌었었다면 다시 원래대로 바꿈
        if (m_SelectedTextureName != ""){                        
            m_pNormalTexture->setTexture(m_NormalTextureName);
        }
        else// 바뀔이미지가 없다면 크기를 원래대로 바꿈                                                    
            m_pNormalTexture->setScale(1.0f);
        }
 
        // 버튼 눌림 종료
        m_IsSelect = false;
    }
}
 
 
/* 버튼이 눌리고 있는 중일때 EXECUTE */
void Execute(float delta)
{
    // 버튼 눌림 상태이며, EXECUTE 상태일 때 실행되어야 할 함수가 1개 이상일 때
    if (m_IsSelect && m_ExecuteFuncList.size())
    {
        // EXECUTE 상태일때 호출해야할 함수가 있다면 호출
        std::for_each(m_ExecuteFuncList.begin(), m_ExecuteFuncList.end(), 
            [](const std::function<void(void)> &func){
            func();
        });
    }
}
 
 
/* lambda, 함수 포인터를 리스트로 저장
 * 각 상태일 때 호출할 함수를 저장하는 리스트 */
std::vector<std::function<void(void)>> m_BeginFuncList;
std::vector<std::function<void(void)>> m_ExecuteFuncList;
std::vector<std::function<void(void)>> m_EndFuncList;
cs

CMyButton 클래스의 주요 함수 및 동작원리 설명

1. 전략 디자인 패턴의 변형으로 버튼 생성시 함수 포인터를 전달합니다.

2. 때문에 사용자는 버튼을 눌렀을 때의 상황에 대해 부담없이 정의할 수 있습니다.

3. 각 버튼은 Begin, Execute, End의 상태를 가질 수 있습니다.

4. 각 상태에 맞는 함수를 생성시 초기화 혹은 AddState 함수로 추가할 수 있습니다. 


사용 예

1
2
3
4
5
auto leftButton = CMyButton::createWithTexture(
        "leftButton_1.png",
        "leftButton_2.png",
        EXECUTE,
        std::bind(&CObjectManager::RotationObject, CObjectManager::Instance(), -1)); 
cs

1. 눌리기 전엔 leftButton_1.png, 눌린 상태엔 leftButton_2.png의 이미지를 보이는 버튼을 생성합니다.

2. 버튼이 눌린 상태(EXECUTE)일 때 CObjectManager::Instance()의 RotationObject(int dir) 함수를 호출합니다.

3. std::bind : 함수 호출 시 전달하는 매개변수를 -1로 고정하고, 호출하는 인스턴스는 CObjectManager::Instance()로써 bind합니다.



귀차니즘을 위한 2줄 요약

1. Button에는 Begin, Execute, End 3 가지의 상태가 존재한다.

2. Button을 create할때 각 상태에 호출될 함수를 넣을 수 있다.


'All > Project' 카테고리의 다른 글

매주 일요일 랭킹 초기화  (0) 2017.04.05
UI_ HealthBarUI  (0) 2016.04.12
별게임의 상태트리  (0) 2016.04.12
AI_ FSM / State  (0) 2016.04.12
Shooter / Bullet  (0) 2016.04.12

앞선 FSM 및 State를 이용한 별게임의 상태 트리는 다음과 같습니다.





'All > Project' 카테고리의 다른 글

UI_ HealthBarUI  (0) 2016.04.12
UI_ MyButton  (0) 2016.04.12
AI_ FSM / State  (0) 2016.04.12
Shooter / Bullet  (0) 2016.04.12
ObjectManager  (0) 2016.04.12

개요

별게임에 나오는 모든 오브젝트는 다음과 같은 상태를 가질 수 있습니다.

1. 자석 아이템을 먹었을때의 상태

2. 거인 아이템을 먹었을때의 상태

3. 코인으로 변화시키는 아이템을 먹었을 때의 상태

4. 별로 변화시키는 아이템을 먹었을 때의 상태

위 4개의 상태는 공존할 수 있습니다.(3번 4번은 서로 공존할 수 없다.)

즉, 플레이어가 거인인 상태에서 자석을 먹고 모든 bullet이 코인으로 변화되는 아이템을 먹을 수 있다는 것입니다.


위와 같은 복잡한 상황을 구현하기 위해 FSM과 State를 도입하였습니다.

먼저 FSM(stateMachine)의 코드는 다음과 같습니다.

(가독성을 위해 적당히 편집하였습니다.)


FSM 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*------------------------CStateMachine------------------------
 * Template 클래스
 * FSM사용을 원하는 클래스에서 정의하여 사용할 수 있다.
 * 사용자는 States를 가지고 있어야 한다.
 * Global, Current, Previous 상태를 가지고 있다.
--------------------------------------------------------------*/
 
 
 
 
/* template으로 정의됨 */
template <class T>
 
 
/* 생성 시 FSM을 사용하고자하는 객체의 This를 넘겨 받는다. */
CStateMachine(T* Owner)
 
 
/* 현재 상태를 전달받은 상태로 변경한다. 
 * 현재 상태는 이전상태에 저장한다. 
 * 현재상태의 Exit함수를 호출하며 새로운 생태의 Enter함수를 호출한다. */
template <class T>
void CStateMachine<T>::ChangeState(CState<T>* pNewState)
{
    if (m_pCurrentState != nullptr)
        m_pCurrentState->Exit(m_pOwner);
    m_pPreviousState = m_pCurrentState;
    m_pCurrentState = pNewState;
    m_pCurrentState->Enter(m_pOwner);
}
 
 
/* 현재 상태와 Global상태를 Execute */
template <class T>
void CStateMachine<T>::Execute(float delta) const
{
    if (m_pGlobalState != nullptr)
        m_pGlobalState->Execute(m_pOwner, delta);
    if (m_pCurrentState != nullptr)
        m_pCurrentState->Execute(m_pOwner, delta);
}
 
 
/* FSM을 사용하고자 하는 주체 */
T* m_pOwner;
 
 
/* Previous 상태는 직전의 상태를 보관한다. 
 * Current에 들어있는 상태를 실행한다.
 * Global은 어떠한 상황에서도 가장 먼저 반영된다. */
CState<T>*            m_pPreviousState;
CState<T>*            m_pCurrentState;
CState<T>*            m_pGlobalState;
cs

CStateMachine<T> 클래스의 주요 함수 및 동작원리 설명

1. 유한 상태 머신 디자인 패턴으로 구현되어 있습니다.

2. Generic Programming 을 위한 Template으로 정의 되어있습니다. 

3. ChangeState에서 이전 상태의 후 처리 함수를 호출하고 새로운 상태의 전처리 상태를 호출하면서 변경합니다.

4. 오브젝트의 AI를 상태머신으로 관리하고 싶을때 Component로 정의하면됩니다. 


FSM 사용 예 ( Player의 FSM ) 

1
CStateMachine<CPlayer>* m_FSM;
cs

1. 플레이어의 AI를 FSM으로 관리하기 위해 정의

2. Player::Execute에서 FSM의 Execute 실행

3. Player의 AI상태를 실행 및 변경 합니다.



아래는 위 FSM 이 관리하는 State 추상클래스입니다.


State 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*---------------------------CState----------------------------
 * Template 클래스
 * FSM을 소유하는 클래스의 상태를 정의하는 추상클래스
 * State의 인터페이스만을 제공한다.
 * 각 함수는 모두 FSM의 주체 인스턴스를 인자로 받는다.
--------------------------------------------------------------*/
 
 
 
 
/* template으로 정의됨 */
template <class T>
 
 
/* Enter()은 상태가 Execute를 실행하기 전에 한번만 호출된다. */
virtual void Enter(T* pOwner) = 0;
 
 
/* Execute()은 상태의 메인 루프이다. */
virtual void Execute(T* pOwner, float delta) = 0;
 
 
/* Exit()은 상태가 종료 혹은 변경될 때 한번만 호출된다. */
virtual void Exit(T* pOwner) = 0;
cs

1. 위의 FSM이 관리하는 State들의 인터페이스 클래스입니다.(추상클래스)

2. 어떤 오브젝트이든 상태를 가질 수 있도록 template으로 정의하였습니다.

3. 전처리를 위한 Enter, 반복 실행을 위한 Execute, 후처리를 위한 Exit으로 구성되어 있습니다.


사용 예(Player의 상태 중 1개)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
class CPlayerNormal : public CState<CPlayer>{
 
public:
    static CPlayerNormal* Instance();
    
    /* 상태 전 처리 */
    void Enter(CPlayer* player)
    {}    
 
    void Execute(CPlayer* player, float delta)
    {
        /* 현재 플레이어가 거인 아이템을 먹었다면 */
        if(eITEM_FLAG_giant & CItemManager::Instance()->getCurrentItem())
        {
            /* 거인 아이템을 먹은 상태로 상태 변경 */
            player->getFSM()->ChangeState(CPlayerGiant::Instance());    
        }
    }
 
    /* 상태 후 처리 */
    void Exit(CPlayer* player)
    {}
 
private:        
    CPlayerNormal(){}    
    virtual ~CPlayerNormal(){}
}
cs

1. CPlayerNormal은 플레이어 클래스의 상태 중 하나입니다.

2. 주체로써 Player의 인스턴스를 전달합니다 



귀차니즘을 위한 3줄 요약

1. 게임의 상태표현을 위해 FSM구현

2. Stage, Player, Bullet은 상태를 가진다.

3. 각각의 상태는 Ente, Execute, Exit의 상태를 가진다.

'All > Project' 카테고리의 다른 글

UI_ MyButton  (0) 2016.04.12
별게임의 상태트리  (0) 2016.04.12
Shooter / Bullet  (0) 2016.04.12
ObjectManager  (0) 2016.04.12
PoolingManager  (0) 2016.04.12

개요

별게임을 개발하면서 가장 많이 변경된 두 클래스라고 생각합니다.

그만큼 앞으로도 많이 변경될 것으로 보입니다.

먼저 코드 전에 간단하게 설명하자면 

Bullet은 모든 Bullet 파생클래스들의 Base클래스 입니다.

모든 Bullet 들 에게 공통적으로 필요한 AI 조종행동 이나 이펙트, action 등을 정의합니다.


Shooter 역시 모든 Shooter 파생클래스의 Base클래스 입니다.


두 클래스가 공통적으로 가지고 있는 함수가 있다면 바로 operator new 와 operator delete 함수 입니다.

operator new 함수는 메모리를 실제로 할당하지 않고 PoolingManager에서 받아오기 위해 정의하였고 

operator delete 는 operator new의 특성을 커버할 수 있도록 정의 되었습니다.

( operator new / delete 에 대한 자세한 설명은 아래 포스팅을 참조해주세요. )

[MemoryPooling_1]

[MemoryPooling_2]

[operator new / operator delete]



이제 코드를 보겠습니다.

(가독성을 위해 필요한 부분만 적절히 편집하였습니다.)



코드


operator new

1
2
3
4
5
6
/* poolingManager에서 FreeMemory Block을 하나 가져옴 */
void* CBullet::operator new(size_t sizeconst std::nothrow_t)
{
    // PoolingManager에서 메모리를 할당 받는다.
    return CPoolingManager::Instance()->BulletNew();
}
cs

PoolingManager의 관리를 받기 위한 operator new

create함수에서 새롭게 메모리 생성하는 것이 아니라 미리 생성해 두었던 메모리를 사용합니다.



ReturnToMemoryBlock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 오브젝트의 메모리를 FreeMemoryBlock으로 변환 == 오브젝트 삭제 */
void CBullet::ReturnToMemoryBlock()
{
    /*removeFromParent 의 이유 : 
    이유는 모든 CMover의 파생 객체들은 메모리 블럭에서 메모리를 할당 받는다.
    그로인해 실행 중 addChild시 같은 메모리를 여러번 addChild할 수 있다.
    때문에 메모리 블럭으로 되돌릴때에는 부모관계를 제거하여야한다.
    또 ReferenceCount를 1 낮춰야 하는 이유도 있다.*/
    this->removeFromParent();
    this->removeAllChildren();
    this->setVisible(false);
    this->setAlive(false);    
    CPoolingManager::Instance()->Bullet_ReturnToFreeMemory(this);
}
cs

사용이 끝난 오브젝트의 메모리를 PoolingManager로 돌려보냅니다.

돌려 보내기 전에 현재 오브젝트에 붙어있는 Children들을 해제하고 오브젝트 역시 부모로 부터 관계를 끊습니다.



Rotation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* 회전행렬을 이용하여 오브젝트 회전 및 이동 */
void CBullet::Rotation(float dir, float delta)
{
    // 회전 속도와 방향을 이용하여 각도를 구하고 라디안으로 변환
    float radian = CC_DEGREES_TO_RADIANS(dir * (m_fRotationSpeed * delta));
 
    // 현재의 Direction Vector를 저장한다.
    Vec2 beforeRotation = getPosition() - m_pPlanet->getPosition();
 
    // 거리도 저장
    float length = beforeRotation.length();
 
    /* 회전행렬을 구함 
     * rotate x = ((x_ * cos(angle)) - (y_ * sin(angle)))
     * rotate y = ((x_ * sin(angle)) + (y_ * cos(angle))) */
    m_RotationVec = Vec2(
    (float)((beforeRotation.x * cos(radian)) - (beforeRotation.y * sin(radian))),
    (float)((beforeRotation.x * sin(radian)) + (beforeRotation.y * cos(radian))));
 
    // 노말라이즈
    m_RotationVec.normalize();
    m_RotationVec *= length;
    
    // 기존의 좌표에 새로운 좌표를 더해준다.
    setPosition(m_pPlanet->getPosition() + m_RotationVec);
 
    // 오브젝트 자체도 회전
    setRotation(getRotation() - (dir *( m_fRotationSpeed * delta)));
}
cs

오브젝트의 회전을 정의 합니다. 

회전행렬을 이용하여 회전 후 좌표를 구하고 오브젝트 자체도 회전하여 줍니다.



R_BezierWithScale

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* 일정 위치로 베지어 곡선을 그리며 이동한 후 커지면서 FadeOut */
void CBullet::R_BezierWithScale(
Vec2 targetPos, 
Vec2 controlPoint_1,
Vec2 controlPoint_2, 
float time, float scale)
 
{
    // 더이상 Execute 하지 않는다.
    setAlive(false);
 
    // 베지어 곡선 생성
    ccBezierConfig bezier;
    bezier.controlPoint_1 = Vec2(controlPoint_1);
    bezier.controlPoint_2 = Vec2(controlPoint_2);
    bezier.endPosition = Vec2(targetPos);
 
    // 베지어 액션 및 다른 액션 순서대로 실행
    auto bezierTo1 = BezierTo::create(time, bezier);
    this->setZOrder(101);
    auto action = Sequence::create(
        bezierTo1,
        ScaleBy::create(0.5f, scale),
 
        // 두 액션이 끝난후 스케줄을 걸어 오브젝트 삭제
        CallFunc::create([&](){
        this->scheduleOnce([=](float dt){
            this->ReturnToMemoryBlock();
        }, 1.0f, "BezierWithScale");
 
    }), nullptr);
    this->runAction(action);
 
    // texture 페이드 아웃
    auto textureAction = FadeOut::create(2.0f);
    m_pTexture->runAction(textureAction);
}
 
cs

오브젝트의 특정 action을 정의합니다. R_은 ReturnToMemoryBlock을 호출한다는 약자입니다.


'All > Project' 카테고리의 다른 글

별게임의 상태트리  (0) 2016.04.12
AI_ FSM / State  (0) 2016.04.12
ObjectManager  (0) 2016.04.12
PoolingManager  (0) 2016.04.12
게임 전체 클래스 UML 및 간단설명  (0) 2016.04.12

개요

PoolingManager에서 생성한 MemorBlock을 게임 오브젝트로서 관리하기 위해 CObejctManager를 만들었습니다.

자세한 설명은 아래 코드와 함께하겠습니다.

(역시 가독성을 위해 적당히 편집하였습니다.)


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*------------------------ObjectManager--------------------------
*
* singleton class
* CMover를 상속받는 모든 클래스를 Execute및 Remove하는 함수이다.
* RemoveAllBullet()함수는 Mover->Delete()함수를 호출한다.
* Delete()에서 removeFromParent()와 operator delete를 호출하여 소멸자를 호출하기 위함
*
*---------------------------- ----------------------------------*/
 
 
 
 
/* PoolingManager에서 CreateBulletList할 때  
생성된 메모리를 관리하기 위해 이곳에 넣는다. */
void AddBullet(void* bullet){
    m_BulletList.emplace_back(static_cast<CBullet*>(bullet));
}
 
 
/* Bullet을 create할 때 이 리스트에 넣는다. */
void Auto_ReturnToMemoryBlock(CBullet* bullet){
    m_ReturnToMemoryBlockList.emplace_back(bullet);
}
 
 
/* 게임 종료 시점에 호출된다. */
void RemoveAllObject(){
    for (auto bullet : m_BulletList)
    {
        if (bullet->HasPointer()) 
            bullet->Delete();
    }
}
 
 
/* Alive 상태의 오브젝트를 Execute한다. */
void Execute(float delta){
    // 지워진 오브젝트는 returnToMemoryBlock을 호출한다.
    ReturnToMemoryBlockEveryFrame();
 
    // 오브젝트의 Execute를 호
    for (auto bullet : m_BulletList)
    {
        if (bullet->IsAlive()) {
            bullet->Execute(delta);
        }
    }
}
 
 
//callback
/* LeftButton RightButton 누르면 호출된다. */
void RotationObject(int dir){
    for (auto bullet : m_BulletList)
    {
        if (bullet->IsAlive()) {
            bullet->Rotation(dir);
        }
    }
}
 
 
/* ReturnToMemoryBlockEveryFrame()
 * 지운 오브젝트들의 ReturnToMemoryBlock을 즉시 호출하면
 * 같은 프레임에서 생성한 오브젝트들이 앞에서 Free로 만든 메모리를 참조할 수 있으므로
 * 한프레임 늦게 메모리 블럭으로 되돌리기 위해서. */
void ReturnToMemoryBlockEveryFrame()
{
    for (auto bullet : m_ReturnToMemoryBlockList)
    {
        if (!bullet->IsAlive()) {
            CPoolingManager::Instance()->Bullet_ReturnToFreeMemory(bullet);
        }
    }
}    
 
 
/* 생성된 메모리를 Object로 캐스팅하여 담을 리스트 */
std::vector<CBullet*> m_BulletList;
 
 
/* Alive가 false인 오브젝트들을 MemoryBlock으로 변경*/
std::vector<CBullet*> m_ReturnToMemoryBlockList;
 
cs

CObjectManager 클래스의 주요 함수 및 동작원리 설명

1. AddBullet을 호출하여 메모리 블럭을 Bullet으로써 관리하도록 합니다.

2. Bullet의 Create()함수에서 Auto_ReturnToMemoryBlock()을 호출하여 m_ReturnToMemoryBlockList에 등록합니다.

3.  m_ReturnToMemoryBlockList에 등록된 오브젝트 중 Alive가 false인 것은 다음 프레임에서 메모리블럭으로 되돌아갑니다.



사용 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* 사용 예 Auto_ReturnToMemoryBlock()에 포인터 등록  */
 
/* operator new */
void* CNormalBullet::operator new(size_t sizeconst std::nothrow_t)
{
    // PoolingManager에서 메모리를 할당 받는다.
    return CPoolingManager::Instance()->BulletNew();
}
 
 
CNormalBullet* CNormalBullet::create(
    std::string textureName,        //bullet 이미지
    float boundingRadius,           //bullet 충돌 범위
    float angle,                    //bullet 초기 각도 
    float speed)                    //bullet 초기 속도
{
    // operator new 호출 후 CNormalBullet 생성자로 초기화
    CNormalBullet* pRet = 
        (CNormalBullet*)new(std::nothrow)CNormalBullet(
        textureName, boundingRadius, angle, speed);    
 
    // nothrow로 인해 초기화 되지 않으면 nullptr반환됨
    if (pRet && pRet->init())
    {
        // ObjectManager의 Auto_ReturnToMemoryBlock()에 등록
        pRet->Auto_ReturnToMemoryBlock();
        return pRet;
    }
    else
    {
        delete pRet;
        pRet = NULL;
        return NULL;
    }
}
cs

1. pRet->Auto_ReturnToMemoryBlock()에서는 ObjectManager의 Auto_ReturnToMemoryBlock()를 this를 인자로 전달하며 호출합니다.

2. ObjectManager의 Auto_ReturnToMemoryBlock()은 m_ReturnToMemoryBlockList 에 전달 받은 포인터를 등록합니다.


사용 예

1
2
3
4
5
/* 사용 예 RemoveAllObject 호출 */
CGameScene::~CGameScene()
{
    CObjectManager::Instance()->RemoveAllObject();
}
cs

1. Scene변경 및 종료 시 RemoveAllObject()를 호출합니다.

'All > Project' 카테고리의 다른 글

AI_ FSM / State  (0) 2016.04.12
Shooter / Bullet  (0) 2016.04.12
PoolingManager  (0) 2016.04.12
게임 전체 클래스 UML 및 간단설명  (0) 2016.04.12
게임 개요  (0) 2016.04.11

개요.


먼저 제가 만든 poolingManger는 아래 두 책에 나오는 내용을 기반으로 만들어 졌다는 것을 미리 밝힙니다.

               


앞에서도 이야기 했듯이 

별 게임은 별, 총알, 아이템 등이 매우 많이 만들어 지고 삭제됩니다..

때문에 게임 개발을 하는 것에 있어서 가장 먼저 고려했던 것이.. 

1. 생성과 삭제의 리스크

2. 메모리 단편화

위 두 가지 이유로 인한 게임 성능 저하 였습니다.

게임이 렉이 걸리고 느리면 게임을 하는 입장에서는 매우 답답하며 화가나는 것은 당연한 사실이니까요.

그래서 고민을 하다가 PoolingManager를 만들게 된 것입니다.



아래는 PoolingManager의 코드 및 간단한 설명입니다. 


(그리고 MemoryPooling에 대해 자세한 설명을 보고싶으시면 아래 포스트들을 참조해 주세요. )

[MemoryPooling_1]

[MemoryPooling_2]

[operator new / operator delete]



먼저 완성된 코드는 아래와 같습니다.

(가독성을 위해 적당히 편집하였습니다.)


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*-----------------------CPoolingManager------------------------
 *
 * singleton pattern
 * 동작 사이클은 아래와 같다.
 *
 * 1. CreateBulletList() - 원하는 만큼의 메모리 블럭 생성 및 리스트에 추가
 * 2. BulletNew() - 생성하고자 하는 오브젝트로 초기화(operator new, 생성자 호출)
 * 3. 사용
 * 4. ReturnToFreeMemory() - 메모리 반환
 * 5. 사용할 때 마다 2번부터 반복 
 * 6. 게임 종료시 메모리 해제
 *
----------------------------------------------------------------*/
 
 
 
/* 메모리 블럭 타입 정의    */
typedef char* MEMORYBLOCK;
 
 
/* size만큼의 메모리 블럭을 생성한다. */
MEMORYBLOCK NewMemoryBlock(size_t sizeconst
{
    /* memoryAlive flag를 위한 1바이트 추가 생성 */
    MEMORYBLOCK block = new char[size + 1];
 
    /* memory 초기화 및 memoryAlive = false */
    memset(block, 0size + 1);                
    return block;
}
 
 
/* size만큼의 char형 포인터를 count만큼 Bullet리스트에 add */
void CreateBulletList(size_t count, size_t size)
{
    m_BulletSize = size;
    m_BulletList.reserve(m_BulletSize);
    while (count--)
    {
        /* 하나의 크기가 size만큼의 메모리 블럭을 count만큼 생성한다. */
        MEMORYBLOCK memBlock = NewMemoryBlock(m_BulletSize);    
        m_BulletList.emplace_back(memBlock);
 
        /* 오브젝트 매니저 리스트에 추가한다. */
        CObjectManager::Instance()->AddBullet(memBlock);
    }
}
 
 
/* pool이 보유한 메모리 리스트가 생성하려는 것보다 적으면 새로 생성 */
void* BulletNew()
{
    for (auto bullet : m_BulletList)
    {
        /* 메모리가 Free(false)상태면 메모리를 사용 중 상태(true)로 전환 후 반환 */
        if (false == bullet[m_BulletSize]) {    
            bullet[m_BulletSize] = true;        
            return bullet;
        }
    }
 
    /* 모든 메모리가 사용 중 상태라면 새롭게 하나 생성 */
    CCLOG("BULLET LIST OVERFLOWED");
    MEMORYBLOCK memBlock = NewMemoryBlock(m_BulletSize);
    m_BulletList.emplace_back(memBlock);
 
    /* 오브젝트 매니저 리스트에 추가한다. */
    CObjectManager::Instance()->AddBullet(memBlock);
 
    /* 메모리를 사용 중 상태로 전환 */
    memBlock[m_BulletSize] = true;    
 
    return memBlock;
}        
 
    
/* Bullet을 메모리블럭으로 전환 (alive off) */
void Bullet_ReturnToFreeMemory(void* bullet)
{
    static_cast<char*>(bullet)[m_BulletSize] = false;
}        
 
 
/* 모든 메모리를 해제한다. (게임이 종료되거나 Scene이 변경될때 호출) */
void DeleteAllMemory()
{
    for (auto bullet : m_BulletList)
    {
        delete[] bullet;
        bullet = nullptr;
    }
    m_BulletList.clear();
}                            
 
 
/* 메모리 블럭 리스트 */
std::vector<MEMORYBLOCK> m_BulletList;
 
 
/* 메모리 블럭 하나 당 크기 */
int m_BulletSize;
cs

CPoolingManager 클래스의 주요 함수 및 동작원리 설명


1. memoryPooling기능을 수행하는 singleton 클래스 입니다.

2. 게임을 시작할 때 원하는 사이즈의 메모리 블럭을 원하는 개수만큼 미리 생성해 놓습니다.

3. 사용자는 필요할 때 해당 메모리들을 사용할 수 있습니다. 

4. MemoryPooling의 관리를 받고 싶다면 해당 클래스의 operator new에서 PoolingManager의 New를 호출해주면 됩니다. 

6. 그러면 미리 생성된 메모리 중 Free상태의 메모리를 할당 받을 수 있습니다. 



사용 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* 사용 예 1 객체 초기화 */
 
/* operator new */
void* CNormalBullet::operator new(size_t sizeconst std::nothrow_t)
{
    // PoolingManager에서 메모리를 할당 받는다.
    return CPoolingManager::Instance()->BulletNew();
}
 
 
CNormalBullet* CNormalBullet::create(
    std::string textureName,        //bullet 이미지
    float boundingRadius,           //bullet 충돌 범위
    float angle,                    //bullet 초기 각도 
    float speed)                    //bullet 초기 속도
{
    // operator new 호출 후 CNormalBullet 생성자로 초기화
    CNormalBullet* pRet = 
        (CNormalBullet*)new(std::nothrow)CNormalBullet(
        textureName, boundingRadius, angle, speed);    
 
    // nothrow로 인해 초기화 되지 않으면 nullptr반환됨
    if (pRet && pRet->init())
    {
        // ObjectManager의 Auto_ReturnToMemoryBlock()에 등록
        pRet->Auto_ReturnToMemoryBlock();
        return pRet;
    }
    else
    {
        delete pRet;
        pRet = NULL;
        return NULL;
    }
}
cs

사용 예 (객체 초기화)

1. NormalBullet의 create에서 호출하는 new는 operator new 로 poolingManager의 New함수를 호출합니다.

2. PoolingManager의 New함수는 미리 생성된 Free메모리를 반환합니다.

3. 반환된 MemoryBlock은 CNormalBullet 생성자로 초기화 되어 사용합니다. 


1
2
3
4
5
6
7
8
9
10
11
/* 사용 예 2 메모리 반환 */
    
void CNormalBullet::ReturnToMemoryBlock()
{
    this->removeFromParent();
    this->removeAllChildren();
    this->setVisible(false);
    this->setAlive(false);    
}
 
cs

사용 예 (메모리 반환)

1. 사용한 메모리를 Free메모리로 반환하려면 setAlive(false) 하면 됩니다.

2. alive가 false인 오브젝트는 다음 프레임에서 Free메모리로 전환됩니다.

3. this->removeFromParent();

    this->removeAllChildren();

    this->setVisible(false);

    this->setAlive(false);

4. 위 일련의 작업들은 현재 오브젝트에 AddChild되어 있는 메모리들을 해제해주는 것과 부모로부터 현재 메모리를 단절시키는 작업을 진행합니다. 



EXTRA : 

처음엔 addChild되어야만 object로써 제대로된 구실을 하는 cocos2dx의 특성을 고려하여 

createBulletList할 때 모든 NormalBullet 등의 최상위 클래스인 CBullet으로 생성한 후 addChild까지 했었습니다.

게임 중 addChild하는 비용까지 없애자는 야심찬 계획이었지만 다음과 같은 이유로 뻘짓이 되었습니다.


1. bullet으로 생성자를 호출하여 초기화 하면 이후 normalBullet으로써 사용하지 못한다.

    (normalBullet의 생성자를 호출한 것이 아니기 때문에 다형성 불가.)


2. 그래서 처음에 Bullet으로 초기화 후 사용할 때 NormalBullet으로 다시 초기화 해보았는데 

    이때는 Ref생성자 호출 과정에서 RefCount가 다시 1이 되기 때문에 이전의 addChild 한 것이 소용없어졌습니다.

    (그리고 생성자를 두 번 호출하는 말도 안되는 문제가 있었죠.)


3.  Bullet으로 생성한 메모리를 NormalBullet으로 사용하려면 두 클래스의 크기가 같아야 했습니다.


위와 같은 일이 있었기에 지금의 모습인 Char* 형으로 모든 Bullet보다 적당히 큰 메모리 블럭을 만들어 놓고 

사용할 때 operator new를 이용하여 NormalBullet이든 SpecificBullet이든 초기화하여 사용할 수 있도록 변경하였습니다.

다형성을 이용할 수 있게된 것이죠.


현재 구조를 보면 사용할 때마다 addChild및 RemoveFromParent를 하고 있습니다.

같은 메모리를 반복해서 사용하니까 당연하게 해주어야 할 일이긴 한데.. 뭔가찜찜한 상태라 차후에 리펙토링을 고려하고 있습니다.



귀차니즘을 위한 3줄 요약

1. PoolingManager구현 

2. 별게임에 적용

3. 게임성능 UP



'All > Project' 카테고리의 다른 글

Shooter / Bullet  (0) 2016.04.12
ObjectManager  (0) 2016.04.12
게임 전체 클래스 UML 및 간단설명  (0) 2016.04.12
게임 개요  (0) 2016.04.11
MemoryPooling_2  (0) 2016.03.15

+ Recent posts