一、定义一个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;
}
}