ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 포물선(이차함수)을 활용해서 원하는 물체에 미사일 날리기 - Cocos2D 활용
    Algorithm with C/Math 2021. 4. 7. 09:13

    개발환경 : cocos2d-1.0.0-x-0.9.0 와 Visual Studio 2008

    WinAPI와 Cocos2D는 좌표계가 서로 다르다.

    Cocos2D에서는 좌측하단이 원점이다.

    즉, 우리가 보편적으로 사용하는 좌표계와 같다.

     

    이차 함수에 대한 내용은 아래의 글을 읽어 보자.

    designatedroom87.tistory.com/130?category=887656

     

    API를 활용한 이차함수를 이용해 점프 기능 만들기

    a가 양수냐, 음수냐에 따라서 이차함수의 그래프의 개형이 달라진다. 그림 출처 : terms.naver.com/entry.nhn?docId=945470&cid=47324&categoryId=47324 0이면 아래로 볼록 a < 0이면 위로 볼록 ⑷ |a|가 클수록..

    designatedroom87.tistory.com

     

     

    [그림 1]

    [그림1 ]에서 보다시피 Hero에서 물체까지의 거리는 d이며,

    붉은색 포물선이 바로 미사일이 발사될 궤도이다.

    먼저, 구현 방법부터 설명하면 미사일과 미사일 그림자 2개를 만들 것이다.

    여기서부터는 Cocos2D 엔진에서 제공해주는 함수를 사용할 것인데, addChild라는 함수를 사용할 것이다.

    즉, 미사일 그림자에 미사일을 addChild할 것이다.

    addChild를 하게 되면, 미사일 그림자가 움직이게되면 미사일도 같이 움직이게 된다.

    즉, addChild 라는 함수를 사용해서 미사일 그림자 입장에서 미사일을 자식으로 가지게 된다.

    미사일 그림자만 이동시키면 자동으로 미사일도 함께 움직이고, 

    반대로 미사일만 움직이게되면, 미사일 그림자는 움직이지 않는다.

    바로 이것을 이용해서 미사일을 움직이게 할 것이다..

    즉, 큰 그림으로 보면, 먼저 미사일 그림자를 위의 거리 d를 따라서 움직이게 만들면 미사일은 같이 움직인다.

    여기서 미사일 자체에 높이 값을 부여해서 거리d쪽으로 이동해 가면서

    미사일의 높이가 변하면서 움직이게 된다.

    스케이트 보드와 사용자의 관계로 설명하는 것이 가장 쉬운 예제일 것 같다.

    마치 스케이트 보드를 타다가 사용자가 점프를 한 이후에 다시 스케이트 보드에 착지하는 것으로 생각하면 된다.

    여기서 미사일의 높이는 포물선 방정식( 이차 함수)을 이용한다.

     

    아래의 [그림 2]를 보자.

    그림자는 거리d 방향으로 움직이게 하면, 미사일도 같이 움직이는데, 이 때 미사일의 높이를

    변하게 만들어주면 만들 수 있다.

    [그림 2]

     

    위의 내용에 따라서, 우리는 기본적으로 2개의 함수를 만들어야 함을 알 수 있다.

    미사일의 그림자를 이동하는 함수와 미사일을 이동하는 함수가 필요하다.

    그리고 플레이어에서 물체로 이동을 하려면 이동 방향 벡터가 필요하다는 사실 또한 알 수 있다.

     

     

     

    (1). 미사일의 이동 방향 벡터를 구하는 함수인 GetMissileVector 함수 만들기.

    위의 그림을 벡터로 표현을하면 아래와 같다.

    미사일 그림자가 d벡터 방향으로 움직이므로, d벡터를 구하는 것이다.

    [그림 3]

    d벡터를 구하는 방법은 Hero와 물체의 좌표를 얻어와서 구할 수 있다.

    그리고, 거리 또한 구할 수 있다.

    벡터d를 구하면 벡터d를 단위벡터화 과정까지 처리한다.

    벡터는 크기와 방향을 갖는데, 이 크기를 보통 1이 되도록 처리를 한다.

    d벡터가 아래의 Missile_vec 이다.

     

     

     

    (2). 미사일 그림자를 타겟으로 이동시키는 함수인 MissileShadowAction함수 만들기.

    MissileShadowAction함수에서 해야할 일은,

    미사일 그림자를 위 [그림 3] 에서 보다시피 거리d를 향해 움직이게 만드는 것이다.

    GetMissileVector함수에서 미사일의 이동 방향 벡터를 구했기 때문에,

    이 함수내에서는 그 방향대로 미사일 그림자의 좌표를 이동시켜주기만 하면 된다.

    이동 방향 벡터는 Missile_vec 라고 하였는데 아래의 코딩에서는 Missile_Shadowvec 을 사용 했는데

    그 이유는 미사일이 발사가 될 때,  Missile_vec 을 구하고 나서

    Missile_ShadowvecMissile_vec 값이 저장이 되므로 이는 서로 같은 값을 가진다.

    굳이 Missile_vec 변수를 사용하지 않고 Missile_Shadowvec별도로 선언을 한 이유는

    구분을 주기 위해서 이다. 

     

     

     

    (3). 실제 미사일을 이동 시키는 함수인 MissileAction함수 만들기.

    MissileAction함수에서 할 일은, 실질적인 미사일을 움직여주는 것이 목표이다.

    미사일은 [그림 1]의 포물선의 방정식을 이용해서 높이 값을 적절히 변경시켜주는 것이라고 하였다.

    그러면, 미사일이 착지하는 시점은 언제인지를 판별하는 것도 알아두어야 한다.

    즉, 높이가 0일 때, 미사일이 착지한 시점이다. [그림 1]을 조금 변경해서 그려보자.

    왜 높이가 0일 때, 미사일이 착지한 시점인지 아래의 그림을 통해 확인해보자.

    [참고]

    위 그림을 다음과 같이 변경해보면 위와 같다.

    그리고, 포물선의 방정식을 살펴보자.

    위에서와 같이 포물선의 방정식에 x = 0 과 x = d에서 높이y값은 0 이다.

    즉, x = d에서 d는 미사일이 움직일 거리이다.

    그렇기 때문에 미사일이 해당거리 d만큼 움직였을 때, 그 때의 높이값은 0이다. ( 방정식의 x에 d를 대입하면 안다. )

    그러므로, 미사일이 착지했는지는 높이가 0인지 아닌지로 판단한다.

    위에서와 같이, 먼저 실제 미사일의 좌표를 얻어와서,

    미사일이 착지했는지( 거리 d만큼 움직였냐 )를 판단해서, 착지했으면 이동이 끝났기 때문에

    변수값을 초기화를 시켜주면 되고,

    착지를 안했으면( 거리 d만큼 안 움직였기 때문에 ) Time변수를 증가시켜서

    그 때의 높이값을 구하면 된다. ( 포물선 식에 대입해서 높이값을 구함. )

    여기서, Time변수를 보통 상수값으로 누적을 시키는 것이 아니라, 움직인 거리로 정의 했다.

    [그림 4]

    위에서 처럼, 미사일의 이동 방향 벡터를 이용하면 Time을 구할 수 있다. ( 피타고라스의 정리 이용 )

    아래의 수식에서 오타가 하나 있는데, MissileVec2가 아니라 Missile_ShadowVec 이다.

    그리고, 미사일의 이동 방향 벡터를 이용했으므로, Time을 일종의 거리로 볼수 있다.

    그래서, Time만큼 움직였을 때, 미사일의 높이는 위의 [그림 4]와 같이 표현될 수 있다.

     

     

    프로그램 실행영상

     

     

     

    (4). MissileAction 함수 내에서 미사일을 회전시키기

    MissileAction함수는 실질적인 미사일의 높이 값을 적용해주는 부분이니까,

    미사일의 각도를 적용하는 것도 이 함수에서 처리를 하는 것이 올바르다.

    앞에서도 했듯이, 각도 회전은 어떻게 할까?

    위의 [그림 4]을 살짝 다음과 같이 변경하면 아래와 같은 그림이 된다.

    [그림 5]

     

    첫 번째로, Time2라는 변수를 하나 더 선언하자. 그리고, 높이 변수 fZ를 하나 더 선언한다.

    그러면 각도를 쉽게 구 할 수 있다.

    다시 아래의 [그림 6]을 보자. 

    [그림 6]은 위의 [그림 5]를 좀 더 확대한 그림이다.

    아래의 Time2는 Time보다 조금 더 지나간 시간이다.

    Time2 때의 높이가 fZ 이다.

    [그림 6]

    Width = Time2 - Time 이라하고, Height = fZ- m_fZ라 하면,

    arctan함수를 이용해서 각도 값을 구할 수 있다.

    그리고, setRotation함수에 각도값을 넣어주면 미사일 회전을 만들 수 있다.

    미사일의 회전은 미사일이 운동하고 있는 경우에만 처리를 하도록 한다.

    즉, 아래의 else문 내에 회전하는 부분이 추가가 되었다.

    회전에 대한 설명은 밑에서 하도록 한다.

    m_nextTime는 m_curTime변수보다 값을 크게 설정해서, 위 [그림 6]처럼 우측에 있게 만들어 주고,

    l_nextZ는 위 그림에서 fZ로, m_nextTime일 때의 높이이므로, 포물선 식에 대입한다.

    그리고, atan2함수로 각도를 얻어내서, setRotation함수에 각도값을 대입하면 된다.

     

    아래부분의 Dir변수가 있는것을 확인할 수 있는데, 미사일 각도 회전에 따른 방향 때문에 쓴 것이다.

     

    [참고]에 의하면 미사일의 발사 궤적은 두 종류 밖에 없다.

    플레이어를 기준으로 물체가 오른쪽에 있냐 왼쪽에 있냐가 기준이다.

    붉은 색 곡선이 미사일의 궤적 방향이다.

     

     

    이는 미사일의 이동 방향 벡터를 통해서 Dir를 결정할 수 있다.

    아래의 그림을 보자.

    아래의 theta가 미사일을 회전시킬 각도이다.

    이동 방향 벡터인 Missile_ShadowVec의 x가 양수이면,  아래의 오른쪽 그림이다.

    그리고 이 theta는 직교좌표계에서 1사분면을 의미한다.

    이는 그대로 arctangent 함수를 이용해서 구하면 된다. 부호의 변경이 필요 없다.

    반대로 이동 방향 벡터인 Missile_ShadowVec의 x가 음수이면,  아래의 왼쪽 그림이다.

    그리고 이 theta는 직교좌표계에서 2사분면을 의미한다.

    이는 그대로 Dir에 -1을 저장해서 부호를 변경해야 한다.

    그리고 arctangent 함수를 이용해서 구하면 된다.

     

     

    그리고 아래는 초기화를 처리하는 함수와 주기적으로 호출되는 함수들이다.

     

     

     

    프로그램 실행영상

    아래의 영상에서 플레이어와 타겟 간의 위치를 잘 보자.

    미사일의 궤적은 두 종류 밖에 없음을 알 수 있다.

     

     

    소스 파일 및 이미지 파일

    AppDelegate.cpp
    0.00MB
    AppDelegate.h
    0.00MB
    HelloWorldScene.cpp
    0.01MB
    HelloWorldScene.h
    0.00MB
    missile.png
    0.00MB
    player.png
    0.00MB
    target.png
    0.00MB

    댓글

Designed by Tistory.