6、wxWidget之Box2D使用userdata

一、定义一个userdata

class FixtureUserData
{
public:

    wxString materialName=_("物体名称");
    int materialIndex;
    // ...
};

二、主程序中使用


Simple::~Simple(){
    delete world;
}
Simple::Simple(const wxString& title)
    :wxFrame(NULL,-1,title,wxPoint(-1,-1),wxSize(800,600))
{
    setlocale(LC_ALL, "");

    SetBackgroundStyle(wxBG_STYLE_PAINT);
    srand(time(NULL));
    timer = new wxTimer(this,-1);

    nWidth = GetSize().GetWidth();
    nHeight = GetSize().GetHeight();

    float x = 0.0f;//x轴重力
    float y = 10.0f;//y轴重力 9.8简化为10.0,方便计算
    b2Vec2 gravity(x, y);
    world = new b2World (gravity);
    int i=0;

    //*** 一、画地面 ***
    //1.地面的运动各状态等属性
    b2BodyDef groundDef;
    groundDef.type = b2_staticBody;//地面是静止的  b2_kinematicBody;//
    groundDef.position = b2Vec2(0,(nHeight-50)/PTM_RATIO);//位置
//    groundDef.angularVelocity=-45;//旋转
    b2Body* groundBody = world->CreateBody(&groundDef);
    //2.形状
    b2PolygonShape groundShape;//多边形
    groundShape.SetAsBox(nWidth/PTM_RATIO,0.5/PTM_RATIO);//在物理世界中的半长 的 半宽 是多少米

    FixtureUserData* udGround= new FixtureUserData;
    udGround->materialIndex = ++i;
    udGround->materialName=wxT("地面");
    //3.地面的属性
    b2FixtureDef groundFixtureDef;
    groundFixtureDef.shape = &groundShape;//形状
    groundFixtureDef.density = 1;//密度
    groundFixtureDef.friction = 0.3; //摩擦系数 取值范围[ 0 - 1 ]
    groundFixtureDef.restitution=0.5;//弹性系数 取值范围[ 0 - 1 ]
    groundFixtureDef.userData.pointer = reinterpret_cast<uintptr_t>(udGround);
    groundBody->CreateFixture(&groundFixtureDef);


    b2BodyDef myBodyDef;
    myBodyDef.type = b2_staticBody;
    myBodyDef.position.Set(0,0);

    //*** 二、物体1 多边形 ***
    //1.物体的运动和状态相关属性,如类型、线速度、角速度等。
    b2BodyDef defRect;
    defRect.position = b2Vec2(260/PTM_RATIO,300/PTM_RATIO);
    defRect.type = b2_dynamicBody;//b2_kinematicBody;//
    defRect.angularVelocity= b2Rot(45).GetAngle();// 45 * 3.14 /180;
    bodyRect = world->CreateBody(&defRect);
    //2.物体形状
    vs[0].Set(-0.5,0.5);
    vs[1].Set(0.5,0.5);
    vs[2].Set(0.5,-0.5);
    vs[3].Set(-0.5,-0.5);
    b2PolygonShape shapeRect;
    shapeRect.Set(vs,4);
    shapeRect.SetAsBox(0.5,0.5);//设定边框.这是一个向量,本质上说他就是一个形状的中心坐标

    //3.物体的物质属性,如密度、摩擦系数、弹性系数等,还有物体的形状。
    b2FixtureDef fixtureDefRect;
    fixtureDefRect.shape = &shapeRect;
    fixtureDefRect.density =1;//密度
    fixtureDefRect.friction =0.2;//摩擦系数
    fixtureDefRect.restitution =0.6;//弹性
    udGround= new FixtureUserData;
    udGround->materialIndex=++i;
    udGround->materialName=wxT("方块物体");
    fixtureDefRect.userData.pointer = reinterpret_cast<uintptr_t>(udGround);
    bodyRect->CreateFixture(&fixtureDefRect);


    //*** 三、画物体 2 球形 ***
    //1.物体的运动和状态相关属性,如类型、线速度、角速度等。
    b2BodyDef defCircle;
    defCircle.type = b2_dynamicBody;
    defCircle.position = b2Vec2(164/PTM_RATIO,3/PTM_RATIO);


    //2.物体形状
    b2CircleShape shapeCircle;
    shapeCircle.m_p = b2Vec2(0,0);//位置,相对于身体位置,即在b2Body中的位置
    shapeCircle.m_radius =11.0 / PTM_RATIO;


    //3.赋予物体大小、形状和其他有形特征
    b2FixtureDef fixtureDefCircle;
    fixtureDefCircle.shape = &shapeCircle;
    fixtureDefCircle.density =1;//密度
    fixtureDefCircle.friction =0.3;//摩擦系数
    fixtureDefCircle.restitution =0.6;//弹性
    //create identical bodies in different positions
    for (int j = 0; j < 3; j++)
    {
        defCircle.position.Set((170 + j * 100) / PTM_RATIO, 200 / PTM_RATIO);
        defCircle.angularVelocity = b2Rot(45).GetAngle();
        bodies[j] = world->CreateBody(&defCircle);
        fixtureDefCircle.friction = 0.3 * (j + 1);
        fixtureDefCircle.restitution = 0.3 * (j + 1);
    udGround= new FixtureUserData;
    udGround->materialIndex= ++i;
    udGround->materialName=wxString::Format(wxT("圆形物体%i"),j);
    fixtureDefCircle.userData.pointer = reinterpret_cast<uintptr_t>(udGround);

        bodies[j]->CreateFixture(&fixtureDefCircle);
    }

    // simullation.
    timeStep = 1.0f / 60.0f;//delta延迟几秒的画面
    velocityIterations = 8;//
    positionIterations = 3;//


    Bind(wxEVT_PAINT,wxPaintEventHandler(Simple::OnPaint),this);
    Bind(wxEVT_TIMER,wxCommandEventHandler( Simple::OnTimer),this);
    Bind(wxEVT_KEY_DOWN,wxKeyEventHandler(Simple::OnKeyDown),this);

    timer->Start(100);
    Centre();
}

void Simple::OnTimer(wxCommandEvent& event)
{
    world->Step(timeStep, velocityIterations, positionIterations);
//    world->DebugDraw();//显示刚体debug轮廓
//    world->ClearForces();//清除作用力
    for (b2Body *b = world->GetBodyList(); b; b=b->GetNext())
    {
        if(b->GetType() ==b2BodyType::b2_dynamicBody)
        {
            b2Fixture* fixture = b->GetFixtureList();
            b2Shape* shape = b->GetFixtureList()->GetShape();

            //抵消重力
            switch(shape->GetType()){
            case b2Shape::e_circle:
                //抵消圆球的重力。重力抵消后,圆球不会下降
//                printf("Mass=%4.2f \n",b->GetMass());
                b->ApplyForce(-(b->GetMass() * world->GetGravity()),b->GetWorldCenter(),true);
                break;
            case b2Shape::e_polygon:
                //抵消重力后,原地旋转
                b->SetGravityScale(0);//如果0改成-1,则向上漂

            }

        }
    }

    Refresh();
}

void Simple::OnPaint(wxPaintEvent& event){
//return;
    wxBufferedPaintDC dc(this);
    dc.Clear();
    wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
    gc->SetPen(*wxRED);


    int i = 0;
//  e_circle = 0, e_edge = 1, e_polygon = 2, e_chain = 3,  e_typeCount = 4
    for (b2Body *b = world->GetBodyList(); b; b = b->GetNext())
    {

        b2Vec2 position = b->GetPosition();
        float angle = b->GetAngle();
        printf("1 type=%i %4.2f %4.2f angle=%4.2f\n", b->GetType(), position.x, position.y, angle);

        b2Vec2 center = b->GetWorldCenter();
        center.x = center.x * PTM_RATIO;
        center.y = center.y * PTM_RATIO;


        printf("2 type=%i %4.2f %4.2f angle=%4.2f\n", b->GetType(), position.x, position.y, angle);

        int j = 0;
        for(b2Fixture* fixture = b->GetFixtureList();
                fixture;
                fixture = fixture->GetNext())
        {
            FixtureUserData* myData = reinterpret_cast<FixtureUserData*>( fixture->GetUserData().pointer );
            if(myData != NULL)
            {
                wxPrintf("i=%i,j=%i index = %i name=%s \n"
                         , ++i, ++j
                         , myData->materialIndex
                         , myData->materialName
                        );
            }

            b2Shape* shape = fixture->GetShape();
            wxGraphicsPath pathGround = gc->CreatePath();
            if(b->GetType() == b2BodyType::b2_staticBody) // b2BodyType::b2_kinematicBody)//
            {
                pathGround.AddRectangle(position.x * PTM_RATIO
                                        , position.y * PTM_RATIO
                                        , 400, 50);
            }
            else if(b->GetType() == b2BodyType::b2_kinematicBody)// b2BodyType::b2_kinematicBody)//
            {
                printf("kinematic x=%4.2f y=%4.2f\n", position.x, position.y);
                pathGround.AddRectangle(position.x * PTM_RATIO
                                        , position.y * PTM_RATIO
                                        , 400, 50);
            }
            else
            {
                position = b->GetPosition();
                printf("type=%i x = %4.2f y=%4.2f angle=%4.2f\n"
                       , shape->GetType()
                       , position.x, position.y
                       , angle);

                if (shape->GetType() == b2Shape::e_circle)
                {
                    b2CircleShape* circle = (b2CircleShape*) shape;
                    pathGround.AddCircle(position.x * PTM_RATIO
                                         , position.y * PTM_RATIO
                                         , circle->m_radius * PTM_RATIO);
                    pathGround.MoveToPoint(position.x * PTM_RATIO, position.y * PTM_RATIO);
                    pathGround.AddLineToPoint(position.x * PTM_RATIO + circle->m_radius * PTM_RATIO
                                              , position.y * PTM_RATIO + circle->m_radius * PTM_RATIO);
                }
                else if(shape->GetType() == b2Shape::e_polygon)
                {
                    b2PolygonShape* poly = (b2PolygonShape*)shape;

                    int vertexCount = poly->m_count;
                    b2Vec2 v[vertexCount];

                    printf("center count=%i x=%4.2f y=%4.2f\n", vertexCount, center.x, center.y);

                    for (int i = 0; i < vertexCount; i++)
                    {
                        v[i] = poly->m_vertices[i] + position;;//
                        v[i].x = v[i].x  * PTM_RATIO;
                        v[i].y = v[i].y  * PTM_RATIO;
                        printf("%i= %4.2f,%4.2f\n ", i, v[i].x, v[i].y );
                        pathGround.AddLineToPoint(v[i].x, v[i].y );
                    }

                }
                else
                {
                    pathGround.AddRectangle(position.x * PTM_RATIO
                                            , position.y * PTM_RATIO
                                            , 50, 50);
                }//end if
            }//end if
            if(angle != 0.0)
            {
                wxGraphicsMatrix mx = gc->CreateMatrix();
                mx.Translate(center.x, center.y);
                mx.Rotate(angle * 3.14); //*3.14/180);//);//
                mx.Translate(-center.x, -center.y);
                pathGround.Transform(mx);
            }


            pathGround.CloseSubpath();
            gc->FillPath(pathGround);
            gc->StrokePath(pathGround);

        }
    }//end for
    delete gc;
}

void Simple::OnKeyDown(wxKeyEvent& event)
{
//    wxLogMessage("you pressed '%i'",event.GetKeyCode());
    b2Vec2 velRect = bodyRect->GetLinearVelocity();//获取线速度
    float force= 0;
    switch(event.GetKeyCode())
    {
    case WXK_LEFT:
        //应用逐渐向上的力.在世界点施加力。
        //如果力不在质心,则会产生扭矩并影响角速度。
        bodies[0]->ApplyForce(b2Vec2(0,50),bodies[0]->GetWorldCenter(),true);
        break;
    case WXK_RIGHT:
        //不在世界原点施加力的情况
        bodies[0]->ApplyForce(b2Vec2(0,50),b2Vec2(10,10),true);
        //对质心施加力
        bodies[1]->ApplyForceToCenter(b2Vec2(0,10),true);//,bodies[0]->GetWorldCenter(),true);
        break;
    case WXK_UP:
        //设置身体的原点 和 旋转的角度。
        //意思是设置某一物体到达某一个位置和角度(到达该角度后不动。除非有其它的外力)
        bodies[0]->SetTransform(bodies[0]->GetWorldCenter(),b2Rot(-45).GetAngle());
        //施加扭矩,逐步顺时针
        bodies[2]->ApplyTorque(b2Rot(45).GetAngle(),false);
//        bodies[2]->SetTransform(b2Vec2(0,1),1);
        break;
    case WXK_DOWN:
        //立即向上的力。作用到质心
        bodies[0]->ApplyLinearImpulse(b2Vec2(0,50),bodies[0]->GetWorldCenter(),false);
        //施加角脉冲,45为顺时针 负数逆时针
        bodies[2]->ApplyAngularImpulse(b2Rot(45).GetAngle(),false);
        break;

    case 87://w
        force = velRect.x * -10;
        bodyRect->ApplyForce(b2Vec2(force,0),bodyRect->GetWorldCenter(),false);
        break;
    case 83://s
        bodyRect->ApplyLinearImpulseToCenter(b2Vec2(bodyRect->GetMass()*10.0,0)
                                             ,false);
        break;
    case 65://a
        if(velRect.x >-5) force = -50;
        bodyRect->ApplyForce(b2Vec2(force,0),bodyRect->GetWorldCenter(),false);
        break;
    case 68://d
        if(velRect.x <5) force = 50;
        bodyRect->ApplyForce(b2Vec2(force,0),bodyRect->GetWorldCenter(),false);
        break;
    case 66://b
        bodyRect->ApplyTorque(b2Rot(45).GetAngle(),false);//不起作用???
        //哦,原来是上面设置的defRect.fixedRotation=true; 这是固定旋转的意思?
        break;
    case WXK_F1:
        break;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值