본문 바로가기

Cocos2d-x v3.17/고급 기능

[Cocos2d-x 고급기능]물리엔진 소개 및 용어

반응형

    소개


    전에 봤던 챕터를 공부한것만으로도 당신은 재밌는 게임을 만들수 있습니다.

    하지만 당신이 복잡한 게임을 제작하려하면 현실세계의 장면을 시뮬레이션 해야 합니다.

    예를 들면 두개의 물체가 충돌하거나 물체가 중력을 받아야 한다거나 할때 어떻게 할까요?

    걱정하지 마세요.

    이번챕터에선 물리엔진을 소개합니다.

    우리가 어떻게 물리엔진을 사용해야 하는지 알아봅시다.

    엔진을 사용해야 하는지?

    당신이 처리해야 할것이 간단할 경우엔 물리엔진을 사용할 필요가 없습니다.

    예를들면 두개 객체가 서로 충돌할시 객체의 update함수와 Rect객체의 containsPoint()intersectsRect() 메서드를 사용하면 충분할겁니다.

     

    예를들면:

    C++

    void update(float dt)

    {

      auto p = touch->getLocation();

      auto rect = this->getBoundingBox();

    if(rect.containsPoint(p))

      {

          // do something, intersection

      }

    }

     

     

    이런 교차검사는 두개 객체가 충돌했는지를 알수 있습니다.

    하지만 아주 간단한 처리만 가능하고 확장이 불가능 합니다.

    당신이 게임을 개발할건데 하나의 씬에 100개의 스프라이트 객체가 존재한다면 그것들이 서로 충돌이 됬는지를 알아야 합니다.

    하지만 이러한 방법을 사용하면 코드가 굉장히 복잡해지고 성능저하도 심각하게 일어납니다.

    CPU사용률이 높아지고 그렇기 때문에 프레임레이트 저하가 되어서 플레이를 할수 없는 게임이 되버립니다.

     

    이럴때 물리엔진을 사용하여야 합니다.

    물리장면  시뮬레이션은 확장성이 좋고 성능저하도 낮습니다.

    위에서 예를 들었던 장면에선 물리엔진을 사용하는것이 최선의 선택방법이 될겁니다.

    처음 물리엔진을 접해본다면 당연히 낯설을 겁니다.

    이제 우리는 아래의 간단한 예제를 보고 용어를 설명하고 공부해봅시다.


    C++

    // create a static PhysicsBody

    auto physicsBody = PhysicsBody::createBox(Size(65.0f , 81.0f ), PhysicsMaterial(0.1f1.0f0.0f));

    physicsBody->setDynamic(false);

    // create a sprite

    auto sprite = Sprite::create("whiteSprite.png");

    sprite->setPosition(Vec2(400400));

    // sprite will use physicsBody

    sprite->addComponent(physicsBody);

    //add contact event listener

    auto contactListener = EventListenerPhysicsContact::create();

    contactListener->onContactBegin = CC_CALLBACK_1(onContactBegin, this);

    _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

    위의 예제는 간단한 예제지만 당신에겐 복잡해보인다구요?

    걱정마세요.조금 분석해보면 그렇게 복잡하지 않다는걸 알게되실겁니다.

    코드 흐름

    1. PhysicsBody 객체 생성.
    2. Sprite 객체 생성
    3. PhysicsBody 객체는 컴포넌트의 형식으로 Sprite 객체에 추가해줍니다.
    1. 리스너를 생성하여 onContactBegin() 이벤트에 대응시켜 줍니다.

     

    인내심을 갖고 한단계씩 분석해봅시다.점점  과정이 이해가 되실겁니다.

     

     

    출처: <http://cocos2d-x.org/docs/cocos2d-x/zh/physics/>


    용어와 개념

    물리엔진을  이해하기 위해서 먼저 일부 용어와 개념을 알아봅시다.

    Bodies(강체)

    강체(Bodies)  추상적인 객체의 물리속성을 설명합니다.질량,위치,회전각도,속도와 damping 포함합니다.

    Cocos2d-x안에서는 PhysicsBody 객체가 강체입니다.

    강체와 도형이 연동되면 강체객체는 기하학적 모양을 갖게 됩니다.도형과 연동되지 않았다면 강체는 그저 추상객체의 물리속성 집합입니다.

     

    재질(Material)

    재질(Material) 추상객체의 재질속성을 설명합니다

    • density: 밀도.물체의 질량을 계산하기 위해 사용됩니다.
    • friction: 마찰.물체간에 마찰을 시뮬레이션하지 위해 사용됩니다.
    • restitution:회복계수.물체의 리바운드를 시뮬레이션 하기 위해서 계수로 표현합니다.계수는 0 1사이이며 0 리바운드가 없다는 소리고 1 최대치의 리바운드 입니다

    도형(Shape)

    도형(Shape)  추상물체의 기하학적 속성을 설명합니다.도형을 강체에 연동시키면 강체는 기하학적 모양을 가지게 됩니다.

    만약 강체가 복잡한 모양을 가져야 한다면 여러  모양을 연동시켜서 모양마다PhysicsMaterial  연동시킵니다type, area, mass, moment, offset 和 tag 속성을 가지고 있고 개중에 익숙하지 않은것들도 있을겁니다.

    한번보시죠.

    • type: 모양을 설명합니다.원형,사각형,다각형등이 있습니다.
    • area:강체의 질량을 계산하기 위한값입니다.밀도와 면적이 강체의 질량을 결정합니다.
    • mass:강체의 질량입니다.물체가 일정힘을 가했을때 가속도의 크기에 영향을 미치고,물체가 중력장에서 힘을 받는 크기를 결정합니다.
    • moment: 강체가 특정각가속도에서 필요한 토크를 얻어옵니다.
    • offset:강체의 위치값에서 강체중심점의 상대적인 오프셋입니다.
    • tag:도형객체의 태그입니다.아직 기억하실지 모르겠지만 모든 노드객체에는 하나의 tag 부여할수 있습니다.객체를 식별하고 더욱쉽게 액세스하기 위함입니다.도형객체의 tag 똑같은 일을 하고있습니다.

    Cocos2d-x 미리 정의된 도형객체가 있습니다.

    • PhysicsShape물리도형의 기본클래스입니다.
    • PhysicsShapeCircle속이 채워져있는 원형입니다.이객체로 속이 비어있는 원형으로 사용할수 없습니다.
    • PhysicsShapePolygon솔리드 다각형
    • PhysicsShapeBox사각형,이것은 특별한 ShapePolygon입니다.
    • PhysicsShapeEdgeSegment
    • PhysicsShapeEdgePolygon속이 비어있는 다변형입니다.여러 선으로 구성된 다각형입니다.
    • PhysicsShapeEdgeBox속이 비어있는 사각형입니다.네개의 선으로 이워져있습니다.
    • PhysicsShapeEdgeChain체인모양입니다.여러 변을 연결시킬수 있습니다.

    연결(Contracts) / 관절(joint)


    연결(Contacts)  관절(joint) 객체는 강체의 서로 연관되있는 방식을 설명합니다.

     

    월드(World)

    월드는 물리 월드를 시뮬레이션합니다

    모든 추상객체들이 들어있습니다.

    당신은 강체,도형,제약조건 모두를 물리월드에 추가시키고 모든 월드에 대하여 업데이트 하면됩니다.

    물리월드는 모든 요소의 상호작용을 제어합니다.

    그중에는 실제로 물리API 사용하여 구현  여러 상호작용은 월드와 관련이 있습니다.

    위에는 기억해야 할것들이 많습니다.

    이것들을 대충을 기억하셨으면 좋겠고 사용될때 기억이나서 다시 찾아볼수 있도록 하면 좋을것 같습니다.


    PhysicsWorld


    물리월드(PhysicsWorld) Cocos2d-x 물리시뮬레티션하기 위한 핵심 객체입니다.

    물리월드는 동시에 여러 이벤트가 발생할수 있습니다.

    우리가 살고있는 세계처럼 말이죠.

    현실세계의 주방을 한번 상상해봅시다.

    당신이 상상하고 있을때 당신의 뇌에선 물리월드의 주방을 렌더링 합니다.

    주방에는 어떤 물체, 먹을것,,가전제품  있을것이고  월드에서  물체들은 상호작용을 할겁니다.

    그것들은 서로 접촉할수도 있을것이고 접촉한다면 어떤 반응을 할겁니다.

    예를들면 칼로 먹을것을 자르고 그것을 가전제품에 조리하는것같은 일을 한다고 가정합니다.

    칼이 먹을것을잘랐습니까?어쩌면 잘랐을수도 있고 어쩌면 안짤랐을수도 있습니다.

     어쩌면  칼은 이것을 자르기에 적합하지 않을수도 있습니다.

     

    물리월드  씬이 내부에서 결합하여 Scene객체의 InitWithPhysics() 메서드만 사용하면 물리월드를 포함한 Scene 생성할수 있습니다.

    초기화할때 함수의 리턴값에대해 알아봅시다.

     

    initWithPhysics() 초기화성공시 true,실패면 false  반환합니다.

    C++

    if( !Scene::initWithPhysics() )

    {

    }


    물리월드마다 아래와 관련이 있는 속성이 있습니다:

    • gravity:중력.모든 월드에 통용되며 디폴트값은 Vec2(0.0f,-98.0f)입니다.
    • speed:물리월드의 속도.여기서 속도는  월드를 시뮬레이션하는 일종의 비율입니다.디폴트값은 1.0 입니다.
    • updateRate:물리월드의 업데이트 빈도입니다.여기서 업데이트 빈도는 게임엔진의 업데이트시간과 물리월드 업데이트 시간의 비율입니다.
    • substeps:물리월드에서 매번 업데이트되는 substeps .

    물리월드를 업데이트 하는 과정을 스텝(Step)이라고 합니다.

    디폴트값으로 설정된다면 물리월드는 계속해서 자동으로 업데이트 됩니다.이것을 AutoStep이라고 합니다. 프레임마다 업데이트가 되지만 setAutoStep(false) 메서드를 사용하여 AutoStep 중지하고 PhysicsWorld::step(time) 메서드를 사용하여 정해진시간마다 업데이트 하게 할수 있습니다.

    게임월드는 프레임마다 업데이트 되지만 물리월드는 Substeps설정을 통해 더욱 빈번한 업데이트를 진행할수 있고 step 더욱 정밀하게 제어할수 있습니다.

     

     

    물리강체(PhysicsBody) 객체는 위치와 속도를 가지고 있습니다. 

    당신은 물리강체에 힘을 가하거나(forces) 물리운동(movement)이나 damping,충격(impulses)등등을 할수있습니다.

    강체는 정적일수도 있고 동적일 수도 있습니다.

    정적인 강체는 가상세계에서 이동하지 않습니다.보기엔 질량이 엄청나게 커서 안움직이는것처럼 말이에요.

    동적강체는 리얼한 시뮬레이션을 하는 강체입니다.

    강체는 힘의 가해서 유저가 수동적으로 이동시킬수 있습니다.

    동적 강체는 모든 종류의 충돌을 발생시킬수 있습니다.

    Cocos2d-x Node::setPhysicsbody()메서드를 제공하여 물리강체와 노드객체를 연결시킬수 있습니다.

     이제 정적물리강체 객체를  ,다섯개의 동적 물리강체 객체를 생성해보고 동적강체 객체를 움직이게 해봅시다:


    C++

    auto physicsBody = PhysicsBody::createBox(Size(65.0f81.0f),

                            PhysicsMaterial(0.1f1.0f0.0f));

    physicsBody->setDynamic(false);

    //create a sprite

    auto sprite = Sprite::create("whiteSprite.png");

    sprite->setPosition(s_centre);

    addChild(sprite);

    //apply physicsBody to the sprite

    sprite->addComponent(physicsBody);

    //add five dynamic bodies

    for (int i = 0; i < 5; ++i)

    {

        physicsBody = PhysicsBody::createBox(Size(65.0f81.0f),

                        PhysicsMaterial(0.1f1.0f0.0f));

    //set the body isn't affected by the physics world's gravitational force

        physicsBody->setGravityEnable(false);

    //set initial velocity of physicsBody

        physicsBody->setVelocity(Vec2(cocos2d::random(-500,500),

                    cocos2d::random(-500,500)));

        physicsBody->setTag(DRAG_BODYS_TAG);

    sprite = Sprite::create("blueSprite.png");

        sprite->setPosition(Vec2(s_centre.x + cocos2d::random(-300,300),

                    s_centre.y + cocos2d::random(-300,300)));

        sprite->addComponent(physicsBody);

    addChild(sprite);

    }


    결과적으로는 다섯개의 동적물리강체 객체와 하나의 정적 물리강체 객체가 사진처럼 계속 충돌합니다:


    출처: <http://cocos2d-x.org/docs/cocos2d-x/zh/physics/concepts.html>



반응형