2014년 2월 28일 금요일

[일기]box2D. UserData 개념 익히기.

#ifndef __MYUSERDATATEST_H__
#define __MYUSERDATATEST_H__

class Ball2 {
public:
        //전과 비교하여 멤버변수에 변화가 생겼다.
float m_radius;
b2Vec2 m_position;
float m_angle;
b2Vec2 m_linearVelocity;

Ball2(b2World* world, float radius) {
m_radius = radius;

b2BodyDef myBodyDef;
myBodyDef.type = b2_dynamicBody;
myBodyDef.position.Set(0, 20);
b2Body* body = world->CreateBody(&myBodyDef);

body->SetUserData( this );         //이 부분이 바뀌었다.

               //전에는 멤버로 강체의 포인터를 지니고 있었으나 현재는 그럴 필요가 없다.
               //상황이 반대이다. 강체가 이 클래스의 포인터를 유저 데이터로 갖는 것이다.

b2CircleShape circleShape;
circleShape.m_p.Set(0, 0);
circleShape.m_radius = m_radius;

b2FixtureDef myFixtureDef;
myFixtureDef.shape = &circleShape;
myFixtureDef.density = 1;

body->CreateFixture(&myFixtureDef);
}
~Ball2(){
}

void render(){

b2Vec2 vel = m_linearVelocity;
float red = vel.Length() / 20.0;
red = b2Min( 1.0f, red );
glColor3f(red,0.5,0.5);


glColor3f(red,1-red,1);//white

//nose and eyes
glPointSize(4);
glBegin(GL_POINTS);
glVertex2f( 0, 0 );
glVertex2f(-0.5, 0.5 );
glVertex2f( 0.5, 0.5 );
glEnd();

//mouth
glBegin(GL_LINES);
glVertex2f(-0.5,  -0.5 );
glVertex2f(-0.16, -0.6 );
glVertex2f( 0.16, -0.6 );
glVertex2f( 0.5,  -0.5 );
glEnd();

//circle outline
glBegin(GL_LINE_LOOP);
for (float a = 0; a < 360 * DEGTORAD; a += 30 * DEGTORAD)
glVertex2f( sinf(a), cosf(a) );
glEnd();
}

void renderAtBodyPosition() {
b2Vec2 pos = m_position;
float angle = m_angle;

glPushMatrix();
glTranslatef( pos.x, pos.y, 0 );
glRotatef( angle * RADTODEG, 0, 0, 1 );
glScalef( m_radius, m_radius, 1 );
render();
glPopMatrix();
}
};

std::vector<Ball2*> balls2;

class MyUserDataTest : public Test {

public:

MyUserDataTest(){
for(int i = 0; i < 20; i++){
float radius = 1 + 2 * (rand()/(float)RAND_MAX); //random between 1 - 3
Ball2* ball = new Ball2(m_world, radius);
balls2.push_back(ball);
}

//a static body
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody;
myBodyDef.position.Set(0, 0);
b2Body* staticBody = m_world->CreateBody(&myBodyDef);

//shape definition
b2PolygonShape polygonShape;

//fixture definition
b2FixtureDef myFixtureDef;
myFixtureDef.shape = &polygonShape;

//add four walls to the static body
polygonShape.SetAsBox( 20, 1, b2Vec2(0, 0), 0);//ground
staticBody->CreateFixture(&myFixtureDef);
polygonShape.SetAsBox( 20, 1, b2Vec2(0, 40), 0);//ceiling
staticBody->CreateFixture(&myFixtureDef);
polygonShape.SetAsBox( 1, 20, b2Vec2(-20, 20), 0);//left wall
staticBody->CreateFixture(&myFixtureDef);
polygonShape.SetAsBox( 1, 20, b2Vec2(20, 20), 0);//right wall
staticBody->CreateFixture(&myFixtureDef);
}

void Step(Settings* settings){
Test::Step(settings);



                //이 부분이 추가되었다. 사용자 데이터를 받아와 위치정보를 저장한다.
                //이 위치정보는 렌더링에 쓰인다.
b2Body* b = m_world->GetBodyList();
while ( b != NULL ){
Ball2* ball = static_cast<Ball2*>( b->GetUserData() );
if( ball != NULL ){
ball->m_position = b->GetPosition();
ball->m_angle = b->GetAngle();
ball->m_linearVelocity = b->GetLinearVelocity();
}

b = b->GetNext();
}

for( int i = 0; i < balls2.size(); i++)
balls2[i]->renderAtBodyPosition();
}

void MouseDown(const b2Vec2& p){
b2Vec2 pp = p;
pp.y = pp.y - 1;

Test::MouseDown(pp);
}

static Test* Create(){
return new MyUserDataTest();
}

};

#endif

코드를 그냥 올린다. 좋지 않은 예이지만 게을러서..

위와 같은 예시는 전의 렌더링 예제를 사용자 데이터를 이용해서 바꾼 것이다. 물론, 렌더링을 하기 위해 위와 같이 하는 것은 바람직하지 못하다.

 http://www.iforce2d.net/b2dtut/user-data 는 학습 원본인데 이곳의 필자는 다음을 명심하라 했다.

 한번 강체(혹은 고정체)에 정수형을 사용자 데이터로 넣었다면, 다른 모든 강체(혹은 고정체)에도 정수형을 사용자 데이터로 넣어라는 것. 이는 사용자 데이터가 어떤 것이 들어있을지를 예측하는 것이 힘들어지는 상황이 반드시 오기 때문에 한 강체에는 구조체를 넣었고 다른 한 강체에는 정수를 넣었을 때, GetUserData 메서드를 호출하여 얻은 포인터를 어떤 자료형으로 캐스팅해야하는지 알 길이 없기 때문이라 한다.

 흠 아직 C++에 익숙하지 않지만, 해결하려면 골치가 아플 것 같아 보인다.

 사용자 데이터를 저장할 수 있는 요소는 다음과 같다.

 강체(body), 고정체(fixture), 접합체(joint)

 box2D에서는 이 사용자 데이터에 대해 일절의 처리도 하지 않는다. 이는 위 3요소를 제거했다 하더라도 사용자 데이터는 제거되지 않는다는 뜻으로, 이것의 삭제는 개발자의 몫이라는 의미와 같다.

 정보 참고용으로 바라봐야 할 것 같다.

흠., 덕분에 이러한 리스트 순회 처리(?) 방식에서는 그 각각을 구분할 방법이 딱히 없을 때! 이러한 데이터를 저장하고 불러와 확인해보는 방식도 있다는 것을 알았다.

댓글 없음:

댓글 쓰기